Yuval
Yuval

Reputation: 927

Make IWebBrowser2 Control safe for scripting

I'm using IWebBrowser2 control in my application to display external web pages. The problem is that the object is not safe for scripting and calls to get_Document fails (with S_FALSE as return value).

I've implemented a new class, IScriptableWebBrowser2 that inherits both from IWebBrowser2 & IObjectSafety, and tried to use it instead of IWebBrowser2 but that didn't do the trick.

How do I make my IWebBrowser2 control safe for scripting ?

class IScriptableWebBrowser2 : 
   public CComObjectRootEx<CComSingleThreadModel>,
   public IWebBrowser2,
   public IObjectSafety
{
BEGIN_COM_MAP(IScriptableWebBrowser2)
   COM_INTERFACE_ENTRY(IObjectSafety)
END_COM_MAP()

    // IObjectSafety implementation
    STDMETHODIMP GetInterfaceSafetyOptions(REFIID riid, 
                                           DWORD *pdwSupportedOptions, 
                                           DWORD *pdwEnabledOptions )
    {
        *pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | 
                               INTERFACESAFE_FOR_UNTRUSTED_DATA;
        *pdwEnabledOptions = *pdwSupportedOptions;
        return S_OK;
    }
    STDMETHODIMP SetInterfaceSafetyOptions(REFIID riid, DWORD dwOptionSetMask, DWORD     dwEnabledOptions)
    {
        return S_OK;
    }
};

Upvotes: 0

Views: 1336

Answers (2)

Yuval
Yuval

Reputation: 927

Well, I finally had some time to come back to this one..

It turns out that get_Document fails if you call it BEFORE the page completely loaded but the return value (S_FALSE) indicates a completely different error ("not safe for scripting")

btw, Loading local pages will give you the desirable behavior.

Therefore, calling get_Document after the page was loaded (DISPID_NAVIGATECOMPLETE2, DISPID_DOWNLOADCOMPLETE, DISPID_DOCUMENTCOMPLETE) will do the trick.

Hope this helps.

Upvotes: 1

I guess you created the browser in a thread and passed it on to another thread.
If that's the case, here's what you should do:

Before passing the IWebBrowser2 instance to another thread, in the creating thread, call CoMarshalInterThreadInterfaceInStream, that will marshal (convert) it to a thread-safe IStream object, and only then pass it to the tagert thread.
Later, in the target thread, you should call CoGetInterfaceAndReleaseStream with the previously marshaled IStream instance, which will unmarshal it back to your original object in the target thread (and release the IStream object along the way).

CoMarshalInterThreadInterfaceInStream in MSDN
CoGetInterfaceAndReleaseStream in MSDN

Hope that helps.

Upvotes: 1

Related Questions