views:

495

answers:

2

I am hosting a web browser control, and want to provide my own context menu.

Ideally, I want to present my own context menu, that contains the original browser's context menu (with all addins etc.) as a sub menu.

If that's not possible / to tricky, I'd be ok with e.g. normally showing my context menu, and showing the original one when the user presses SHIFT.

Do I need to implement IDocHostUIHandler? if yes, how do I specify a custom context menu, how can I force the original one? How do I get the control to use my implementation?

The control is created as such (error handling omitted):

HRESULT hr=AtlAxCreateControlEx(
   L"Shell.Explorer",m_wndWebCtrl.m_hWnd,
   NULL,NULL,(IUnknown**)&unk,
   IID_IWebBrowser2, NULL); // (IPersistStreamInit*)this);

hr = AtlAdviseSinkMap( this, true);

IUnknownPtr unk;
AtlAxGetControl(m_wndWebCtrl.m_hWnd, &unk);

IWebBrowser2Ptr browser2 = unk;
+1  A: 

Yes, you do need to implement IDocHostUIHandler.

Ok, i guess you could intercept right-clicks, keystrokes, and that other message that'll normally display a context menu... But that's probably gonna break badly sooner or later; at very least, i'd expect it to break accessibility.

Once you've intercepted IDocHostUIHandler::ShowContextMenu(), you have the option of returning S_OK to squelch the built-in menu after showing your own. You can use the normal Win32 menu routines for this purpose, a custom control, or even fancy HTML if that's what does it for you. Per the documentation, enough context is provided to allow you to determine what element context is requested for, and what the default context menu would be.

Unfortunately, I know of no way to get a handle to the built-in menu. You could probably fake it by showing your context menu and then returning S_FALSE if the user chose the "original" option, but even then there's no way to attach the resulting menu to an existing popup menu (which really should be gone by the time you return anyway if you're running the modal-loop common to such popups). It is possible to add options to the built-in menus.

You should be able to use GetKeyboardState() to determine the state of the shift key when the menu was requested.


Assuming you only want a subset of the normal browser functionality anyway, you might be better served by just re-implementing the options you want (back, forward, print) and invoking the appropriate command if the user chooses them. Alternately, if you only want normal menus in a very specific scenario (for instance: editing commands in a textarea), use the ShowContextMenu() arguments to identify this and only then return S_FALSE to trigger the default. I've had pretty good luck with this latter technique; after all, they are supposed to be context menus...

Shog9
Thanks Shog :) I just don't want to cut off the user completely from the default functionality, So I guess GetKeyboardState will do the trick. Do also happen to know how I tell ATL to use my IDocHostUIHandler in its client site implementation?
peterchen
Couldn't tell you, i'm afraid... Never tried it using ATL myself. Maybe this will help? http://support.microsoft.com/kb/274202
Shog9
+1  A: 

I am adding the following information how to "inject" your own DocHostUI implementation into the browser control:

The default way is to implement IOleClientSite, and support the IDocHostUIHandler on the implementing object.

There is a simpler way: In the DocumentComplete handler, query the IHTMLDocumennt for ICustomDoc, which allows you to supply your interface from a standalone object. This allows you to keep whatever IOleClientSite implementation your environment provides.

More details can be found here.

peterchen