问题
I have a namespace extension, which provides a virtual view of files/folders in a server.
In the IContextMenu::QueryContextMenu()
I have added some of the custom menu items.
I have also set couple of SGAOF flags in the IShellFolder::GetAttributesOf()
to get the rename, delete, and properties, in the context menu.
Is there any way I can get the "Send To" option in the context menu for items in my namespace extension? and How do I handle these commands once these are enabled?. Please advise.
This is the code I tried as Denis Anisimov suggested
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);
}
The default context menu is created as part of GetUIObjectOf. and the instance of MyNSEContextMenu class is through the 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;
}
Related registries written are as follows
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,
回答1:
SendTo is just simple shell extension which implements IContextMenu(2,3). CLSID of extension is {7BA4C740-9E81-11CF-99D3-00AA004AE837} in Windows 7 (dont forget to check correct CLSID in other Windows versions you want to support). So just use something like this:
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;
But your should be ready that some command of SendTo will be hidden and some will not work correctly because some of them requests real files but you have virtual only.
Normal Send to menu:
Send to menu in NSE:
回答2:
The simple way is to add a shortcut to the SendTo folder. To find that, simply paste %APPDATA%\Microsoft\Windows\SendTo
into an Explorer window.
This only works if you have a command line program that takes a file name as an argument. If this is not what you need please edit your question with further details of how your extension code is accessed. Also, if this is C# please tag it so.
The registry key for SendTo can be found at HKEY_CLASSES_ROOT\AllFilesystemObjects\shellex\ContextMenuHandlers. The value since at least Vista and up to Windows 8 is {7BA4C740-9E81-11CF-99D3-00AA004AE837}. You can write a shell extension for this key. I have done this in the past, but don't have any source code that would help. The documentation is here: http://msdn.microsoft.com/en-us/library/windows/desktop/cc144067%28v=vs.85%29.aspx.
来源:https://stackoverflow.com/questions/22990080/how-to-addenable-standard-send-to-context-menu-option-in-a-namespace-extensi