當(dāng)用戶右擊一個shell對象時,shell會顯示它的上下文菜單。文件系統(tǒng)對象有大量的標(biāo)準(zhǔn)菜單項,如"剪切"和"拷貝",這些都是缺省的菜單項。如果對象是一個文件,是文件類的成員,就能夠在注冊表里指定附加的菜單項。Shell檢查注冊表,看看文件類型是否與一些上下文菜單handler相關(guān)聯(lián),如果是,shell會咨詢這些handler是否添加額外的菜單項。
上下文菜單handler是一種shell擴展handler,它添加命令到已有的上下文菜單中。上下文菜單handler都與特定的文件類相關(guān)聯(lián),并且在顯示這類文件的成員的上下文菜單時調(diào)用。通過實現(xiàn)和注冊這樣一個handler,能夠動態(tài)地添加菜單項到對象的上下文菜單上,從而為特殊的對象定制菜單。
上下文菜單Handler的工作原理
作為一種shell擴展handler,上下文菜單handler同所有其它handler一樣, 是進程內(nèi)COM 對象,即對象作為動態(tài)連接庫 (DLL)實現(xiàn)。除了IUnknown接口外,上下文菜單還必須導(dǎo)出IShellExtInit和IContextMenu接口,作為選擇,上下文菜單也能導(dǎo)出IContextMenu2和IContextMenu3,這些接口可以實現(xiàn)自畫菜單項。
IShellExtInit接口僅僅被shell用來初始化handler,主要的操作通過handler的IContextMenu接口進行。Shell首先調(diào)用IContextMenu::QueryContextMenu,傳送一個HMENU句柄,這個方法用它來增加上下文菜單。如果用戶亮選了這些新添加的某個命令項, IContextMenu::GetCommandString將被調(diào)用,以取得這條菜單的幫助信息,把它顯示在資源管理器的狀態(tài)條上。如果用戶單擊了handler的條目,shell調(diào)用IContextMenu::InvokeCommand,從而handler能夠執(zhí)行合適的操作。
實現(xiàn)IContextMenu接口
1、實現(xiàn)QueryContextMenu方法
Shell通過調(diào)用IContextMenu::QueryContextMenu,允許handler把它的菜單項添加到菜單中。QueryContextMenu共有5個參數(shù),各參數(shù)作用如下:
1) Hmenu:HMENU類型,表示上下文菜單的句柄。
2) IndexMenu:第一個被添加的菜單索引。
3) IdCmdFirst:添加的菜單ID初值。
4) idCmdLast:添加的菜單ID值。
5) uFlags:與上下文菜單相關(guān)的狀態(tài)標(biāo)志,共有3種,如下:
CMF_DEFAULTONLY 用戶選擇了缺省的命令,通常是通過雙擊對象產(chǎn)生。QueryContextMenu 在把控制返回給shell前不應(yīng)該修改菜單。
CMF_NODEFAULT 菜單沒有缺省的條目,這個方法應(yīng)該把它的命令加到菜單中。
CMF_NORMAL 上下文菜單將被正常顯示,這個方法應(yīng)該把它的命令加到菜單中。
必須注意的是,任何添加的菜單項的ID必須落在idCmdFirst和idCmdLast兩個參數(shù)中間,通常,添加的第一個菜單項ID設(shè)為idCmdFirst,以后每添加一個菜單項,就把ID加1,這樣,即使shell調(diào)用了不止一個handler,也可以確保菜單項的ID不超過idCmdLast和可能的ID值。
在ID和idCmdFirst之間,菜單項ID的command offset(命令偏移)是不同的,應(yīng)該保存handler添加到上下文菜單中的每個菜單項的offset,因為如果shell按順序調(diào)用GetCommandString或者InvokeCommand,可以使用它來鑒別菜單項的ID.
還應(yīng)該為每一個添加的命令賦予一個verb.Verb是語言獨立的字符串,當(dāng)調(diào)用InvokeCommand時,常常用verb來代替偏移以鑒別命令。
QueryContextMenu 方法使用InsertMenu或InsertMenuItem 添加新的菜單項,然后返回一個嚴(yán)格設(shè)置為SEVERITY_SUCCESS的HRESULT值,把它的值設(shè)置為被分配的的命令I(lǐng)D.例如,假如idCmdFirst是5,添加了3個菜單項,ID分別是5,7,8,則返回值應(yīng)該是MAKE_HRESULT(SEVERITY_SUCCESS, 0, 8 - 5 + 1)。
上下文菜單handler是一種shell擴展handler,它添加命令到已有的上下文菜單中。上下文菜單handler都與特定的文件類相關(guān)聯(lián),并且在顯示這類文件的成員的上下文菜單時調(diào)用。通過實現(xiàn)和注冊這樣一個handler,能夠動態(tài)地添加菜單項到對象的上下文菜單上,從而為特殊的對象定制菜單。
上下文菜單Handler的工作原理
作為一種shell擴展handler,上下文菜單handler同所有其它handler一樣, 是進程內(nèi)COM 對象,即對象作為動態(tài)連接庫 (DLL)實現(xiàn)。除了IUnknown接口外,上下文菜單還必須導(dǎo)出IShellExtInit和IContextMenu接口,作為選擇,上下文菜單也能導(dǎo)出IContextMenu2和IContextMenu3,這些接口可以實現(xiàn)自畫菜單項。
IShellExtInit接口僅僅被shell用來初始化handler,主要的操作通過handler的IContextMenu接口進行。Shell首先調(diào)用IContextMenu::QueryContextMenu,傳送一個HMENU句柄,這個方法用它來增加上下文菜單。如果用戶亮選了這些新添加的某個命令項, IContextMenu::GetCommandString將被調(diào)用,以取得這條菜單的幫助信息,把它顯示在資源管理器的狀態(tài)條上。如果用戶單擊了handler的條目,shell調(diào)用IContextMenu::InvokeCommand,從而handler能夠執(zhí)行合適的操作。
實現(xiàn)IContextMenu接口
1、實現(xiàn)QueryContextMenu方法
Shell通過調(diào)用IContextMenu::QueryContextMenu,允許handler把它的菜單項添加到菜單中。QueryContextMenu共有5個參數(shù),各參數(shù)作用如下:
1) Hmenu:HMENU類型,表示上下文菜單的句柄。
2) IndexMenu:第一個被添加的菜單索引。
3) IdCmdFirst:添加的菜單ID初值。
4) idCmdLast:添加的菜單ID值。
5) uFlags:與上下文菜單相關(guān)的狀態(tài)標(biāo)志,共有3種,如下:
CMF_DEFAULTONLY 用戶選擇了缺省的命令,通常是通過雙擊對象產(chǎn)生。QueryContextMenu 在把控制返回給shell前不應(yīng)該修改菜單。
CMF_NODEFAULT 菜單沒有缺省的條目,這個方法應(yīng)該把它的命令加到菜單中。
CMF_NORMAL 上下文菜單將被正常顯示,這個方法應(yīng)該把它的命令加到菜單中。
必須注意的是,任何添加的菜單項的ID必須落在idCmdFirst和idCmdLast兩個參數(shù)中間,通常,添加的第一個菜單項ID設(shè)為idCmdFirst,以后每添加一個菜單項,就把ID加1,這樣,即使shell調(diào)用了不止一個handler,也可以確保菜單項的ID不超過idCmdLast和可能的ID值。
在ID和idCmdFirst之間,菜單項ID的command offset(命令偏移)是不同的,應(yīng)該保存handler添加到上下文菜單中的每個菜單項的offset,因為如果shell按順序調(diào)用GetCommandString或者InvokeCommand,可以使用它來鑒別菜單項的ID.
還應(yīng)該為每一個添加的命令賦予一個verb.Verb是語言獨立的字符串,當(dāng)調(diào)用InvokeCommand時,常常用verb來代替偏移以鑒別命令。
QueryContextMenu 方法使用InsertMenu或InsertMenuItem 添加新的菜單項,然后返回一個嚴(yán)格設(shè)置為SEVERITY_SUCCESS的HRESULT值,把它的值設(shè)置為被分配的的命令I(lǐng)D.例如,假如idCmdFirst是5,添加了3個菜單項,ID分別是5,7,8,則返回值應(yīng)該是MAKE_HRESULT(SEVERITY_SUCCESS, 0, 8 - 5 + 1)。