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,