Simerjeet

Hi

I have Browser Helper Object which is used to implement a customized context menu when right clicked on an image. This has been done by overriding the ShowContextMenu() function of
IDOCHostUIHandler interface.
My customized context menu shows up successfully on right-clicking, but I have following issues:

1. Since I am using the default menu lying in the shdocvw.dll, I loose all the enteries created by other third party vendors like yahoo and google.
2. Also for adding the Standard Menu extensions (which are mentioned in the registry) i use the following code
Code Snippet

V_VT(&var1) = VT_INT_PTR;
V_BYREF(&var1) = hMenu;

V_VT(&var2) = VT_I4;
V_I4(&var2) = dwID;

hr = spCT->Exec(&CGID_ShellDocView, SHDVID_ADDMENUEXTENSIONS, 0, &var1, &var2);

but the HRESULT returned in hr is E_INVALIDARGS. So I loose the standard menu extensions as well

Can anyone please suggest me a mechanism, how I can retain the context menu enteries from third part vendors as well as the standard menu extensions in the registry while still be able to show my own entry.

Please note that my own custom menu entry is not a simple menu item. It is one with an icon, like Google shows with a "G' icon.

Thanks

Simer



Re: Internet Explorer Extension Development Cutomizing the IE context menu

John Sudds - MSFT

Nice try, but I do not recommend this approach.

The IDocHostUIHandler interface was created to permit applications that host the WebBrowser control to implement their own custom UI. It was never intended to be used from within a BHO. As you have figured out, using it from within the browser circumvents every other code path that needs to modify the browser context menu, including GPOs (administrative templates) that prevent certain menu options from appearing.

Your code snippet is not long enough to tell what might be happening. Have you already added your custom menu option, or does that step follow the code above






Re: Internet Explorer Extension Development Cutomizing the IE context menu

Simerjeet

Thanks for the suggestions.

In the code snippet mentioned above, the code for adding my context menu item follows afterwards. Till this point, I get the default menu from the shdocvw.dll and try to add the context menu extensions that mentioned in the registry.

Also, can you please suggest me a way, how I can achieve adding my own context menu item (with an icon) to the IE browser context menu and still retain menu items by other third party vendors like google and yahoo

Regards





Re: Internet Explorer Extension Development Cutomizing the IE context menu

Nathan Baker

Hi, Simerjeet and John,

I've been working with this as well, and ran into the same problem you did. Using the registry is not a solution that does what we want, so we have tried using other methods.

The one that has gotten us the farthest at this point is to subclass the browser window, interpose our own window procedure, capture WM_INITMENUPOPUP to get the hmenu, and insert our own menu items the Win32 way.

Unfortunately, the endgame for this is still in doubt. IE does not generate a WM_COMMAND or WM_MENUCOMMAND message when a menu item is clicked, and we have been having difficulty with getting even WM_LBUTTONUP messages while the menu is displayed. I'm not familiar enough with Win32 programming to know if this is a dead end or if there's a chance that we can still pull this off, but I'll let you know if it turns out well.

In the meantime, suggestions from others who have succeeded inserting menu items into the existing menu would be appreciated.

EDIT: It is worth noting that the Yahoo toolbar's menu items seem resilient to other toolbars/add-ons overriding IDocHostUIHandler:: ShowContextMenu, while the Google toolbar's are not. Thus, it is clearly possible (via whatever method Yahoo uses) to do what it is we're trying to do.

Thanks,
Nathan




Re: Internet Explorer Extension Development Cutomizing the IE context menu

John Sudds - MSFT

I bet there are several forum readers that are wondering exactly how you accomplished this feat of Win32 magic. (I know I am...) Is a sanitized code snippet forthcoming

As a cautionary note, the Yahoo tools have earned an uneasy reputation with the IE team. They must employ some serious hackers over there because they are notorious for finding every possible way to implement their features. Unfortunately, the IE7 rearchitecturing exposed the weaknesses of this approach and the next release of IE is almost sure to do it again.






Re: Internet Explorer Extension Development Cutomizing the IE context menu

Nathan Baker

Hi John,

I didn't think it was particularly magical, but I can post some (C#) code if you're interested.

