Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Possible Bug in IContextMenu::QueryContextMenu when using InsertMenu

43 views
Skip to first unread message

Jeffrey Walton

unread,
Dec 1, 2007, 4:09:44 AM12/1/07
to
Hi All,

I'd like to confirm this issue with others who know more. This *did
not* exist in Windows 2000, but *does* exist in XP, 2003, and Vista. I
suspect it is a side effect of the major rewrite that occured between
2000/XP.

The problem is that we insert two menu items (from two different
Dlls), but only one menu item is listed in Explorer's Context Menu.

Any comments on my misuse of InsertMenu would be greatly appreciated.
I've already tried so many variations on calling InsertMenu, I believe
I covered most cases.

Jeff
Jeffrey Walton

== Background ==
Create two distinct shell extension Dlls using the ATL COM wizard (not
necessary). Name them such that the first three letters of each Dll
are the same (this promotes 'stacking' or grouping together of the
entries in the Context Menu). For example, ABC_Dll_1, and ABC_Dll_2.

Then, implement the standard interfaces: Initialize(LPCITEMIDLIST,
LPDATAOBJECT, HKEY), InvokeCommand(LPCMINVOKECOMMANDINFO),
GetCommandString(UINT, UINT, UINT*, LPSTR, UINT), and
QueryContextMenu(HMENU, UINT, UINT, UINT, UINT).

Finally, add a handler for any file type in the registry script for
both Dlls:
HKCR
{
NoRemove *
{ ...
ForceRemove ACB_Dll_1 = s '{xxxxxxxx-xxxx-xxxx-xxxx-
xxxxxxxxxxxx}'
... }
}

== Reproduction ==
In IContextMenu::QueryContextMenu, add the following code:

...
UINT uID = uidFirstCmd;
int filecount = GetFileCount();

if( filecount == 0 )
{
// We did not insert anything. We must inform as such,
// since other Context menu handlers downstream depend on
// our result.
return MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_NULL, 0);
}
else if( filecount >= 1 )
{
// InsertMenu always returns TRUE
InsertMenu( hmenu, uMenuIndex , MF_BYPOSITION,
uID++, _T("Description") );
}
else
{
DebugBreak();
}

return MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_NULL, uID -
uidFirstCmd);

== Results of CDB tracing ==
When ABC_Dll_1 calls InsertMenu, it does so with the following
parameters:
uID = uidFirstCmd;
InsertMenu( hMenu /*=0x148e0139*/ , uMenuIndex /* =0x00 */,
MF_BYPOSITION,
uID /* =0x7973*/, T("Description") )

When ABC_Dll_2 calls InsertMenu, it does so with the following
parameters:
uID = uidFirstCmd;
InsertMenu( hMenu /*=0x148e0139*/ , uMenuIndex /* =0x00 */,
MF_BYPOSITION,
uID /* =0x7974*/, T("Description") )

** uidFirstCmd has been incremented as expected. **

=== InsertMenu tracing ===
InsertMenu creates a structure, calls SetMenuItemInfoStruct() and then
call ThenkedMenuItemInfo. All calls return a non-zero value in EAX. I
presume this means the function succeded (I do not have source code).

=== Shell32 tracing ===
After each menu is inserted, control is passed from our
QueryContextMenu to Shell32. First is Shell32!HDXA_AppendMenuItems2.

==== Shell32!HDXA_AppendMenuItems2 tracing ====
The pseudocode of the parameter validation is:
ECX = uID - uidFirstCmd // 1: we inserted 1 item
ECX &=0xFFFF
EDI = uidFirstCmd
EDI -= Relative Base Value // Some sort of based adjustment?
EAX -= EDI // some sort of difference
EAX += ECX // EAX = 59 in my case

Then a call to Shell32!_imp__DSA_InsertItem. Shell32!
_imp__DSA_InsertItem returns 0x004 fifor the first Dll, and 0x007 for
the second call due to the second Dll. So I presume this means the
function succeded (I do not have source code).


Jeffrey Walton

unread,
Dec 1, 2007, 4:48:48 AM12/1/07
to
According to MSDN InsertMenu (http://msdn2.microsoft.com/en-us/library/
ms647987.aspx), one should call DrawMenuBar() if the menu changes.
However, we do not get the HWND we need for DrawMenuBar() until
InvokeCommand(), which is called when a user *clicks* on our menu
item.

Jeff

0 new messages