我有一个命名空间扩展,它提供了一个服务器中的文件/文件夹的虚拟视图。
在IContextMenu::QueryContextMenu()
我已经添加了一些自定义菜单项。
我还在IShellFolder::GetAttributesOf()
设置了几个SGAOF标志,以获得上下文菜单中的重命名,删除和属性。
有什么办法可以让我的名字空间扩展项目的上下文菜单中的“ 发送到 ”选项? 一旦启用这些命令,我该如何处理这些命令? 请指教。
这是Denis Anisimovbuild议的那个代码
const CLSID SendToCLSID = { 0x7BA4C740, 0x9E81, 0x11CF, { 0x99, 0xD3, 0x00, 0xAA, 0x00, 0x4A, 0xE8, 0x37 } }; HRESULT CMyNSEContextMenu::Initialize(PCIDLIST_ABSOLUTE pidlFolder , IDataObject *pDataObj, HKEY hkeyProgID ) { OutputDebugString(L"CMyNSEContextMenu::Initialize\n"); //Other initialization code ... ... if (_pdtobj) { _pdtobj->Release(); _pdtobj = NULL; } _mpidlFolder = pidlFolder; _pdtobj = pDataObj; if (pDataObj) { _pdtobj->AddRef(); CoCreateInstance(SendToCLSID, NULL, CLSCTX_INPROC_SERVER, IID_IContextMenu, (LPVOID*)&_pSendToMenu); } return S_OK; } HRESULT CMyNSEContextMenu::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast , UINT uFlags ) { OutputDebugString(L"CMyNSEContextMenu::QueryContextMenu\n"); UNREFERENCED_PARAMETER(indexMenu); UNREFERENCED_PARAMETER(idCmdFirst); //Get File Name IShellItemArray *psia=NULL; HRESULT hr; USHORT items = 0; //Adding other menu items AddMenuItem(hmenu, indexMenu++, idCmdFirst + MENUVERB_XXX, IDS_COMMAND_XXX, IDB_XXX); items++; IShellExtInit *pShellExtInitSendTo = NULL; _pSendToMenu->QueryInterface(IID_IShellExtInit, (LPVOID*)&pShellExtInitSendTo); pShellExtInitSendTo->Initialize(NULL, _pdtobj, 0); // your IDataObject with CFSTR_SHELLIDLIST format) hr = _pSendToMenu->QueryContextMenu(hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags); if (SUCCEEDED(hr)) { items += HRESULT_CODE(hr); } return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (USHORT)(items)); } HRESULT CMyNSEContextMenu::HandleMenuMsg( UINT uMsg, WPARAM wParam, LPARAM lParam ) { IContextMenu2 *pSendToMenu = NULL; _pSendToMenu->QueryInterface(IID_IContextMenu2, (LPVOID*)&pSendToMenu); return pSendToMenu->HandleMenuMsg(uMsg,wParam,lParam); } HRESULT CMyNSEContextMenu::HandleMenuMsg2( UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plResult ) { IContextMenu3 *pSendToMenu = NULL; _pSendToMenu->QueryInterface(IID_IContextMenu3, (LPVOID*)&pSendToMenu); return pSendToMenu->HandleMenuMsg2(uMsg, wParam, lParam, plResult); } HRESULT CMyNSEContextMenu::GetCommandString(UINT_PTR idCmd , UINT uType , UINT * pRes , LPSTR pszName , UINT cchMax ) { OutputDebugString(L"CMyNSEContextMenu::GetCommandString\n"); return _pSendToMenu->GetCommandString(idCmd, uType, pRes, pszName, cchMax); }
默认的上下文菜单是作为GetUIObjectOf的一部分创build的。 MyNSEContextMenu类的实例是通过Classfactory。
HRESULT CMyNSEShellFolder::GetUIObjectOf(HWND hwnd, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT * /* prgfInOut */, void **ppv) { OutputDebugString(L"CMyNSEShellFolder::GetUIObjectOf\n"); *ppv = NULL; HRESULT hr = E_NOINTERFACE; if (riid == IID_IContextMenu) { // The default context menu will call back for IQueryAssociations to determine the // file associations with which to populate the menu. DEFCONTEXTMENU const dcm = { hwnd, NULL, m_pidl, static_cast<IShellFolder2 *>(this), cidl, apidl, NULL, 0, NULL }; hr = SHCreateDefaultContextMenu(&dcm, riid, ppv); } //Others .... .... else if (riid == IID_IQueryAssociations) { else { ASSOCIATIONELEMENT const rgAssocItem[] = { { ASSOCCLASS_PROGID_STR, NULL, L"MyNSE_Type"}, }; hr = AssocCreateForClasses(rgAssocItem, ARRAYSIZE(rgAssocItem), riid, ppv); } } ... ... return hr; } //Called from the class factory HRESULT CMyNSEContextMenu_CreateInstance(REFIID riid, void **ppv) { *ppv = NULL; CMyNSEContextMenu* pContextMenu = new (std::nothrow) CMyNSEContextMenu(); HRESULT hr = pContextMenu ? S_OK : E_OUTOFMEMORY; if (SUCCEEDED(hr)) { hr = pContextMenu->QueryInterface(riid, ppv); pContextMenu->Release(); } return hr; }
相关registry如下
HKEY_LOCAL_MACHINE, L"Software\\Classes\\CLSID\\%s", szContextMenuClassID, NULL, (LPBYTE)g_szExtTitle, REG_SZ, HKEY_LOCAL_MACHINE, L"Software\\Classes\\CLSID\\%s\\InprocServer32", szContextMenuClassID, NULL, (LPBYTE)L"%s", REG_SZ, HKEY_LOCAL_MACHINE, L"Software\\Classes\\CLSID\\%s\\InprocServer32", szContextMenuClassID, L"ThreadingModel", (LPBYTE)L"Apartment", REG_SZ, HKEY_LOCAL_MACHINE, L"Software\\Classes\\CLSID\\%s\\ProgID", szFolderViewImplClassID, NULL, (LPBYTE)L"MyNSE_Type", REG_SZ, // For performance, only context menu verbs that register this are considered when the user double-clicks. HKEY_CLASSES_ROOT, L"CLSID\\%s\\ShellEx\\MayChangeDefaultMenu", szContextMenuClassID, NULL, (LPBYTE)L"", REG_SZ, // register the context menu handler under the MyNSE_Type type. HKEY_CLASSES_ROOT, L"MyNSE_Type\\shellex\\ContextMenuHandlers\\%s", szContextMenuClassID, NULL, (LPBYTE)szContextMenuClassID, REG_SZ,
SendTo只是实现IContextMenu(2,3)的简单外壳扩展。 在Windows 7中,扩展的CLSID是{7BA4C740-9E81-11CF-99D3-00AA004AE837}(别忘了在你想支持的其他Windows版本中检查正确的CLSID)。 所以只需要使用这样的东西:
function TMenuWithSentTo.QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst, idCmdLast, uFlags: UINT): HResult; const SendToCLSID: TGUID = '{7BA4C740-9E81-11CF-99D3-00AA004AE837}'; var ShellExtInit: IShellExtInit; begin Result := 0; // Add you menu items here CoCreateInstance(SendToCLSID, nil, CLSCTX_INPROC_SERVER, IContextMenu, FSendToMenu); FSendToMenu.QueryInterface(IShellExtInit, ShellExtInit); ShellExtInit.Initialize(nil, FDataObject, 0); // your IDataObject with CFSTR_SHELLIDLIST format Result := Result + FSendToMenu.QueryContextMenu(Menu, indexMenu, idCmdFirst, idCmdLast, uFlags); // Add you menu items here end; function TMenuWithSentTo.InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult; begin if IsMyCommand(lpici) then begin // Process your command here Result := S_OK; end else Result := FSendToMenu.InvokeCommand(lpici); end; function TMenuWithSentTo.GetCommandString(idCmd: UINT_PTR; uFlags: UINT; pwReserved: PUINT; pszName: LPSTR; cchMax: UINT): HResult; begin if IsMyCommandID(idCmd) then begin // Process your command here Result := S_OK; end else FSendToMenu.GetCommandString(idCmd); end; function TMenuWithSentTo.HandleMenuMsg(uMsg: UINT; WParam: WPARAM; LParam: LPARAM): HResult; var SendToMenu2: IContextMenu2; begin if IsMyMessage(uMsg, WParam, LParam) then begin // Process your command here Result := S_OK; end else begin FSendToMenu.QueryInterface(IContextMenu2, SendToMenu2); Result := SendToMenu2.HandleMenuMsg(uMsg, WParam, LParam); end; end; function TMenuWithSentTo.HandleMenuMsg2(uMsg: UINT; wParam: WPARAM; lParam: LPARAM; var lpResult: LRESULT): HResult; var SendToMenu3: IContextMenu3; begin if IsMyMessage(uMsg, WParam, LParam) then begin // Process your command here Result := S_OK; end else begin FSendToMenu.QueryInterface(IContextMenu3, SendToMenu3); Result := SendToMenu3.HandleMenuMsg(uMsg, WParam, LParam); end; end;
但是你应该准备好SendTo的一些命令会被隐藏起来,有些命令不能正常工作,因为有些命令会请求真实的文件,但是你只有虚拟的。
正常发送到菜单:
发送到NSE的菜单:
简单的方法是将一个快捷方式添加到SendTo文件夹。 要发现这一点,只需将%APPDATA%\Microsoft\Windows\SendTo
粘贴到资源管理器窗口即可。
这只适用于如果你有一个命令行程序,文件名作为参数。 如果这不是您所需要的,请编辑您的问题,并详细说明如何访问您的扩展代码。 另外,如果这是C#请标记它。
SendTo的注册表项可以在HKEY_CLASSES_ROOT \ AllFilesystemObjects \ shellex \ ContextMenuHandlers找到。 至少从Vista到Windows 8的价值是{7BA4C740-9E81-11CF-99D3-00AA004AE837}。 你可以写这个键的外壳扩展。 我过去做过这个,但是没有任何可以帮助的源代码。 文档在这里: http : //msdn.microsoft.com/en-us/library/windows/desktop/cc144067%28v=vs.85%29.aspx 。