处理器类型 | COM接口 |
Context menu 处理器 | IContextMenu |
Property sheet 处理器 | IShellPropSheetExt |
Drag and drop 处理器 | IContextMenu |
Drop 处理器 | IDropTarget |
QueryInfo 处理器(Shell V4.71+) | IQueryInfo |
其中 "Drag and drop 处理器" 的除了 COM 接口 IContextMenu 实现外还得需要注册表的特殊注册才可以实现。其中 IContextMenu 接口有三个虚成员函数需要我们的组件来实现,其函数原型分别如下:
HRESULT QueryContextMenu( HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags ); |
注:在QueryContextMenu 成员函数中我们可以加入自己的菜单项,插入菜单项其实很简单,我们可以通过 InsertMenu API 函数来实现,如下代码所示:
::InsertMenu(hmenu, indexMenu, MF_STRING | MF_BYPOSITION, idCmdFirst, IDM_REG_MNU_TXT); |
QueryContextMenu 的处理过程十分简单,在这里无须多说。
HRESULT GetCommandString( UINT idCmd, UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax ); |
注:GetCommandString 成员函数为 Explorer 提供了在状态栏显示菜单命令提示信息的方法。在这个方法中 "LPSTR pszName" 是我们要关注的参数,我们只要根据 "UINT uFlags" 参数来填充 "LPSTR pszName" 参数即可。在这里可能会涉及到 ANSI 和 UNICODE 之间相互转换的知识,不过在这里我要提醒大家的是:在 COM 编程中尽可能使用兼容的 TCHAR 类型,同时对字符操作也尽量不要使用 C 类的
HRESULT InvokeCommand( LPCMINVOKECOMMANDINFO pici ); |
InvokeCommand 函数实现最终菜单项命令的执行。在 "LPCMINVOKECOMMANDINFO pici" 参数中包含了当前用户执行的菜单项ID和其他一些标志信息,如下代码可获取菜单项的ID:
//如果 nFlag 不为0则说明 pici->lpVerb 指向一个以''''\0''''结尾的字符串 int nFlag = HIWORD(pici->lpVerb); //用户当前点击的菜单项ID int nMnuId = LOWORD(lpici->lpVerb); |
一旦获取了菜单项ID那么我们就可以根据不同的菜单项来执行相应的动作,如图1.2 所示的 "Register Component" 和 "UnRegister Component" 菜单项所对应的 "注册/反注册进程内组件" 动作。
3.组件必要的宏定义部分
其实这一步十分简单,本可以忽略,但是为了把过程讲的更清楚一点我还是列了出来:
//声明组件注册所用的注册表REG资源 //其中IDR_SIMPLESHLEXT为注册表资源ID DECLARE_REGISTRY_RESOURCEID(IDR_SIMPLESHLEXT) //AddRef和Release成员函数的实现 DECLARE_PROTECT_FINAL_CONSTRUCT() //组件接口映射部分,该部分映射主要是告诉QueryInterface能返回哪些接口给外部 BEGIN_COM_MAP(CSimpleShlExt) COM_INTERFACE_ENTRY(ISimpleShlExt) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(IShellExtInit)//IShellExtInit接口 COM_INTERFACE_ENTRY(IContextMenu)//IContextMenu接口 END_COM_MAP() |
4.组件注册