介绍
IE除了允许我们添加自定义的主菜单外,还允许在右键菜单中添加自定义的菜单,。很多著名的网络软件如网络蚂蚁,、网际快车等都在右键菜单中添加了可以用来下载文件的快捷菜单。IE的右键菜单扩展同其它COM扩展不太一样,其它扩展只要在注册表中填写一定的配置信息就可以使用了,而右键菜单扩展必须由一个JavaScript脚本来创建并调用其中的方法。由于我们的COM组件必须能从脚本语言中创建,因此右键菜单扩展的必须是一个Automation(自动化)组件,也就是说除了IUnknown接口外,还必须支持IDispatch接口。幸好,Delphi提供了内置的自动化COM组件的支持,我们只需要从TAutoObject而不是标准的TComObject派生COM组件就可以了。
经常使用IE复制粘贴网页上的信息,我发现IE右键菜单中的复制命令不是很方便,比如当在一个超链接上激活右键菜单,会发现只有复制快捷方式可以使用,而复制菜单为灰色被禁用状态,而有时我不仅想复制超链接本身,还想复制它的文本,这时我只能是选中链接的文本,然后再点复制,这很不方便。下面我们就来创建一个右键菜单扩展,允许复制超级链接的文本。
创建COM组件
新建一个ActiveX Library项目,保存为IEContext.dpr,然后使用命令 File | New … | ActiveX | Automation Object创建一个名为TIEContextMenu的自动化对象,保存为CIEContextMenu.pas文件。接下来选中Tools | Environment Options命令,激活IDE配置管理界面,切换到Type Library页面,设定类型库语言为Pascal,见下图:
设定为Language选项为Pascal后,则Type Library编辑器会使用我们熟悉的Pascal语言而不是IDL语言来描述COM的接口定义。
然后使用View | Type Library激活COM组件的类型库编辑器,添加接口方法CopyUrlText,如下图所示:
CopyUrlText将被用来把连接只有一个参数,就是UrlText,这个参数会由后面我们编写的脚本语句传递过来。完成的COM组件实现如下:
type
TIEContextMenu = class(TAutoObject, IIEContextMenu)
protected
procedure CopyUrlText(const UrlText: WideString); safecall;
end;
implementation
uses ComServ, Clipbrd, Dialogs, Sysutils, Windows, Registry;
procedure TIEContextMenu.CopyUrlText(const UrlText: WideString);
begin
//将链接文本复制到剪贴板上
Clipboard.AsText:=UrlText;
end;
注册扩展
要想使右键菜单扩展生效,必须填写下列注册表项:
1. 在HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt关键字下添加内容为要创建的右键扩展菜单项的标题文本关键字。文本中可以包含&字符用来指定菜单的快捷方式。
2. 设定标题文本关键字的默认值为包含脚本语句的html文件,当用户点击菜单项时,IE会执行html文件中的脚本,而我们将在脚本中创建自动化对象,并将链接文本作为参数调用自动化对象的方法。
3. 复制链接文本只对链接有意义,而对于其它html页面中的元素无意义,我们可以在注册表中HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt\<菜单标题>关键字下添加一个可选的二进制值Contexts值来指定菜单扩展显示的上下文。下表是上下文的列表:
上下文 | 值(16进制) |
默认 | 0x1 |
图像 | 0x2 |
控制 | 0x4 |
表格 | 0x8 |
文本选区 | 0x10 |
锚点 | 0x20 |
超级链接属于上下文中的锚点,所以需要设定contexts的值为32(等于16进制的20)。
下面就是实现注册的类工厂的实现:
type
TIEContextMenuFactory = class(TAutoObjectFactory)
public
procedure UpdateRegistry(Register: Boolean); override;
end;
procedure AddExtMenuItem(MenuText, Url: string; Contexts:DWord);
var
reg: TRegistry;
begin
Reg := TRegistry.Create;
with Reg do try
RootKey := HKEY_CURRENT_USER;
OpenKey('\Software\Microsoft\Internet Explorer\MenuExt\' + MenuText, True);
WriteString('', Url);
WriteInteger('contexts', contexts);
CloseKey;
finally
Free;
end;
end;
procedure RemoveExtMenuItem(MenuText: string);
var
reg: TRegistry;
begin
Reg := TRegistry.Create;
with Reg do try
RootKey := HKEY_CURRENT_USER;
DeleteKey('\Software\Microsoft\Internet Explorer\MenuExt\' + MenuText);
finally
Free;
end;
end;
…
procedure TIEContextMenuFactory.UpdateRegistry(Register: Boolean);
begin
inherited;
if Register then
AddExtMenuItem('
¸′复制链接文本', ExtractFilePath(GetDllName)+'copyurl.htm',32)
else
RemoveExtMenuItem('
¸′复制链接文本');
end;
initialization
TIEContextMenuFactory.Create(ComServer, TIEContextMenu, Class_IEContextMenu,
ciMultiInstance, tmApartment);
end.
脚本语句
完成了COM组件的编写,剩下的任务就是编写驱动COM组件的VBScript语句的编写了,下面是copyurl.htm的内的VBScript的内容:
<script language="VBScript">
Sub CopyLink(UrlText)
On Error Resume Next
set CopyUrl=CreateObject("IEContext.IEContextMenu")
if err<>0 then
MsgBox("CopyUrl not properly installed!"+ vbCrLf+"Please register CopyUrl ")
else
call CopyUrl.CopyUrlText(UrlText)
end if
end sub
Sub OnContextMenu()
set srcEvent = external.menuArguments.event
set EventElement = external.menuArguments.document.elementFromPoint ( srcEvent.clientX, srcEvent.clientY )
if srcEvent.type = "MenuExtAnchor" then
set srcAnchor = EventElement
do until TypeName(srcAnchor)="HTMLAnchorElement"
set srcAnchor=srcAnchor.parentElement
Loop
Call CopyLink(srcAnchor.innerText)
elseif srcEvent.type="MenuExtUnknown" then
set srcAnchor = EventElement
do until TypeName(srcAnchor)="HTMLAnchorElement"
set srcAnchor=srcAnchor.parentElement
if TypeName(srcAnchor)="Nothing" then
Call CopyLink(EventElement.innerText)
exit sub
end if
Loop
Call CopyLink(srcAnchor.innerText)
elseif 1=1 then
MsgBox("Unknown Event Source """ + srcEvent.type + """" + vbCrLf + "Please send description of error to hubdog@263.net")
end if
end sub
call OnContextMenu()
</script>
简单介绍一下脚本的处理流程,当IE加载copyurl.htm时,会自动调用OnContextMenu过程,在这个过程中,我们可以通过变量external.menuArguments获得IE的IDispatch接口,通过external.menuArguments.event可以进一步获得IE的点击事件的信息,包括用户点击的位置(X,Y坐标可以通过ClientX和ClientY属性获得)。同时可以从IE的当前页面中通过external.menuArguments.document.elementFromPoint方法获得被点中的HTML元素,如果元素类型为HTMLAnchorElement,则表示它是一个链接对象,则元素的innerText属性就对应的链接的标题文本,这时就调用CopyLink子过程,在CopyLink中调用CreateObject(‘IEContext.IEContextMenu’) 来创建我们的菜单扩展对象,其中IEContext.IEContextMenu是扩展对象的ProgID,是由项目的名称+去掉T的扩展对象的类名组合出来的。最后将获得的Url文本作为参数调用扩展对象的CopyUrlText就可以了,菜单对象会完成将文本放到系统的剪贴板中的工作。
总结
使用菜单命令Run | Register ActiveX Server注册复制链接文本扩展,然后打开光盘中的download.htm文本,选中一个链接,点击右键菜单,执行“复制链接文本”后,将复制的结果粘贴到记事本中,然后在执行复制快捷方式,同样将复制的结果粘贴到剪贴板中,得到的结果见下图: