我有一个命名空间扩展,它提供了服务器中文件/文件夹的虚拟视图。
在IContextMenu::QueryContextMenu()
我添加了一些自定义菜单项。
我还在IShellFolder::GetAttributesOf()
中设置了几个SGAOF标志,以便在上下文菜单中获取重命名,删除和属性。
我有什么方法可以获得" 发送到"我的命名空间扩展中的项目的上下文菜单中的选项?一旦启用这些命令,我该如何处理?请指教。
这是我尝试的代码,因为Denis Anisimov建议
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的一部分创建的。而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;
}
编写的相关注册表如下
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,
答案 0 :(得分:1)
SendTo只是简单的shell扩展,它实现了IContextMenu(2,3)。 Windows 7中的扩展名为{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中的菜单:
答案 1 :(得分:0)
简单的方法是向SendTo文件夹添加快捷方式。要找到它,只需将%APPDATA%\Microsoft\Windows\SendTo
粘贴到资源管理器窗口中即可。
仅当您有一个以文件名作为参数的命令行程序时,此方法才有效。如果这不是您所需要的,请编辑您的问题,并详细说明如何访问您的扩展程序代码。另外,如果这是C#,请将其标记。
可以在HKEY_CLASSES_ROOT \ AllFilesystemObjects \ shellex \ ContextMenuHandlers中找到SendTo的注册表项。至少从Vista到Windows 8的价值是{7BA4C740-9E81-11CF-99D3-00AA004AE837}。您可以为此密钥编写shell扩展。我过去做过这个,但是没有任何有用的源代码。文档在这里:http://msdn.microsoft.com/en-us/library/windows/desktop/cc144067%28v=vs.85%29.aspx。