Using WebBrowser2 Interface in Multithreaded application.

david_johns and I are working on an application together.  I had more points available so I am repeating his question with more points to hopefully attract an answer:

We are using a WebBrowser2 interface to do some work for us in our application.  We are trying to introduce multithreading allowing the browser to pick up information in the background and let the user continue using the application.

We seem to lose control of the WebBrowser2 (it will no longer navigate or recieve when one thread that was using it exits and another tries to access it.  The browser is still running, but the WebBrowser2 seems to be a corrupt pointer.

500 points for the person who can figure out how to acess the same WebBrowser2 interface inside of a thread different from the one it was created in or somehow store a reference to the browser itself from which we can restore the WebBrowser2 interface before starting to use it in the second thread.  Thanks for your help.

Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

As I pointed out in (that ended up with *no* feedback from your co-worker)

See see;en-us;150777 ("INFO: Descriptions and Workings of OLE Threading Models")

See also;en-us;206076 ("206076 - MARSHAL.EXE: How To Marshal Interfaces Across Apartments")

To elaborate (

"Always Call CoInitialize(Ex)
A few months ago, I received an e-mail message from a friend at a prominent hardware company. His company had written a fairly sophisticated COM-based application that employed a number of in-proc and local (out-of-process) COM components. At startup, the application created COM objects to serve various client threads running in multithreaded apartments (MTAs). The objects were also consigned to MTAs, which meant that interface pointers could be freely exchanged among client threads. In testing, my friend discovered that everything worked fine until the application was ready to shut down. Then, for no apparent reason, calls to Release (calls that had to be made in order to properly free the interface pointers that the clients were holding) were locking up. His question: "What on earth is going wrong?"
The answer, as it turned out, was quite simple. The application's developers had done everything right with one very important exception: they weren't calling CoInitialize or CoInitializeEx in all of their client threads. One of the fundamental rules of modern-day COM is that every thread that uses COM should first initialize COM by calling either CoInitialize or CoInitializeEx. There are no exemptions to this rule. Among other things, CoInitialize(Ex) places a thread inside an apartment and initializes important per-thread state information that is required for COM to operate properly. Failure to call CoInitialize(Ex) typically manifests itself early in the application's lifetime in the form of failed COM API functions, most commonly activation requests. But sometimes the problems are more insidious and don't manifest themselves until it's too late, as in the case of calls to Release that disappear and never return. Once the dev team added CoInitialize(Ex) calls to all the threads that touched COM, their problems went away.
Ironically, Microsoft is one of the reasons that COM programmers sometimes don't call CoInitialize(Ex). The Microsoft® Knowledge Base contains documents stating that calls to CoInitialize(Ex) aren't strictly necessary for MTA-based threads (see article Q150777 for an example). Yes, there are cases in which you can get away with skipping CoInitialize(Ex). No, you shouldn't do it unless you know what you're doing and can be absolutely sure that you'll suffer no debilitating effects. It's never harmful to call CoInitialize(Ex), so my advice to COM programmers is to always call it from any thread that does anything whatsoever with COM.

Don't Pass Raw Interface Pointers Between Threads
One of the first COM projects I ever consulted on involved a distributed application comprising about 100,000 lines of code, written by a large software company on the West Coast. The application created dozens of COM objects on various machines and called into those objects from background threads launched by client processes. The development team was stymied by calls that would disappear into never-never land or simply fail for no obvious reason. One of the most egregious symptoms that they demonstrated for me was that following a call that failed to return, starting other COM-enabled applications (including Microsoft Paint, of all things) on the same machine would frequently induce those applications to lock up too.
An examination of their code revealed that they had broken one of the fundamental laws of COM concurrency, which says that if one thread wants to share an interface pointer with another thread, it should first marshal the interface pointer. Marshaling an interface pointer enables COM to create a new proxy if necessary (and a new channel object, pairing the proxy with a stub) to permit callouts from another apartment. Passing a raw interface pointer (a 32-bit address in memory) to another thread without marshaling it bypasses COM's concurrency mechanism, and can produce all sorts of undesirable behavior if the sending and receiving threads reside in different apartments. (In Windows® 2000, because two objects can share an apartment but reside in different contexts, it can even get you in trouble if the threads are in the same apartment.) A typical symptom involves calls that fail and return RPC_E_WRONG_THREAD_ERROR.
Windows NT® 4.0 and higher make it easy to marshal interface pointers between threads with a pair of API functions named CoMarshalInterThreadInterfaceInStream and CoGetInterfaceAndReleaseStream. Let's say one thread in your application (thread A) has created a COM object and received an IFoo interface pointer in return, and that another thread in the same process (thread B) wants to place calls to that object. In preparation for passing the interface pointer to thread B, thread A should marshal the interface pointer like this:

CoMarshalInterThreadInterfaceInStream (IID_IFoo, pFoo, &pStream);

Once CoMarshalInterThreadInterfaceInStream has returned, thread B can safely unmarshal the interface pointer:

IFoo* pFoo;
CoGetInterfaceAndReleaseStream (pStream, IID_IFoo, (void**) &pFoo);"

>>so I am repeating his question with more points to hopefully attract an answer

Rule of thub: Provide feedback. Don't abandon questions.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
stringsandbeyondAuthor Commented:

Wow!  Thanks for all the great info.  Just one more question before I close this out.  As David mentioned we have developed a class that attempts to make the process of using the browser really easy.  As of yet the class does not have any knowledge about the thread that creates it and the one that is operating it.

I am guessing that the best way to handle it is to create the browser instance in the first thread that needs it and go ahead and call CoMarshalInterThreadInterfaceInStream() in the Open() routine.  Then make an Initialize() function that calls CoIntializeEx() and CoGetInterfaceAndReleaseStream() to get control of the WebBrowser2.  Then make an UnInitialize() function that calls CoUnitialize() and CoMarshalInterThreadInterfaceInStream() again to pass the WebBrowser2 back into the next thread that needs it.  Does this approach seem reasonable?  Will the method crash if the thread that calls CoMarshalInterThreadInterfaceInStream() exits before the interface is passed into the next thread that uses it?

Thanks so much for your help.
>>Does this approach seem reasonable?

Hum, there is no need to multiply call 'CoInitializeEx()' - just do that once when your application starts up or creates a thread (then you need to call it agin in the new thread). Also, there is no need to pass the WebBrowser2 'back' again, once it is marshalled across the thread boundaries, both threads can use it. Just be sure to release the interface in both threads, so the proxy (if any) can be released by the marshaling layer.

>>Will the method crash if the thread that calls CoMarshalInterThreadInterfaceInStream()
>>exits before the interface is passed into the next thread that uses it?

I'd create the interface in the applications main thread and pass it to the others when they 'need' it.

BTW, if you want to avoid all the marshalling hassle, take a look at ("IGlobalInterfaceTable"), which provides aninterface is an efficient way for a process to store an interface pointer in a memory location that can be accessed from multiple apartments within the process, such as processwide variables and agile (free-threaded marshaled) objects containing interface pointers to other objects (last half of the sentence shamelessly stolen from that page :o)

BTW, on the last issue, see also ("Creating the Global Interface Table") ("When to Use the Global Interface Table") ("ActiveX Q&A, MSJ September, 1997 - Apartment Neutrality: The Free Threaded Marshaler and the Global Interface Table")
stringsandbeyondAuthor Commented:

You're the best!  Thanks again.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today

From novice to tech pro — start learning today.