when I marshal ActiveX interface through Global Interface Table (GIT), do I need to call GetInterfaceFromGlobal() from every thread that will use this interface? Alternatively, once one thread gets a pointer to the marshaled interface, that same pointer is good to use from other threads too?
You have to call it from every thread. Each thread gets its own proxy.
In theory you can use one proxy... it may work. But GetInterfaceFromGlobal may also directly return the pure interface if you call it from the creating thread... no proxy needed in this case.
Related
I know that you need synchronize (yourprocedure) to set e.g. a label's text.
But what about:
Reading a label's text.
Toggle/Set the label's enabled property.
Call other labels procedures/functions (e.g. onclick event).
Is there an easy rule to know/remember when I need to use synchronize?
PS.: Is synchronize similar to PostMessage/SendMessage?
Easy rule of thumb: ANY access to VCL UI components needs to be synchronized. That includes both reading and writing of UI control properties. Win32 UIs, most notably dialogs like MessageBox() and TaskDialog(), can be used directly in worker threads without synchronizing.
TThread.Synchronize() is similar to SendMessage() (in fact, it used to be implemented using SendMessage() internally in Delphi 5 and earlier). TThread.Queue() is similar to PostMessage().
Any time you access a VCL UI component, you need to implement some type of thread safety measure. This is also, typically, the case when you're accessing a variable or procedure that exists or will be accessed by another thread. However, you don't need to use the Synchronize method in all of these situations. There are other tools at your disposal, and Synchronize is not always your best solution.
Synchronize blocks both the main thread and the calling thread while it's performing the procedure that you pass to it, so overusing it can detract from the benefits of multi-threading. Synchronize is probably most commonly used for updating your UI, but if you find that you're having to use it really frequently, then it might not be a bad idea to check and see if you can restructure your code. I.E. do you really need to read labels from within your thread? Can you read the label before starting the thread and pass it into the thread's constructor? Can you handle any of these tasks in the thread's OnTerminate event handler?
I am looking into the usage of Global Interface Table.
I understand that when you call GetInterfaceFromGlobal() from another STA thread you get a proxy to the original interface pointer. The proxy is responsible for passing control to the object creating thread.
What if I have only one thread and call GetInterfaceFromGlobal() in this only thread, i.e. the object creating thread, and then use the returned interface pointer (actually a proxy) just like using the original interface pointer? In other words, is the proxy (which is supposed to be used by another thread) usable to the main thread?
And what if I use the Global Interface Table in MTA threads for MTA object? Will it work or corrupt?
Thanks in advance.
You will get your own pointer back since no proxy is necessary.
Hi I am a beginner in COM. I want to test a COM dll in both STA and MTA modes. My first question is: is it possible a COM object supports both STA and MTA?
Now I imagine the STA code snippet below:
// this is the main thread
m_IFoo;
CoInitializeEx(STA); // initialize COM in main thread
CreateInstance(m_IFoo);
m_IFoo->Bar();
CreateThread(ThreadA);
// start ThreadA
// this is secondary thread
ThreadA()
{
CoInitializeEx(STA);
m_IFoo->Buz(); // call m_IFoo's method directly
}
Will this code work? Am I missing any fundamental things? I know the main thread needs a window message loop to let calls from other threads be executed. Do I have to do anything about it?
Now I move on to test MTA. If I merely replace "STA" with "MTA" in the above code, will it work?
Another question is: As a thread with GUI must be STA, I cannot initialize and test MTA in a GUI thread?
Thanks in advance and sorry for me being naive on COM and threading.
Your code is not legal COM, because you are passing a pointer directly from one STA to another, which COM doesn't allow.
In COM, interface pointers have "apartment affinity", they can only be used within an apartment. To pass a pointer from one STA to another, or between STA and MTA, you have to 'marshal' the pointer to a safe representation, which is then unmarshaled by the receiving thread.
The simplest way to do this is using the Global Interface Table; you register the interface with it in one thread and get back a DWORD, which you then use in the other thread to get back a version of the interface that the other thread can use.
If both threads are MTA, you can avoid doing this. While STA are one-per-thread - each STA thread has its own aparment - the MTA is shared by all MTA threads. This means that MTA threads can pass COM pointers between themselves freely. (But they still need to marshal if passing pointers to or from STA threads.)
Generally speaking, you don't change code between STA or MTA, you usually decide this once at the outset. If the thread has UI, then it needs a message loop, and is usually STA. If there's no UI, you may decide to use MTA. But once you make that decision and write your code, it's rare to change to the other later, since picking one or the other has different requirements and assumptions that affect the code; change from STA to MTA or vice versa and you'd have to carefully review the code and see if things like pointer assignments needed to be changed.
Being able to switch from "MTA" to "STA" and consequences of such switch will depend on how the object is registered in system registry. In order for the object to "support" both cases without marshalling it has to have ThreadingModel set to Both.
Please see this great answer - Both means "either Free or Apartment depending on how the caller initializes COM". That's exactly what you want.
As to using the "STA" mode - yes, the tread object belongs to will have to run the message loop by calling GetMessage(), TranslateMesage() and DispatchMessage() in a loop. Anyway the objects methods won't be called directly from the second thread - they will go through the proxy. Please see this very good article for thorough explanation.
My VC++ 2005 Dialog based application initializes a COM object in the dialog class and uses it in the worker thread.
I called CoInitialize(NULL) At the start of the application and the at the start of the worker thread. But when a COM method is called the error "The application called an interface that was marshalled for a different thread" follows.
If I use CoInitializeEx(0,COINIT_MULTITHREADED) then I will get the same error message
Please help me in finding the root cause.
Thanks.
You created two single-threaded apartments by calling CoInitialize(NULL). An interface pointer must be marshaled from one apartment to the other before it is usable. Initializing the worker thread as MTA doesn't solve the problem. The original interface pointer was still created in a single-threaded apartment and is thus not thread-safe. In other words, you cannot call the interface methods directly from a thread. Those calls have to be marshaled to the thread that created the interface. Marshaling the interface pointer sets up the plumbing that makes that possible.
The only time you don't have to marshal is when both threads are MTA. That's almost never possible, your main thread must be STA if it creates any windows. And the COM server would actually have to be thread-safe, they very rarely are. They advertise what they need with the ThreadingModel key in the registry. COM will actually create an STA thread if necessary to find a good home for the server.
You must marshal the pointer with CoMarshalInterThreadInterfaceInStream() to avoid the error. That's a fairly unfriendly function, IGlobalInterfaceTable is easier to use. The COM server also has to support it, you typically need a proxy/stub DLL that takes care of the marshaling. You'll get E_NOINTERFACE if it doesn't.
Also beware the overhead, marshaling a call from the worker thread to the main thread is pretty expensive and subject to how responsive your main thread is. In other words, if you wrote the thread to speed up your program or to avoid blocking the user interface then this won't actually work. It is the 'there is no free lunch' principle.
Probably CoMarshalInterface() and CoUnMarshalInterface() are the simplest way to do this.
Look at http://support.microsoft.com/kb/206076. You can download the code example and find different implementations of your requirements in Client.cpp.
I think one of the ways to access COM objects inside another thread would be to use Global Interface Pointers. After initialization,form the GIT pointer to the thread along with dwCookie value. Then inside the thread reinterpret-cast the pointer as a DWORD and pass it to the GI table to get our COM pointer.
Thanks
I am doing a BHO (extension for IE) that receives events on other thread. When I access the DOM from that other thread, IE crashes. Is it possible to make the DOM accessed from the same thread as the main BHO thread so that it does not crash?
It seems like a general COM multithreading problem, which I don't understand much.
Look into using CoMarshalInterface or CoMarshalInterThreadInterfaceInStream
These will give you a wrapped interface to an STA COM object that is thread safe.
I don't know much about IE extensions, but it sounds like some COM object needs to be marked a Single Threaded Apartment, so that the COM runtime system ensures that it is run on the same thread which called it initially. If you can't alter the other object, you could probably route your calls to the DOM through a separate COM object marked as STA to achieve the same effect. Hope this helps... I know a bit about COM multithreading, but not much about IE extensions.
ah, fun fun fun multithreading with COM.
Gerald's answer looks right if you want to transfer an interface pointer from one thread to another exactly once. I've found that the GIT (global interface table) is a big help for this kind of thing if you're in a multithreaded system... basically you don't keep around interface pointers but rather DWORD cookies used by the GIT to get an appropriately-marshaled interface pointer for whatever thread you are using it. (you have to register the object in question with the GIT first, and unregister it later when you are done or your object is finished)
Be careful though. Performance can become a serious issue.
If you're just playing around to learn about BHOs, you can use the STA to make your ::SetSite() implementing object operate as if it were single threaded (this allows you to let other threads pull your BHO's pointer out of the GlobalInterfaceTable as #JasonS mentions.
If you're doing something that is expected to be part of a product I highly recommend you very carefully reconsider going MTA everywhere you can and handling the concurrency and thread safety issues yourself. In this case you would only need to ensure that the threads inter-operating with your BHO COM object, were themselves, initialized for COM.
For example, if you want to monitor incoming/outgoing data of website looking for things (either dangerous or sensitive) - then you do NOT want to force all of those threads down the throat of an STA object because, using Yahoo as an example, more than 30 requests will launch and your BHO will start locking up IE.