.NET Forum / .NET Framework / New Users / March 2006
Extending WebBrowser using WebBrowserSite won't call methods - sample code?
|
|
Thread rating:  |
DavidB - 10 Mar 2006 11:11 GMT Trying to extend a 2.0 WebBrowser control using WebBrowserSite as per docs. Tried implementing IDocHostUIHandler, IDocHostUIHandler2, IInternetSecuritymanager, IServiceProvider. The only methods which get called (so far) are IDocHostUIHandler2.GetOverrideKeyPath() and IServiceProvider.QueryService(). What do I have to do to get the others to be called? A bit of sample code would do wonders at this point!!!
DavidB
Igor Tandetnik - 10 Mar 2006 13:13 GMT > Trying to extend a 2.0 WebBrowser control using WebBrowserSite as per > docs. Tried implementing IDocHostUIHandler, IDocHostUIHandler2, [quoted text clipped - 3 lines] > IServiceProvider.QueryService(). What do I have to do to get the > others to be called? If you managed to get IDocHostUIHandler2 called, then you should not have any difficulty with IDocHostUIHandler. Check your QueryInterface implementation, make sure you are actually answering positively to requests for this interface.
IInternetSecurityManager is retrieved with IServiceProvider::QueryService call. You say QueryService does get called - so just implement it appropriately.
 Signature With best wishes, Igor Tandetnik
With sufficient thrust, pigs fly just fine. However, this is not necessarily a good idea. It is hard to be sure where they are going to land, and it could be dangerous sitting under them as they fly overhead. -- RFC 1925
DavidB - 10 Mar 2006 23:27 GMT No, that quite specifically isn't happening. Only one member of IDocHostUIHandler2 gets called (the non-inherited member). Implement IDocHostUIHandler in exactly the same way and nothing in it gets called. Those interfaces do not get requested by WebBrowserSite.QueryService().
I don't have or expect to have an implementation of QueryInterface. I assume the CCW looks after that.
I've got code for doing this in C++, and in C# with managed axWebBrowser in Framework 1.1. I'm just trying to get WebBrowserSite to do something useful in Framework 2.0. One small piece of sample code doing something useful would most likely solve my problem.
Any links, samples, suggestions?
DavidB
>> Trying to extend a 2.0 WebBrowser control using WebBrowserSite as per >> docs. Tried implementing IDocHostUIHandler, IDocHostUIHandler2, [quoted text clipped - 12 lines] > call. You say QueryService does get called - so just implement it > appropriately. Igor Tandetnik - 10 Mar 2006 23:38 GMT > No, that quite specifically isn't happening. Only one member of > IDocHostUIHandler2 gets called (the non-inherited member). Implement [quoted text clipped - 3 lines] > I don't have or expect to have an implementation of QueryInterface. I > assume the CCW looks after that. I have no idea what CCW is.
> I've got code for doing this in C++, and in C# with managed > axWebBrowser in Framework 1.1. I'm just trying to get WebBrowserSite > to do something useful in Framework 2.0. Ah. I don't use .NET and know very little about it. Sorry for wasting your time. Hopefully somebody more knowledgeable in .NET interop will pick up from here.
 Signature With best wishes, Igor Tandetnik
With sufficient thrust, pigs fly just fine. However, this is not necessarily a good idea. It is hard to be sure where they are going to land, and it could be dangerous sitting under them as they fly overhead. -- RFC 1925
Colin Neller - 13 Mar 2006 16:23 GMT David,
The CCW does take care of the QueryInterface call, but if your IDocHostUIHandler is not getting called, I am suspicious of how you have it defined. Verify that the GUID attribute on the interface definition is correct and that the interface is COM visible. If you like, post it here and I'll take a look.
 Signature Colin Neller http://www.colinneller.com/blog
