介紹
向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包含QueryStatus
和
Exec
兩
個方法,其中文檔上說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擴展的一些更為高級的技術。
新浪微博:http://t.sina.com.cn/androidguy 昵稱:李寧_Lining