用过NetAnts的朋友都知道,它会在IE的右键快捷菜单中加入Download All By NetAnts的项目,点一下它,NetAnts就会得到当前网页的所有连接,方便用户快速下载文件。这是怎么做的呢?



要解决这个问题,我们先抽象出问题的实质:

1)在IE地快捷菜单中加入自己的项目



2)使该项目指向自己的程序,并将所有的连接、连接描述等信息作为参数传递给自己的程序。



问题已经很明了了,对于第一步来说,很简单,修改过注册表的朋友都能轻易实现。



首先打开注册表编辑器(regedit.exe),在HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt 键下,你可以看到 Download &All By NetAnts 的子键(如果安装了NetAnts的话),其中“&”符号后面的字母标识了快捷键的按键,我想着学过Windows编程的朋友都知道。在该子键下仅有两个键值,如图,其中“默认”表示菜单所指向的文件,“Contests”则表示你添加的菜单项目在什么情况下出现。我们注意到,NetAnts指向的是NaGetAll.htm文件,根据MSDN上说,这个文件应该是个脚本文件,必要时,它会被隐藏的对话框调用,当脚本执行完毕,对话框也自动关闭。Contexts的值表示什么时候显示关联菜单,它可以取以下值:



0x1

CONTEXT_MENU_DEFAULT

缺省的菜单

0x2

CONTEXT_MENU_IMAGE

图象关联菜单

0x4

CONTEXT_MENU_CONTROL

控件关联菜单

0x8

CONTEXT_MENU_TABLE

表格关联菜单

0x10

CONTEXT_MENU_TEXTSELECT

文本选取关联菜单

0x20

CONTEXT_MENU_ANCHOR

锚点关联菜单

0x40

CONTEXT_MENU_UNKNOWN

未知元素的关联菜单



以上值可以通过有效的OR运算组合,如0x12,表示只在图象、文本选取关联菜单中才显示自定义的菜单条目。如果我们联想一下的话,很容易想到这可以做一个自动填表工具。更多的内容你可以到MSDN上找吧!好了,废话少说。

既然指向的是Htm文件,那么如何启动NetAnts,又如何传递参数呢?这也很简单,我们先打开NaGetAll.htm文件:

<script language="VBScript">

On Error Resume Next

set NetAntsApi = CreateObject( "NetAnts.API" ) //创建NetAnts对象

if err<>0 then

Alert("NetAnts not properly installed on this PC!")

else

set links = external.menuArguments.document.links //得到网页所有连接的集合

ReDim params(links.length*2) //links.length为所有连接的个数

params(0)=external.menuArguments.document.Url //得到当前页面的Url

for i = 0 to links.length-1

params(i*2+1)=links(i).href //连接地地址

params(i*2+2)=links(i).innerText //连接的描述

next

NetAntsApi.AddUrlList params

end if

</script>

正如前面提到的那样是VBScript,通过menuargument获得window对象,然后通过window对象得到网页的连接集合及相应的必要信息,最后调用了NetAnts对象,将所有的信息以数组的形式传递给NetAnts对象,我们所要做的就是创建自己的COM对象。

创建COM对象不太容易,但用VB,Delphi这样的快速开发工具到也不难。下面笔者就用C++ Builder实际来创建一个COM对象来完成上述功能。

启动C++ Builder创建一个新的工程,在Form1中加入一个ListBox组件,用于显示加入的连接地址。在该工程下新建一个Automation Object,如图,





输入GetUrl,其余保持不便,按OK钮,这样C++ Builder将为你创建一系列文件用于描述COM结构,我们所要做的就是添加接口和方法。

在IGetUrl接口中加入AddHrefList方法,并且添加一个Variant*类型的参数pList,设置返回值为HRESULT,如图:



然后点按刷新按钮 ,C++ Builder会自动刷新所需文件。在工程管理器中打开GetUrlImpl.cpp文件,会看到刚才接口的实现函数的声明,添加如下代码,并保存工程。

Variant* vp=(Variant*)pList; //转换为Variant类,在此转换成SafeArray*也可,但麻烦一些

int di=vp->ArrayDimCount(); //得到数组的维数

if (di>1)

return E_FAIL;

int hb=vp->ArrayHighBound(); //得到数组的上下标

int lb=vp->ArrayLowBound();

for (int n=lb;n<=hb;n++)

{

Variant vi=vp->GetElement(n); //得到数组的元素

String ai=String(vi);

Form1->ListBox1->Items->Add(ai);

}

return S_OK;

现在,一个自动化对象对象已经创建完成。编译运行程序。就在系统中自动注册了类,以及类的所有接口。接下来就很简单了,按照NaGetAll.htm文件的形式写一个VBScript,如下:

<script language="VBScript">

On Error Resume Next

set OB = CreateObject( "Project1.GetUrl" )

if err<>0 then

Alert("必要的类没有注册!")

else

set links = external.menuArguments.document.links

ReDim params(links.length)

params(0)=external.menuArguments.document.Url

for i = 0 to links.length-1

params(i+1)=links(i).href

next

OB.AddHrefList params

Alert("你成功了!")

end if

</script>



并且在注册表中加入开始讲的那样的键值,好了所有的工作都做完了。不过细心的读者会发现上述代码与NaGetAll.htm还是有一点出入,主要就在最后的Alert("我成功了!")上,这是为了解决对象生存期的问题,为了解决这个问题,需要在上面代码的开始加入:

AddRef(),这是IUnKnown接口的方法,用于增加对象的应用计数,防止对象在非必要是自动被卸载,当然如果你确定可以卸载对象了,则在必要的地方加入Release(),这同样是IUnKnown接口的方法,用于减少对象应用计数,当引用计数为 0时,Windows会自动卸载对象。