>> No, that quite specifically isn't happening. Only one member of >> IDocHostUIHandler2 gets called (the non-inherited member). Implement [quoted text clipped - 13 lines] > time. Hopefully somebody more knowledgeable in .NET interop will pick up > from here. DavidB - 14 Mar 2006 14:53 GMT > David, > [quoted text clipped - 3 lines] > correct and that the interface is COM visible. If you like, post it here > and I'll take a look. The interface is as correct as I can get it. I tried emorcillo olelib, pinvoke.net and manual.
The interface is implemented on class ExtWebBrowserSite : WebBrowser.WebBrowserSite, which is the way I read the docs. I assume this class cannot be made COM visible, since it inherits from a protected class, but doesn't need to be.
I implemented IDocHostUIHandler, IDocHostUIHandler2 and IServiceProvider on this class (see code). Of these, only IDocHostUIHandler2.GetOverrideKeyPath and IServiceProvider.QueryService get called.
IServiceProvider.QueryService gets called for many SIDs including ISecurityManager but not including IDocHostUIHandler or IDocHostUIHandler2. Without this, I don't see how I can implement IDocHostUIHandler on a different class.
But there are probably many things I don't understand. Any help much appreciated. Sample code would be even better.
[BTW thanks for the link on your blog. I've seen that C# code for NewWindow3 mentioned before, but not been able to find it.]
DavidB
------------ code starts here (long) ------------------- using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; using System.Diagnostics;
namespace WebGetWebControl {
/// <summary> /// Implement class to extend the Web Browser /// </summary> public class ExtWebBrowser : WebBrowser {
//////////////////////////////////////////////////////////////// /// <summary> /// Implement class that allows ActiveX control to retrieve extensibility interfaces /// </summary> class ExtWebBrowserSite : WebBrowser.WebBrowserSite , olelib.IServiceProvider , olelib.IDocHostUIHandler , olelib.IDocHostUIHandler2 { WebBrowser _host; public ExtWebBrowserSite(WebBrowser host) : base(host) { _host = host; Debug.WriteLine(String.Format("ExWBSite ctor {0}", host)); }
#region IDocHostUIHandler Members
void olelib.IDocHostUIHandler.EnableModeless(int fEnable) { Debug.WriteLine(String.Format("IDocHostUIHandler {0}", 0)); throw new Exception("The method or operation is not implemented."); }
olelib.IDataObject olelib.IDocHostUIHandler.FilterDataObject(olelib.IDataObject pDO) { Debug.WriteLine(String.Format("IDocHostUIHandler {0}", 1)); throw new Exception("The method or operation is not implemented."); }
olelib.IDropTarget olelib.IDocHostUIHandler.GetDropTarget(olelib.IDropTarget pDropTarget) { Debug.WriteLine(String.Format("IDocHostUIHandler {0}", 2)); throw new Exception("The method or operation is not implemented."); }
object olelib.IDocHostUIHandler.GetExternal() { Debug.WriteLine(String.Format("IDocHostUIHandler {0}", 3)); throw new Exception("The method or operation is not implemented."); }
void olelib.IDocHostUIHandler.GetHostInfo(ref olelib.DOCHOSTUIINFO pInfo) { Debug.WriteLine(String.Format("IDocHostUIHandler {0}", 4)); throw new Exception("The method or operation is not implemented."); }
void olelib.IDocHostUIHandler.GetOptionKeyPath(ref int pOLESTRchKey, int dw) { Debug.WriteLine(String.Format("IDocHostUIHandler {0}", 5)); throw new Exception("The method or operation is not implemented."); }
void olelib.IDocHostUIHandler.HideUI() { Debug.WriteLine(String.Format("IDocHostUIHandler {0}", 6)); throw new Exception("The method or operation is not implemented."); }
void olelib.IDocHostUIHandler.OnDocWindowActivate(int fActivate) { Debug.WriteLine(String.Format("IDocHostUIHandler {0}", 7)); throw new Exception("The method or operation is not implemented."); }
void olelib.IDocHostUIHandler.OnFrameWindowActivate(int fActivate) { Debug.WriteLine(String.Format("IDocHostUIHandler {0}", 8)); throw new Exception("The method or operation is not implemented."); }
void olelib.IDocHostUIHandler.ResizeBorder(ref olelib.RECT prcBorder, olelib.IOleInPlaceUIWindow pUIWindow, int fRameWindow) { Debug.WriteLine(String.Format("IDocHostUIHandler {0}", 9)); throw new Exception("The method or operation is not implemented."); }
void olelib.IDocHostUIHandler.ShowContextMenu(olelib.ContextMenuTarget dwContext, ref olelib.POINT pPOINT, olelib.IOleCommandTarget pCommandTarget, object HTMLTagElement) { Debug.WriteLine(String.Format("IDocHostUIHandler {0}", 10)); throw new Exception("The method or operation is not implemented."); }
void olelib.IDocHostUIHandler.ShowUI(int dwID, olelib.IOleInPlaceActiveObject pActiveObject, olelib.IOleCommandTarget pCommandTarget, olelib.IOleInPlaceFrame pFrame, olelib.IOleInPlaceUIWindow pDoc) { Debug.WriteLine(String.Format("IDocHostUIHandler {0}", 11)); throw new Exception("The method or operation is not implemented."); }
void olelib.IDocHostUIHandler.TranslateAccelerator(ref olelib.MSG lpmsg, ref olelib.UUID pguidCmdGroup, int nCmdID) { Debug.WriteLine(String.Format("IDocHostUIHandler {0}", 12)); throw new Exception("The method or operation is not implemented."); }
int olelib.IDocHostUIHandler.TranslateUrl(int dwTranslate, int pchURLIn) { Debug.WriteLine(String.Format("IDocHostUIHandler {0}", 13)); throw new Exception("The method or operation is not implemented."); }
void olelib.IDocHostUIHandler.UpdateUI() { Debug.WriteLine(String.Format("IDocHostUIHandler {0}", 14)); throw new Exception("The method or operation is not implemented."); }
#endregion
#region IDocHostUIHandler2 Members
void olelib.IDocHostUIHandler2.EnableModeless(int fEnable) { Debug.WriteLine(String.Format("IDocHostUIHandler2 {0}", 0)); throw new Exception("The method or operation is not implemented."); }
olelib.IDataObject olelib.IDocHostUIHandler2.FilterDataObject(olelib.IDataObject pDO) { Debug.WriteLine(String.Format("IDocHostUIHandler2 {0}", 1)); throw new Exception("The method or operation is not implemented."); }
olelib.IDropTarget olelib.IDocHostUIHandler2.GetDropTarget(olelib.IDropTarget pDropTarget) { Debug.WriteLine(String.Format("IDocHostUIHandler2 {0}", 2)); throw new Exception("The method or operation is not implemented."); }
object olelib.IDocHostUIHandler2.GetExternal() { Debug.WriteLine(String.Format("IDocHostUIHandler2 {0}", 3)); throw new Exception("The method or operation is not implemented."); }
void olelib.IDocHostUIHandler2.GetHostInfo(ref olelib.DOCHOSTUIINFO pInfo) { Debug.WriteLine(String.Format("IDocHostUIHandler2 {0}", 4)); throw new Exception("The method or operation is not implemented."); }
void olelib.IDocHostUIHandler2.GetOptionKeyPath(ref int pOLESTRchKey, int dw) { Debug.WriteLine(String.Format("IDocHostUIHandler2 {0}", 5)); throw new Exception("The method or operation is not implemented."); }
void olelib.IDocHostUIHandler2.GetOverrideKeyPath(ref int pchKey, int dw) { Debug.WriteLine(String.Format("IDocHostUIHandler2 {0}", 6)); throw new Exception("The method or operation is not implemented."); }
void olelib.IDocHostUIHandler2.HideUI() { Debug.WriteLine(String.Format("IDocHostUIHandler2 {0}", 7)); throw new Exception("The method or operation is not implemented."); }
void olelib.IDocHostUIHandler2.OnDocWindowActivate(int fActivate) { Debug.WriteLine(String.Format("IDocHostUIHandler2 {0}", 8)); throw new Exception("The method or operation is not implemented."); }
void olelib.IDocHostUIHandler2.OnFrameWindowActivate(int fActivate) { Debug.WriteLine(String.Format("IDocHostUIHandler2 {0}", 8)); throw new Exception("The method or operation is not implemented."); }
void olelib.IDocHostUIHandler2.ResizeBorder(ref olelib.RECT prcBorder, olelib.IOleInPlaceUIWindow pUIWindow, int fRameWindow) { Debug.WriteLine(String.Format("IDocHostUIHandler2 {0}", 8)); throw new Exception("The method or operation is not implemented."); }
void olelib.IDocHostUIHandler2.ShowContextMenu(olelib.ContextMenuTarget dwContext, ref olelib.POINT pPOINT, olelib.IOleCommandTarget pCommandTarget, object HTMLTagElement) { Debug.WriteLine(String.Format("IDocHostUIHandler2 {0}", 9)); throw new Exception("The method or operation is not implemented."); }
void olelib.IDocHostUIHandler2.ShowUI(int dwID, olelib.IOleInPlaceActiveObject pActiveObject, olelib.IOleCommandTarget pCommandTarget, olelib.IOleInPlaceFrame pFrame, olelib.IOleInPlaceUIWindow pDoc) { Debug.WriteLine(String.Format("IDocHostUIHandler2 {0}", 10)); throw new Exception("The method or operation is not implemented."); }
void olelib.IDocHostUIHandler2.TranslateAccelerator(ref olelib.MSG lpmsg, ref olelib.UUID pguidCmdGroup, int nCmdID) { Debug.WriteLine(String.Format("IDocHostUIHandler2 {0}", 11)); throw new Exception("The method or operation is not implemented."); }
int olelib.IDocHostUIHandler2.TranslateUrl(int dwTranslate, int pchURLIn) { Debug.WriteLine(String.Format("IDocHostUIHandler2 {0}", 12)); throw new Exception("The method or operation is not implemented."); }
void olelib.IDocHostUIHandler2.UpdateUI() { Debug.WriteLine(String.Format("IDocHostUIHandler2 {0}", 13)); throw new Exception("The method or operation is not implemented."); }
#endregion
#region IServiceProvider Members
void olelib.IServiceProvider.QueryService(ref olelib.UUID guidService, ref olelib.UUID riid, IntPtr ppvObject) { Debug.WriteLine(String.Format("IServiceProvider {0}", guidService)); throw new Exception("The method or operation is not implemented."); }
#endregion }
//-------------------------------------------------------------- // Override method to tell ActiveX host where to find extensibility interfaces // protected override WebBrowserSiteBase CreateWebBrowserSiteBase() { return new ExtWebBrowserSite(this); }
public void Test() { } } }
>>> No, that quite specifically isn't happening. Only one member of >>> IDocHostUIHandler2 gets called (the non-inherited member). Implement [quoted text clipped - 13 lines] >> your time. Hopefully somebody more knowledgeable in .NET interop will >> pick up from here. Colin Neller - 14 Mar 2006 16:03 GMT >> Verify that the GUID attribute on the interface definition is correct and >> that the interface is COM visible.
> The interface is implemented on class ExtWebBrowserSite : > WebBrowser.WebBrowserSite, which is the way I read the docs. I assume this > class cannot be made COM visible, since it inherits from a protected > class, but doesn't need to be. The _interface_ definition needs to be COM visible, not necessarily the class implementing it. Please post your interface definition for IDocHostUIHandler.
> IServiceProvider.QueryService gets called for many SIDs including > ISecurityManager but not including IDocHostUIHandler or > IDocHostUIHandler2. Without this, I don't see how I can implement > IDocHostUIHandler on a different class. IDocHostUIHandler and IDocHostUIHandler2 both are queried through QueryInterface, not QueryService. The behavior you are seeing is the correct one. You were right to implement IDocHostUIHandler, IDocHostUIHandler2, and IServiceProvider in the same class.
> [BTW thanks for the link on your blog. I've seen that C# code for > NewWindow3 mentioned before, but not been able to find it.] No problem, but do keep in mind that NewWindow3 is only supported on Windows XP SP2 and later.
DavidB - 16 Mar 2006 09:44 GMT > The _interface_ definition needs to be COM visible, not necessarily the > class implementing it. Please post your interface definition for > IDocHostUIHandler. I didn't know that. The documentation says [ComVisible] is true by default; nothing I can find anywhere about making interfaces ComVisible; I've implemented other classes and never found any use for [ComVisible]. How about that. Where do you put it?
Here it is -- exactly as imported from a type library intended for VB.
/////////////////////////////////////////////////// using System; using System.Runtime.InteropServices;
namespace olelib { [InterfaceType(1)] [Guid("BD3F23C0-D43E-11CF-893B-00AA00BDCE1A")] public interface IDocHostUIHandler { void EnableModeless(int fEnable); IDataObject FilterDataObject(IDataObject pDO); IDropTarget GetDropTarget(IDropTarget pDropTarget); object GetExternal(); void GetHostInfo(ref DOCHOSTUIINFO pInfo); void GetOptionKeyPath(ref int pOLESTRchKey, int dw); void HideUI(); void OnDocWindowActivate(int fActivate); void OnFrameWindowActivate(int fActivate); void ResizeBorder(ref RECT prcBorder, IOleInPlaceUIWindow pUIWindow, int fRameWindow); void ShowContextMenu(ContextMenuTarget dwContext, ref POINT pPOINT, IOleCommandTarget pCommandTarget, object HTMLTagElement); void ShowUI(int dwID, IOleInPlaceActiveObject pActiveObject, IOleCommandTarget pCommandTarget, IOleInPlaceFrame pFrame, IOleInPlaceUIWindow pDoc); void TranslateAccelerator(ref MSG lpmsg, ref UUID pguidCmdGroup, int nCmdID); int TranslateUrl(int dwTranslate, int pchURLIn); void UpdateUI(); } } /////////////////////////////////////////////////////
> No problem, but do keep in mind that NewWindow3 is only supported on > Windows XP SP2 and later. Not a problem. It's in-house code, so that's not an issue.
All hints gratefully accepted.
DavidB
Colin Neller - 16 Mar 2006 16:40 GMT >> The _interface_ definition needs to be COM visible, not necessarily the >> class implementing it. Please post your interface definition for >> IDocHostUIHandler.
> I didn't know that. The documentation says [ComVisible] is true by > default; nothing I can find anywhere about making interfaces ComVisible; > I've implemented other classes and never found any use for [ComVisible]. > How about that. Where do you put it? I am not absolutely sure about the COM visibility attribute, but it doesn't hurt. Some examples I have seen have it defined explicitly. You are correct that it is true by default (unless you have set it false at the assembly or super-class level), so I doubt it is the problem in your case.
After having reviewed your interface, I noticed that the methods are defined in alphabetical order. Since this is an IUnknown (not IDispatch) inteface, the order of the methods must be in the correct order for VTable lookup. Below is a definition that has the correct order, and I have used it successfully before (from http://www.codeproject.com/cs/miscctrl/WebBrowserEx.asp). Also notice the ComImport attribute... honestly, I don't fully understand what it does (anyone else care to comment?), but it may be necessary.
--- code ---
[ComImport()] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [GuidAttribute("bd3f23c0-d43e-11cf-893b-00aa00bdce1a")] internal interface IDocHostUIHandler { [PreserveSig] uint ShowContextMenu(uint dwID, ref tagPOINT ppt, [MarshalAs(UnmanagedType.IUnknown)] object pcmdtReserved, [MarshalAs(UnmanagedType.IDispatch)] object pdispReserved);
void GetHostInfo(ref DOCHOSTUIINFO pInfo); void ShowUI(uint dwID, ref object pActiveObject, ref object pCommandTarget, ref object pFrame, ref object pDoc); void HideUI(); void UpdateUI(); void EnableModeless(int fEnable); void OnDocWindowActivate(int fActivate); void OnFrameWindowActivate(int fActivate); void ResizeBorder(ref tagRECT prcBorder, int pUIWindow, int fRameWindow);
[PreserveSig] uint TranslateAccelerator(ref tagMSG lpMsg, ref Guid pguidCmdGroup, uint nCmdID);
void GetOptionKeyPath([MarshalAs(UnmanagedType.BStr)] ref string pchKey, uint dw); object GetDropTarget(ref object pDropTarget);
[PreserveSig] int GetExternal([MarshalAs(UnmanagedType.IDispatch)] out object ppDispatch);
[PreserveSig] uint TranslateUrl(uint dwTranslate, [MarshalAs(UnmanagedType.BStr)] string pchURLIn, [MarshalAs(UnmanagedType.BStr)] ref string ppchURLOut);
IDataObject FilterDataObject(IDataObject pDO); }
DavidB - 19 Mar 2006 14:14 GMT Thanks, Collin.
The (sorted) interface definition I gave you was generated by the COM import functionality. The real interface is defined in IDL, and does appear to be in the correct order. Even so, I tried your definition and it made no difference.
Unless a Microsoftie is prepared to let us all into the secret, I'm going to have to write this one off as: Nice idea, no cigar.
DavidB
>>> The _interface_ definition needs to be COM visible, not necessarily the >>> class implementing it. Please post your interface definition for [quoted text clipped - 61 lines] > IDataObject FilterDataObject(IDataObject pDO); > } Charles Law - 19 Mar 2006 19:40 GMT Have you not been able to use the working sample I posted?
Charles
> Thanks, Collin. > [quoted text clipped - 74 lines] >> IDataObject FilterDataObject(IDataObject pDO); >> } uwe.keim@gmail.com - 17 Mar 2006 05:58 GMT Here is my (working) hint:
1.) Create an own class, derive that class solely from IDocHostUIHandler:
private class MyDocHostUIHandler : UnsafeNativeMethods.IDocHostUIHandler { ... }
2.) introduce the interface definition of ICustomDoc. E.g. like the following:
[ComImport(), InterfaceType( ComInterfaceType.InterfaceIsIUnknown ), GuidAttribute( "3050f3f0-98b5-11cf-bb82-00aa00bdce0b" )] internal interface ICustomDoc { [PreserveSig] void SetUIHandler( IDocHostUIHandler pUIHandler ); }
3.) Call that interface's member:
private MyDocHostUIHandler docHostUIHandler = null;
protected override void OnDocumentCompleted( WebBrowserDocumentCompletedEventArgs e ) { if ( docHostUIHandler == null ) { docHostUIHandler = new MyDocHostUIHandler( this );
((ICustomDoc)Document.DomDocument).SetUIHandler( docHostUIHandler ); }
base.OnDocumentCompleted( e ); }
4.) Be happy :-)
Best regards Uwe (http://www.magerquark.com)
DavidB - 19 Mar 2006 14:16 GMT Thanks, Uwe. I expect that will work. My purpose was to find out whether the .NET 2.0 code could be made to work -- no joy on that so far! DavidB
> Here is my (working) hint: > [quoted text clipped - 40 lines] > Best regards > Uwe (http://www.magerquark.com) Alexander Ogol - 24 Mar 2006 21:14 GMT Hello, DavidB! You wrote on Sun, 19 Mar 2006 13:16:55 GMT:
??>> if ( docHostUIHandler == null ) ??>> { ??>> docHostUIHandler = new MyDocHostUIHandler( this ); ??>> ??>> ((ICustomDoc)Document.DomDocument).SetUIHandler( ??>> docHostUIHandler ); ??>> }
This approach (reassigning UI Handler later) is good for most cases, but there is one issue that SetUIHandler() can be called only after first Navigate(), so: 1. IDocHostUIHandler.GetOptionKeyPath() is not called (method of default WebBrowserSite is already called when initializing WebBrowser), so you can't set for your component to use custom path in registry to read settings and though can't do some customizations without affecting whole system (for example, "Disable script errors" flag can be modified only via this registry setting)
2. First Navigate() goes using WebBrowserSite's IDocHostUIHandler implementation, so if you change look(&feel) of component, you'll receive visual glitches on this first.
BTW, FYI http://lab.msdn.microsoft.com/productfeedback/viewfeedback.aspx?feedbackid=e2405 bec-e366-4081-ac62-ee569032a7cd
that's about IDocHostUIHandler's bug at all
 Signature With best regards, Alexander Ogol. E-mail: alexander@ogol.dp.ua
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|