介绍

向IE中添加的自定义菜单,可以被用来执行可执行文件,脚本语言和COM对象的方法,对于前两种执行方式,相对比较简单,只需要对注册表进行编程就可以了,但是能够执行的功能非常有限,而使用COM组件扩展IE菜单则相对复杂,但是能够执行的功能也相对是最强大的,所以下面我就主要介绍基于COM的菜单扩展方式,还要注意的一点是只有IE5及以后的版本才支持菜单的扩展。

创建COM组件

对于一个IE菜单项COM组件来说,它最少需要实现IOleCommandTargetCOM接口,如果COM组件还想要对当前IE中显示的页面进行操作的话,就还需要实现IObjectWithSite接口,对于IObjectWithSite接口,我将在后面的工具条按钮扩展中讨论它的实现。

首先在Delphi中用New | Other命令调出New Items对话框,然后在ActiveX页面中选择创建一个新的ActiveX Library,将项目保存为IEMenu.dpr,然后再次调用New | Other | ActiveX命令,新建一个名为TIEHelloWorld的Com Object对象,然后添加IOleCommandTarget接口的方法实现,完成的类的定义如下:

type
  TIEHelloWorld = class(TComObject, IOleCommandTarget)
  protected
    //IOleCommandTarget方法接口
    function QueryStatus(CmdGroup: PGUID; cCmds: Cardinal;
      prgCmds: POleCmd; CmdText: POleCmdText): HResult; stdcall;
    function Exec(CmdGroup: PGUID; nCmdID, nCmdexecopt: DWORD;
      const vaIn: OleVariant; var vaOut: OleVariant): HResult; stdcall;
  end;

IOleCommandTarget包含QueryStatusExec两个方法,其中文档上说QueryStatus方法会被IE调用来获得当前菜单的状态,我们需要返回OLECMDF_ENABLED或者其它值来表示是否允许点击,但是在实际当中,我发现IE从来没有调用过我的菜单扩展的QueryStatus方法,不过不管怎么说,还是按正常的来实现。

function TIEHelloWorld.QueryStatus(CmdGroup: PGUID; cCmds: Cardinal;
  prgCmds: POleCmd; CmdText: POleCmdText): HResult;
begin
  //允许点击菜单
  prgCmds^.cmdf:=OLECMDF_ENABLED;
  Result := S_OK;
end;

当用户点击菜单后,IE会调用IOleCommandTarget接口的Exec方法来执行用户自定义的操作。

function TIEHelloWorld.Exec(CmdGroup: PGUID; nCmdID, nCmdexecopt: DWORD;
  const vaIn: OleVariant; var vaOut: OleVariant): HResult;
begin
  Result := S_OK;
  //nCmdI为0时,表示菜单和工具条按钮被点击了
  try
    ShowMessage('Hello IE');
  except
    Result:=E_FAIL;
  end;
  //注意下面的话语句会导致AV,不知道为什么?
  //vaOut := Null;
end;

Exec方法带有很多参数,其中IE在调用菜单扩展和工具条按钮扩展组件的的Exec方法时,会设定nCmdI为0,其它参数对于我们来说,都不需要关心,只要在成功执行代码后,返回S_OK,在失败时返回E_Fail就可以了。实现了IOleCommandTarget接口之后,一个最简单的IE菜单扩展就完成了。

注册组件

要想让IE在启动后能够发现菜单扩展COM组件,并加载菜单进行显示,需要在注册表中填写一些配置信息。

1、 要在HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Extensions\项目下新建一个关键字,名为菜单扩展的Guid的字符串形式。

2、 然后在新建的HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Extensions\<菜单扩展Guid>关键字下再创建一个名为ClsidExtension的项目,值也为扩展的Guid。

3、 然后HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Extensions\<菜单扩展Guid>关键字下添加名为MenuText的字符串字段,写入IE用来显示菜单扩展的菜单项标题文本。

4、 我们还可以创建一个MenuStatusBar,IE会在鼠标停留在我们的扩展对应的菜单项时,在IE的状态条上显示MenuStatusBar的文本。这个注册表项不是必须项目,可以省略。

5、 通常情况下,IE会在工具菜单下显示我们的扩展菜单,但是我们也可以创建一个MenuCustomize字段,设定其值为help。这时IE会将我们的菜单放到帮助主菜单下面。如果我们的菜单扩展是用来向IE中添加上下文帮助的,可以设定这个选项。这个注册表项同样也是可以忽略的。

注意:如果将注册表位置由HKEY_LOCAL_MACHINE改成HKEY_CURRENT_USER,则菜单扩展会对所有该机器上用户生效。

为了实现添加必要的注册表信息,编写AddMenuItem方法来实现注册功能:

//添加IE菜单
procedure AddMenuItem(MenuText, StatusBarText, Guid:
  string; HelpMenu: Boolean);
var
  Reg: TRegistry;
begin
  Reg := TRegistry.Create;
  with Reg do
  begin
    RootKey := HKEY_LOCAL_MACHINE;
    OpenKey('\Software\Microsoft\Internet Explorer\Extensions\' + Guid, True);
    if HelpMenu then
      WriteString('MenuCostumize', 'help');
    WriteString('CLSID', '{1FBA04EE-3024-11d2-8F1F-0000F87ABD16}');
    WriteString('MenuText', MenuText);
    WriteString('MenuStatusBar', StatusBarText);
    WriteString('ClsidExtension', Guid);
    CloseKey;
    CloseKey;
    Free;
  end;
end;

同时我们还要注销菜单扩展的功能,方法RemoveMenuItem被用来删除注册表项,删除注册表项是Guid来进行的,因为Guid可以保证唯一

//删除IE菜单
procedure RemoveMenuItem(Guid: string);
var
  Reg: TRegistry;
begin
  Reg := TRegistry.Create;
  with Reg do
  begin
    RootKey := HKEY_LOCAL_MACHINE;
    DeleteKey('\Software\Microsoft\Internet Explorer\Extensions\' + Guid);
    free;
  end;

end;

最后,我们定义TIEHelloMenuFactory的TComObjectFactory派生类来调用上面的方法实现COM的组件的注册和注销:

type
  TIEHelloMenuFactory = class(TComObjectFactory)
  public
    procedure UpdateRegistry(Register: Boolean); override;
  end;
{ TIEHelloMenuFactory }
 
procedure TIEHelloMenuFactory.UpdateRegistry(Register: Boolean);
begin
  inherited;
  if Register then
//添加到Tools菜单下
AddMenuItem('HelloIE', 'Hello IE MenuItem', GuidToString(ClassID), False)
  else
    //Todo: 通过Guid进行删除
    RemoveMenuItem(GuidToString(ClassID));
end;
 
initialization
  TIEHelloMenuFactory.Create(ComServer, TIEHelloWorld, Class_IEHelloWorld,
    'IEHelloWorld', '', ciMultiInstance, tmApartment);
end.

完成程序后,我们可以在Delphi IDE中使用菜单 Run | Register ActiveX Server和UnRegister ActiveX Server来注册创建好的菜单扩展,然后启动IE,运行后的效果示意图:

总结

上面我们介绍了如何创建一个最简单的菜单扩展,接下来我将探讨IE扩展的一些更为高级的技术。

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