I'm providing a custom namespace and binary behaviour to a .net WebBrowser control, and it works just fine under specific circumstances. Using the following code, the breakpoints (marked with ●
) all hit and my namespace is properly implemented complete with the behaviour:
int IServiceProvider.QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject)
{
int hr = Native.E_NOINTERFACE;
ppvObject = IntPtr.Zero;
if (riid == IidClsid.IID_IElementBehaviorFactory)
{
// Returning S_OK tells the html host to query for our IHostBehaviorInit.
● hr = Native.S_OK;
}
else if (riid == IidClsid.IID_IHostBehaviorInit)
{
ppvObject = Marshal.GetComInterfaceForObject(this, typeof(IHostBehaviorInit));
● hr = Native.S_OK;
}
else if (guidService == IidClsid.IID_IInternetSecurityManager)
{
ppvObject = Marshal.GetComInterfaceForObject(this, typeof(IInternetSecurityManager));
● hr = Native.S_OK;
}
return hr;
}
However, the first and second breakpoint only hit because of a script error in the test page. If I fix the error or suppress errors, the breakpoints never hit. For example, the following code prevents my namespace and behaviour from ever being registered:
WebBrowser.Document.Window.Error += OnWebBrowserDocumentWindowError;
public void OnWebBrowserDocumentWindowError (object sender, IHTMLEventObj e)
{
e.Handled = true;
}
This is what the MSDN documentation for IHostBehaviorInit says:
MSHTML calls the host application's
IServiceProvider::QueryService
to request theIElementBehaviorFactory
interface, and requests the host for theIHostBehaviorInit
interface. If theIHostBehaviorInit
interface is available, MSHTML calls theIHostBehaviorInit::PopulateNamespaceTable
method. The host application can then query MSHTML for theIElementNamespaceTable
interface and use theIElementNamespaceTable::AddNamespace
method to append additional namespaces to the namespace table.
I've noticed that, if I click on a <select>
to open the drop-down list, the first and second breakpoints hit all of a sudden. It's really strange behaviour, can anyone help me figure this out?
This may not answer the question directly, but it's too lengthy for a simple comment.
Why do you compare riid
rather than guidService
in the first two cases? Looks like a bug to me, use guidService
instead.
Further, once you've determined the service being requested, you should not be using Marshal.GetComInterfaceForObject
, because riid
and guidService
may differ. Instead, use Marshal.GetIUnknownForObject
and Marshal.QueryInterface
:
IntPtr unk = Marshal.GetIUnknownForObject(this);
try
{
return Marshal.QueryInterface(unk, ref riid, out ppvObject);
}
finally
{
Marshal.Release(unk);
}
Also, the way you implement your IServiceProvider
may affect how MSHTML picks it up. I suggest you use IProfferService
for this. I have a full-fledged example of how to use IProfferService
with WebBrowser
here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With