Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IServiceProvider IElementBehaviorFactory not queried until an unhandled JavaScript error is thrown

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 the IElementBehaviorFactory interface, and requests the host for the IHostBehaviorInit interface. If the IHostBehaviorInit interface is available, MSHTML calls the IHostBehaviorInit::PopulateNamespaceTable method. The host application can then query MSHTML for the IElementNamespaceTable interface and use the IElementNamespaceTable::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?

like image 639
Andy E Avatar asked Nov 01 '22 04:11

Andy E


1 Answers

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.

like image 67
noseratio Avatar answered Nov 15 '22 04:11

noseratio