I'm trying to write a context menu handler with c++. I would like the handler to work on all files and all folders, also those in the left pane o the explorer. I started based on a CodeProject Project that I'm trying to adapt to my needs. I got it from here.
Until now everything seems to work as expected, except for the folders of the Explorer's left pane. There I get an AccessViolationException. The exception occures between the right click and the display of the context menu. I removed the code in the different functions until it works again and it seems that the problem is coming from the QueryContextMenu method.
Does someone know what I'm doing wrong?
Here is my current code that works (somewhat obvious because no item is added):
STDMETHODIMP ShellExt::Initialize (LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hProgID )
{
FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stg = { TYMED_HGLOBAL };
HDROP hDrop;
// Look for CF_HDROP data in the data object.
if ( FAILED( pDataObj->GetData ( &fmt, &stg ) ))
{
// Nope! Return an "invalid argument" error back to Explorer.
return E_INVALIDARG;
}
// Get a pointer to the actual data.
hDrop = (HDROP) GlobalLock ( stg.hGlobal );
// Make sure it worked.
if ( NULL == hDrop )
return E_INVALIDARG;
// Sanity check - make sure there is at least one filename.
UINT uNumFiles = DragQueryFile ( hDrop, 0xFFFFFFFF, NULL, 0 );
HRESULT hr = S_OK;
if ( 0 == uNumFiles )
{
GlobalUnlock ( stg.hGlobal );
ReleaseStgMedium ( &stg );
return E_INVALIDARG;
}
// Get the name of the first file and store it in our member variable m_szFile.
if ( 0 == DragQueryFile ( hDrop, 0, m_szFile, MAX_PATH ) )
hr = E_INVALIDARG;
GlobalUnlock ( stg.hGlobal );
ReleaseStgMedium ( &stg );
return hr;
}
STDMETHODIMP ShellExt::QueryContextMenu (HMENU hmenu, UINT uMenuIndex, UINT uidFirstCmd, UINT uidLastCmd, UINT uFlags )
{
return MAKE_HRESULT ( SEVERITY_SUCCESS, FACILITY_NULL, 0 );
}
STDMETHODIMP ShellExt::GetCommandString (UINT_PTR idCmd, UINT uFlags, UINT* pwReserved, LPSTR pszName, UINT cchMax)
{
return E_INVALIDARG;
}
STDMETHODIMP ShellExt::InvokeCommand (LPCMINVOKECOMMANDINFO pCmdInfo)
{
return S_OK;
}
But now if I add an item in ShellExt::QueryContextMenu the Explorer's left pane throws the exception, while files and folders in the right pane work great. I tried the following two version I found on the internet, but both have the same problem:
STDMETHODIMP ShellExt::QueryContextMenu (HMENU hmenu, UINT uMenuIndex, UINT uidFirstCmd, UINT uidLastCmd, UINT uFlags )
{
// If the flags include CMF_DEFAULTONLY then we shouldn't do anything.
if ( uFlags & CMF_DEFAULTONLY )
return MAKE_HRESULT ( SEVERITY_SUCCESS, FACILITY_NULL, 0 );
InsertMenu ( hmenu, uMenuIndex, MF_BYPOSITION, uidFirstCmd, _T("Test Item") );
return MAKE_HRESULT ( SEVERITY_SUCCESS, FACILITY_NULL, 1 );
}
and
STDMETHODIMP ShellExt::QueryContextMenu (HMENU hmenu, UINT uMenuIndex, UINT uidFirstCmd, UINT uidLastCmd, UINT uFlags )
{
// If the flags include CMF_DEFAULTONLY then we shouldn't do anything.
if ( uFlags & CMF_DEFAULTONLY )
return MAKE_HRESULT ( SEVERITY_SUCCESS, FACILITY_NULL, 0 );
UINT uID = uidFirstCmd;
UINT pos = uMenuIndex;
MENUITEMINFO mii = { sizeof(mii) };
mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_STATE;
mii.fType = MFT_STRING;
mii.dwTypeData = _T("Menu 1");
mii.fState = MFS_ENABLED;
mii.wID = uID++;
if (!InsertMenuItem(hmenu, pos++, TRUE, &mii))
{
return HRESULT_FROM_WIN32(GetLastError());
}
return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, uID - uidFirstCmd);
}
Parameters I get in QueryContextMenu:
- hmenu = 0x0000000001480405
- uMenuIndex = 3
- uidFirstCmd = 148
- uidLastCmd = 32762
- uFlags = 1044
Exception Details.
The code in QueryContextMenu and GetCommandString gets executed. The exception occures somewhere after this but still before the contextmenu gets visible. Unfortunaly the details do not mean very much to me:
Exception thrown at 0x00007FF9B1C4C613 (shell32.dll) in explorer.exe: 0xC0000005: Access violation reading location 0x00007FF9776D9868. occurred
Stacktrace:
shell32.dll!00007ff9b1c4c613()
ExplorerFrame.dll!00007ff98d24993a()
ExplorerFrame.dll!00007ff98d2c69a4()
ExplorerFrame.dll!00007ff98d24de6c()
ExplorerFrame.dll!00007ff98d251286()
ExplorerFrame.dll!00007ff98d1fbad0()
ExplorerFrame.dll!00007ff98d1ad5b3()
ExplorerFrame.dll!00007ff98d180f2e()
user32.dll!00007ff9b079ca66()
user32.dll!00007ff9b079c34b()
comctl32.dll!00007ff99d78b0da()
comctl32.dll!00007ff99d78b017()
ExplorerFrame.dll!00007ff98d187521()
ExplorerFrame.dll!00007ff98d17d2e0()
comctl32.dll!00007ff99d78b0da()
comctl32.dll!00007ff99d78aef2()
user32.dll!00007ff9b079ca66()
user32.dll!00007ff9b079c34b()
duser.dll!00007ff98106dff5()
atlthunk.dll!00007ff983061208()
user32.dll!00007ff9b079ca66()
user32.dll!00007ff9b079c78c()
user32.dll!00007ff9b07afa83()
ntdll.dll!00007ff9b34833a4()
win32u.dll!00007ff9b0071184()
user32.dll!00007ff9b079bfbe()
user32.dll!00007ff9b079be38()
comctl32.dll!00007ff99d77a099()
comctl32.dll!00007ff99d80b556()
comctl32.dll!00007ff99d7b1302()
user32.dll!00007ff9b079ca66()
user32.dll!00007ff9b079c34b()
comctl32.dll!00007ff99d78b0da()
comctl32.dll!00007ff99d78b017()
ExplorerFrame.dll!00007ff98d1bf33b()
ExplorerFrame.dll!00007ff98d1bf27b()
comctl32.dll!00007ff99d78b0da()
comctl32.dll!00007ff99d78aef2()
user32.dll!00007ff9b079ca66()
user32.dll!00007ff9b079c582()
ExplorerFrame.dll!00007ff98d1748a3()
ExplorerFrame.dll!00007ff98d1747a9()
ExplorerFrame.dll!00007ff98d1746f6()
ExplorerFrame.dll!00007ff98d175a12()
ExplorerFrame.dll!00007ff98d1870c2()
windows.storage.dll!00007ff9af8db38c()
windows.storage.dll!00007ff9af8db045()
windows.storage.dll!00007ff9af8daf25()
SHCore.dll!00007ff9b164c315()
kernel32.dll!00007ff9b06281f4()
ntdll.dll!00007ff9b344a251()
It seems I resolved the problem. I reworked the remaining part of the project, i.e. the implementation of the IClassFactory and also the implementation of the IUnknown interface of the shellextension class, with the objective to understand what these "things" are for in that project.
While doing so I found some Bugs, uninitialized variables, casts to wrong types, etc. I also changed some counters from UINT to LONG so that I can use InterlockedIncrement instead of ++. And after that the problem seems to be gone. I can't say exactly what bug caused the AccessViolationException anymore, but at the end it was not in the QueryContextMenu method as I thought...
User contributions licensed under CC BY-SA 3.0