介绍

 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文本,选中一个链接,点击右键菜单,执行“复制链接文本”后,将复制的结果粘贴到记事本中,然后在执行复制快捷方式,同样将复制的结果粘贴到剪贴板中,得到的结果见下图:

posted on 2009-08-28 22:37  on_road  阅读(571)  评论(0编辑  收藏  举报