Reputation: 927
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
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
Reputation: 1202
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