1

I have a BHO(Internet Explorer extension) and I'm trying to set a "data:image/png;base64, [code]" (base64 encoded image buffer) as the src of an IHTMLImgElement. When put_src was called from the main thread of the BHO, there was no problem, but now that I call it from a different thread, it returns E_OUTOFMEMORY. The base64 encoded string is very long. For a shorter base64 string it returns no error.

I have to specify that I have no memory leaks, I used only smart COM pointers, and deleted all allocated memory.

Also I use the same type of base64 string to call set_backgroundImage for IHTMLStyle objects and it returns no error.

  • MSHTML Document object and its DOM API is *not* thread-safe. It must be called on the same and only thread where it was created, which is the same thread where you BHO gets created. – noseratio Mar 03 '14 at 11:23
  • thank you for your answer. What does it specifically mean "not thread safe"? As I wrote in the main post the call to set_backgroundImage returns with no problem. – evilwhaleboy Mar 03 '14 at 12:51
  • I used the GIT (Global interface table) to marshal and unmarshal the IWebBrowser2 object, so, from what I understand it should work just fine – evilwhaleboy Mar 03 '14 at 14:06

2 Answers2

1

What does it specifically mean "not thread safe"? As I wrote in the main post the call to set_backgroundImage returns with no problem.

In this context, it simply means you cannot call it directly from any other thread but the main thread, where your BHO was created. If you need to use it from another thread, marshal the object's IHTMLImgElement interface to that thread, e.g. with CoMarshalInterThreadInterfaceInStream.

More info:

noseratio
  • 59,932
  • 34
  • 208
  • 486
  • I used the GIT (Global interface table) to marshal and unmarshal the IWebBrowser2 object. – evilwhaleboy Mar 03 '14 at 14:51
  • @evilwhaleboy, show the code you use to marshal WebBrowser/MSHTML COM objects via GIT. – noseratio Mar 03 '14 at 22:01
  • `HRESULT hr = CoCreateInstance(CLSID_StdGlobalInterfaceTable, 0, CLSCTX_INPROC_SERVER, IID_IGlobalInterfaceTable, (void**)&pGIT); HRESULT hr = this->pGIT- >RegisterInterfaceInGlobal(_pSite, IID_IWebBrowser2, &this->dwCookie); CComPtr pSiteObj; hr = this->pGIT->GetInterfaceFromGlobal(this->dwCookie, IID_IWebBrowser2, (void**)&pSiteObj);` – evilwhaleboy Mar 04 '14 at 06:12
  • @evilwhaleboy, this looks all right. By chance, do you cache any COM pointers across threads, like a pointer to `IHTMLDocument2`? – noseratio Mar 04 '14 at 07:10
  • sorry for the maybe dumb question, but what does caching a pointer across threads mean? – evilwhaleboy Mar 04 '14 at 07:26
  • It means you might save a pointer to a COM interface on one thread (in a member or static variable), then use it on the other thread, without marshaling. – noseratio Mar 04 '14 at 07:29
  • I didn't do such thing. – evilwhaleboy Mar 04 '14 at 07:32
  • My guess is that the error E_OUTOFMEMORY has to do with the string being very long ~75000 characters. But I don't understand why it works when it is called from the main thread, and it doesn't in the worker thread – evilwhaleboy Mar 04 '14 at 07:54
  • @evilwhaleboy, you may want to try to marshal this call (and the data) to the main thread via your own custom interface on your BHO, and then call MSHTML on the main thread directly. – noseratio Mar 04 '14 at 10:17
  • I don't think I know what you mean, I need to do the work in a thread, how can I call the method in the main thread? – evilwhaleboy Mar 04 '14 at 14:02
  • @evilwhaleboy, following the sample from the [first](http://support.microsoft.com/kb/206076) link in my answer. It contains `TSTMARSH` which implements `ITest` interface and shows how to call it from another thread. Do the same with your BHO. – noseratio Mar 05 '14 at 10:52
1

If the IWebBrowser2 object is marshaled to another thread the string passed to put_src method must be a BSTR allocated with SysAllocString, not a simple LPWSTR. I got the answer from another forum.