As background, I use a customized version of the (awkwardly-named) WndProcHooker class available on MSDN (http://msdn2.microsoft.com/en-us/library/ms229658.aspx). I modified it to take a hWnd directly rather than a System.Windows.Forms.Control.


Here is the setup function:

Code Snippet

protected void SetUpContext(mshtml.HTMLDocument hDoc)
{
//Set the UI handler for the current document (for context menu)
try {
IOleWindow iole = (IOleWindow)hDoc;
IntPtr phwnd;
iole.GetWindow(out phwnd);

//Menu init
WndProcHooker.HookWndProc(
phwnd,
new WndProcHooker.WndProcCallback(InitPopup_Handler),
Win32.WM_INITMENUPOPUP);

//Menu destroy
WndProcHooker.HookWndProc(
phwnd,
new WndProcHooker.WndProcCallback(UnInitPopup_Handler),
Win32.WM_UNINITMENUPOPUP);
}


Here is the Menu Initialization:

Code Snippet

protected int InitPopup_Handler(IntPtr hwnd,
uint msg,
uint wParam, //HMENU
int lParam,
ref bool handled)
{
handled = true;

hmenu = wParam;
//0x7000 is a magic number used for testing purposes
if (!Win32.InsertMenu(new IntPtr(wParam), 0x7000, Win32.MF_BYCOMMAND, 0x7000, "Test")) {
Log.WriteLine(LogLevels.PartialFailure, "Could not insert context menu item.");
}

WndProcHooker.HookWndProc(
hwnd,
new WndProcHooker.WndProcCallback(LMB_Up_Handler),
Win32.WM_LBUTTONUP);

return 0;
}



The uninit function is similar...it removes the menu item and unhooks the WM_LBUTTONUP message. This is all standard Win32 popup menu stuff, with a little bit of interop magic to make it work in C#.

As mentioned before, the problem with this approach right now is that the LBM_Up_Handler is never called while the menu is displayed. If we can get this resolved, we can use the standard Win32 way of handling popup menus to insert and remove menu items from the standard menu.

In reference to your comment about Yahoo, I wouldn't know how they do things there. However, I will say that if IE actually provided a decent way of appending dynamic items onto the standard menu without breaking others' extensions, there would be no hacking (or "Win32 magic") necessary. But you work with what you're given, and the method above I think works well without seeming too hackish or relying on features that are likely to be removed.

Nathan




Re: Internet Explorer Extension Development Cutomizing the IE context menu

John Sudds - MSFT

Thanks for your post.

It's cool to see how this stuff works in managed code. You've done a nice job of avoiding the usual pitfalls--such as relying on window hierarchy and class names. I likewise hope that a "supportable" workaround can be found.

BTW, Yahoo is one of our premiere partners and I certainly don't mean to give anyone the impression that they are doing something wrong here, especially when almost every other cool add-on I know about is doing the same. Just know that "advanced" add-on development of this kind tends to raise eyebrows over here, simply because we feel your pain when everything you've worked so hard to attain suddenly stops working when the browser is changed to accomodate new features.

Yes, I hear you. Big Smile






Re: Internet Explorer Extension Development Cutomizing the IE context menu

Nathan Baker

Thanks, John.

What I posted above is just the latest of several attempts to find a clean solution that doesn't rely on digging into IE's internals--we are by no means locked in to this solution. If you have any suggestions as to better paths we could take, I would certainly appreciate it.

To be honest, my biggest frustration has been the lack of definitive resources for doing something like this (hence me bothering random strangers on forums about these problems). If there's no supported API for doing this sort of thing, I personally believe it would be best to come out and say it. This way extension developers will at least know that what we're doing is not necessarily going to be supported downstream.

I appreciate your responses, and any tips about how we could finish this up or other ways we could go about it would not go unappreciated Smile

Nathan




Re: Internet Explorer Extension Development Cutomizing the IE context menu

G Back

John, although we all appreciate your help and responses in this forum, I can't help but say this:

What you call "advanced" add-on development (customized menus, menu images, using context-sensitive menus and being able to AJAX their content) is a task so simple outside the Microsoft IE world that in 2007 it no longer requires formal training in programming - self-taught programmers with a moderate amount of experience doing client-side Javascript do it routinely for such browsers as Firefox. I assume that's why you put the "advanced" in double quotes.

- GB





Re: Internet Explorer Extension Development Cutomizing the IE context menu

Simerjeet

Well Well.... There seems to be a lot of activity happening here when I was asleepSmile

Nathan,

I too attempted the same solution of hacking the WndProc but then got stuck. Though my menu item gets added to the context menu but when I clicked my menu item, it simply refused to generated the WM_COMMAND message.

I was always under the impression that there must be a simple and cleaner way to add such context menu items to the IE Context menu and may be I was missing out something.

Now that we know its not simple and straightforward, I would appreciate if anyone of us first finds a decent solution/workaround to this issue, kindly share on this forum.

Regards






Re: Internet Explorer Extension Development Cutomizing the IE context menu

G Back

it simply refused to generated the WM_COMMAND message.

That may be because IE might be calling TrackPopupMenu with the
TPM_RETURNCMD flag set, see http://www.answers.com/topic/trackpopupmenu-win-api . When this flag is set, the menu item is returned from TrackPopupMenu. This means TrackPopupMenu probably will not post a WM_COMMAND message when it processes a WM_LBUTTONUP message inside the menu item area.

(Of course, it would take only 5 minutes to verify whether this is true if IE were an Open Source project... When I was younger, I believed RMS was a nut and not us. Now I'm afraid it may be the other way around.)

- GB





Re: Internet Explorer Extension Development Cutomizing the IE context menu

Nathan Baker

Right, as mentioned above, the Explorer context menu does not send a WM_COMMAND message (this is especially interesting considering that it appears to consume those messages (see for example the page at http://msdn.microsoft.com/workshop/browser/hosting/wbcustompart2.asp, which overrides ShowContextMenu and then uses SendMessage with WM_COMMAND to notify explorer if it's a default menu item which has been clicked) -- it's as if this method of augmenting the standard context menu were explicitly made more difficult in IE, since IE used to send a WM_COMMAND message (see http://groups.google.com/group/microsoft.public.inetsdk.programming.mshtml_hosting/browse_thread/thread/73238de231f7fdd9/bcaab632d0647855), but as of IE5 no longer does so).

This is why I have been trying to capture the LBUTTON_UP message instead. If I can get the coordinates of the button click and then determine if it matches our item using GetMenuItemRect, that is an indication that our item has been clicked. However, like I mentioned above, this step has proved more difficult than I would have thought.

Thanks for the responses, as most of the time when I have asked for help about this issue online I haven't gotten anything. Maybe we should form an 'IE add-on writers support group' or something Smile.

Nathan




Re: Internet Explorer Extension Development Cutomizing the IE context menu

G Back

A piece of code from the open source community may provide us with an explanation for why an overridden window procedure never sees the WM_LBUTTONUP message that occurs when a user clicks on a menu item: because it is never dispatched to that window's procedure.

If you look at the open source reimplementation of Windows, called ReactOS, and specifically their implementation of TrackPopupMenu (called MenuPopupMenu) (see http://www.reactos.org/generated/doxygen/d1/d67/dll_2win32_2user32_2windows_2menu_8c.html#a56) you'll find that instead of calling GetMessage/DispatchMessage in their local message loop, which would send the message through the window function, they instead peek at the message queue, and if it is a WM_LBUTTONUP message, they handle it directly. Unfortunately, the code doesn't describe the rationale for that decision, but we can suspect that it may be to mimic what MS's original implementation does (among other design considerations.)

That being the case, the only chance is to interpose in the message queue before the WM_LBUTTONUP message is seen by IE. You may be able to use SetWindowsHookEx for this purpose, described here: http://www.codeproject.com/threads/winspy.asp

- GB





Re: Internet Explorer Extension Development Cutomizing the IE context menu

Jim McCurdy

I am implementing a similar BHO to add assist with a context menu extension. What I have done is to combine the simplier reg-entry based Menu Extension approach that Microsoft favors (http://msdn2.microsoft.com/en-us/library/aa753589.aspx) with a BHO similar to yours. In my BHO COM object, I register context Menu Extension that points to a HTML/JS file on my web site. This adds the menu items into the IE context menu simply and reliably. I then use the BHO, as you have done, to:

o subclass the IE window

o catch the WM_INITPOPUPMENU message

o look for my menu item

o add an icon for it

o move it up or down in the menu

o remove it under certain condition.

This works well except that the "command" that gets executed when clicking the menu item is handled by IE's normal context Menu Extension implementation which directs to a URL where I can get at the page doc. I am looking into ways to have the conext Menu Extension call back into my BHO so I can keep the implementation entirely in the BHO and not straddled out to a web page. I am not sure if that can be done, even though IE toolbar buttons can call a COM object.

I'd be interested in hearing from you, and whether you think this could work for you.

Jim McCurdy





Re: Internet Explorer Extension Development Cutomizing the IE context menu

Nathan Baker

Jim,

Thanks for your post. I think that your method might be promising. As for the command, you can try using our method of trapping the LBUTTONUP message (more on this in a minute), meanwhile setting the action in the registry to something that is effectively a no-op.

We recently managed to figure out how to get the LBUTTONUP message for the menu. It was more complex than I had figured it would be. Essentially, we had to set a windows hook (via SetWindowsHookEx) to have our custom callback executed when GetMessage was called. If anyone else is trying to do this from C#-land, one warning is that C# will automatically create delegates for functions passed in as parameters and then garbage-collect them at potentially awkward moments, so keep a global reference around.

Once we get this message, the following sequence can be performed:
1: Get the coordinates of the click (these are client coordinates)
2: Call MenuItemFromPoint to get the offset of the menu item which was clicked
3: Call GetMenuItemId with that offset to get the ID of the clicked item
4: Call GetMenuItemRect to get the rectangle for the item (this returns coordinates relative to the menu, which are useless, unless the first parameter is null. This contradicts the documentation, which claims that the function returns screen coordinates, and doesn't mention that the returned rectangle differs based on the first parameter)
5: See if the rectangle contains the point
6: If so, send ourselves a WM_MENUCOMMAND message so that we know to process the action

The toolbar that we are writing is part of an open-source project; once it has been released, I will post a link to a page where the code can be downloaded. If anyone wants to see (C#) code before that time, I will be glad to post relevant snippets.

So to go back to your problem, Jim, you can take the same approach and, as I mentioned above, have the command that IE executes just do nothing. This is a bit of a roundabout way of achieving the goal, but it may also be the best way.

Nathan