Firing a COM Event From Another Thread - c++

I have created an in-process COM object (DLL) using ATL. Note that this is an object and not a control (so has no window or user-interface.) My problem is that I am trying to fire an event from a second thread and I am getting a 'Catastrophic failure' (0x8000FFFF). If I fire the event from my main thread, then I don't get the error. The second thread is calling CoInitializeEx but this makes no difference. I am using the Apartment threading model but switching to Free Threaded doesn't help.
The fact I am trying to do this from a second thread is obviously crucial. Is there an easy way to do this or am I going to have to implement some hidden-window form of messaging?
For example, in my main object's source file:
STDMETHODIMP MyObject::SomeMethod(...)
{
CreateThread(NULL, 0, ThreadProc, this, 0, NULL);
// Succeeds with S_OK
FireEvent(L"Hello, world!");
return S_OK;
}
DWORD WINAPI ThreadProc(LPVOID param)
{
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
MyObject* comObject = reinterpret_cast<MyObject*>(param);
// Fails with 0x8000FFFF
comObject->FireEvent(L"Hello, world!");
}
void MyObject::FireEvent(BSTR str)
{
...
// Returns 0x8000FFFF if called from ThreadProc
// Returns S_OK if called from SomeMethod
pConnection->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);
}

COM basics
In STA your object lives on a single thread (The Thread). This thread is the one it's created on, it's methods are executed on and it's events are fire on. The STA makes sure that no two methods of your object are executed simultaneously (because they have to be executed on The Thread so this is a nice consequence).
This does not mean that your object can't be accessed from other threads. This is done by creating proxies of your object for every thread other than The Thread. On The Thread you pack an IUnknown with CoMarshalInterThreadInterfaceInStream and on the other thread you unpack with CoGetInterfaceAndReleaseStream which actually creates the proxy on the other thread. This proxy uses the message pump to sync calls to you object, calls that are still executed on The Thread, so The Thread has to be free (not busy) to executed a call from another thread.
In your case you want your object to be able to execute methods on one thread and rise events on another thread. So this has to happen in MTA, so your object has to live in MTA, so your class has to be free-threaded. Threads belong to exactly one apartment, so a thread can not be in MTA and STA simultaneously. If your object lives in MTA whenever an STA object tries to use it, it will have to create a proxy. So you get a slight overhead.
What I guess is that you are thinking of some very clever "technique" to offload your main thread, and do some "async" events, which will not fly in the end :-)) If you think about it there has to a listener on this second [worker] thread...
Btw, this line
MyObject* comObject = reinterpret_cast<MyObject*>(param);
can be done in MTA only.

I think the real problem is not what your component is configured with, but the host process. Many hosts, like the Office Object Model ones, live in a single threaded apartment in which case it is not allowed to call them from anything but the main thread.
If that is the case you can let COM do the work by using the single threaded apartment model and moving the actual call to a function in a CoClass and invoke that function from your thread.
That only passes window messages behind the scenes as well, but spares you from implementing this yourself.
Threading in COM (wikipedia):
The Single-Threaded Apartment (STA) model is a very commonly used model. Here, a COM object stands in a position similar to a desktop application's user interface. In an STA model, a single thread is dedicated to drive an object's methods, i.e. a single thread is always used to execute the methods of the object. In such an arrangement, method calls from threads outside of the apartment are marshalled and automatically queued by the system (via a standard Windows message queue). Thus, there is no worry about race conditions or lack of synchronicity because each method call of an object is always executed to completion before another is invoked.
See also Message Pumping in the same article.

Related

Will COM marshalling be (ever) neccessary for an object with ThreadingModel Both?

This is triggered by another question.
Specifically, I have a in process COM class, that is defined in the CLSID registry as having a ThreadingModel of Both.
Our process activates this object through CoCreateInstance (not CoCreateInstanceEx, if that even matters for an in-proc dll server)
Given a threading model of Bothand given th rules listed in the docs:
Threading model of server | Apartment server is run in
------------------------------------------------------
Both | Same apartment as client
and given what Hans writes in the other answer:
... Marshaling occurs when the client call needs to be made on a
different thread. ... can happen when the ThreadingModel specified in
the comClass element demands it. In other words, when the COM object
was created on one thread but is called on another and the server is
not thread-safe.
my tentative conclusion would be that such an object will never need implicit marshalling of calls to its interfaces, since the object will always live in the same apartment as its client.
Is that correct, even if the client process is running as STA?
Yes, there may be marshaling.
If the client of your COM class is running in an STA and you attempt to invoke your class from another apartment, it will have to marshal to the apartment that it was created in.
The COM terminology can be really confusing. When you refer to a 'client' in this case, you're really referring to a thread, not the entire application (as it would imply).
Both just means that the threading model of the server conforms to the client that instantiates it. That is, when you instantiate your class, it takes on the threading model of the thread it was created on. Since you're instantiating the server in an STA, your server will use STA, meaning it can only be invoked on the thread that created it; if another thread tries to invoke it, it will marshal to the thread it was created on.
I can't help myself posting this, although it is not a direct answer to the question.
There's a brilliant MSKB article from the golden ages of COM: INFO: Descriptions and Workings of OLE Threading Models. Still there, and has all the relevant info. The point is, you should not worry about whether there is marshaling or not, if you follow the rules. Just register your object as ThreadingModel=Both, aggregate the Free-Threaded Marshaler with CoCreateFreeThreadedMarshaler, and be done. COM will do the marshaling if needed, in the best possible way. Depending on the client's apartment model, the client code may receive the direct pointer to your interface, if it follows the rules too.
Any "alien" interface that you may receive when a method of your interface gets called, will be valid in the scope of the call, because you stay on the same thread. If you don't need to store it, that's all that matters.
If however you do need to cache the "alien" interface, the right way of doing this would be to store it using CoMarshalInterThreadInterfaceInStream/CoGetInterfaceAndReleaseStream:
To store it:
Enter critical section;
call CoMarshalInterThreadInterfaceInStream and store the IStream pointer in a member field;
Leave critical section;
To retrieve it
Enter critical section;
call CoGetInterfaceAndReleaseStream to retrieve the interface
call CoMarshalInterThreadInterfaceInStream and store it again as IStream for any future use
Leave critical section;
Use the interface in the scope of the current call
To release it:
When you no longer need keeping it, just release the stored IStream (inside the critical section).
If the "alien" object is free-threaded too, and the things are happening inside the same process, you will likely be dealing with a direct interface pointer after CoGetInterfaceAndReleaseStream. However, you should not make any assumptions, and you really don't need to know if the object your dealing with is the original object or a COM marshaller proxy.
This can be slightly optimized by using CoMarshalInterface w/ MSHLFLAGS_TABLESTRONG / CoUnmarshalInterface / IStream::Seek(0, 0) / CoReleaseMarshalData instead of CoGetInterfaceAndReleaseStream/CoGetInterfaceAndReleaseStream, to unmarshal the same interface as many times as needed without releasing the stream.
More complex (and possibly more efficient) caching scenarios are possible, involving Thread Local Storage. However, I believe that would be an overkill. I did not do any timing, but I think the overhead of CoMarshalInterThreadInterfaceInStream/CoGetInterfaceAndReleaseStreamis really low.
That said, if you need to maintain a state that stores any resources or objects which may require thread affinity, other than aforementioned COM interfaces, you should not mark your object as ThreadingModel=Both or aggregate the FTM.
Yes, marshalling is still possible. A couple of examples:
the object is instantiated from an MTA thread and so placed into an MTA apartment and then its pointer is passed into any STA thread and that STA thread calls methods of the object. In this case an STA thread can only access the object via marshalling.
the object is instantiated from an STA thread and so placed into an STA apartment belonging to that thread and then its pointer is passed into another STA thread or an MTA thread. In both cases those threads can only access the object via marshalling.
In fact you can expect no marshalling only in the following two cases:
the object is instantiated from an MTA thread and then only accessed by MTA threads - both the one that instantiated the object and all other MTA threads of the same process.
the object is instantiated from an STA thread and then only accessed by that very thread
and in all other cases marshalling will kick in.
ThreadingModel = Both simply means that the COM server author can give a guarantee that his code is thread-safe but cannot give the same guarantee that other code he didn't write will be called in a thread-safe way. The most common case of getting such foreign code to execute is through callbacks, connection points being the most common example (usually called "events" in client runtimes).
So if the server instance was created in an STA then the client programmer is going to expect the events to run on that same thread. Even if a server method that fires such an event was called from another thread. That requires that call to be marshaled.

Initialization and instantiation of COM objects in multithreading client

I'm writing plugin for one software. This software invokes
void Init() {...}
on loading and have multithreading feature: program can run multiple threads and can call custom functions from my plugin at the same time.
In my plugin I'm using COM objects which I initialize following way:
void Init() { // "Global" initializaton
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
position.CreateInstance(__uuidof(Position));
order.CreateInstance(__uuidof(Order));
}
And next I implement plugin-based function (example):
int SendOrder(....) {
return order.SendOrder(...); // invoke COM object's method
}
Problem is that this variant not working as expected so I moved COM object instantiation directly to the function's body:
int SendOrder(....) {
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
order.CreateInstance(__uuidof(Order));
int ret = order.SendOrder(...);
CoUnitialize();
return ret;
}
Now COM object will be instantiated on every function call and this variant works as expected (every thread now have it's own apartment and object's instance), but I'm afraid that is not the best solution, because instantiation is costly operation.
Can this be done somehow better?
If you want to be able to invoke COM objects at the same time on multiple threads, you should be initializing the the thread to use a multi-threaded apartment, instead of single-threaded apartment.
Currently, you're initializing the thread as a single-threaded apartment, which means that any objects created on that thread will only execute their functions on that thread. If you attempt to use one of these objects from a different thread, the calls will be marshaled to the thread that created them.
If COM needs to marshal a function call to another thread, it does it via Windows's messaging system. If the thread isn't pumping it's messages, the function will never be called; this is most likely what's happening to you, and why you're seeing that nothing gets executed.
If you initialize your thread as a multi-threaded apartment by using COINIT_MULTITHREADED instead of COINIT_APARTMENTTHREADED when you call CoInitializeEx, it will allow objects created by this thread (i.e. your order) to be used on any other thread.

Calling CoInitialize/CoUnInitialize

i have a .NET application which is using a COM component using COM Interop, The Component instanciate itself and interface pointer is returned in an API cal to the .net wrapper, at a later point in the application flow a call is made to the COM component.
//Pseudo code
//CLISD_ITEM is a another CoClass housed by this COM component, the component is a STA based dll
HRESULT GetItem(ITem **ptr)
{
HRESULT hr = CoCreateInstance(CLSID_ITEM.....,....(void **) &pItem);
pItem->QI(ptr);
}
my question is should i call CoInitialize and CoUninitialize() inside the function GetItem, as of now i not making these calls and the code seems to be working fine, but there are reports of some intermittent crash when calling CoCreateInstance.
if anyone can help me here.
No, CoInitializeEx() must always be called by the owner of the thread. Which is never the component itself, it didn't start the thread. Only the owner can determine which apartment type is correct since it needs to take care of apartment guarantees. In particular, an STA thread must pump a message loop. A component can never provide that guarantee.
And this is done consistently in a .NET app, the CLR always calls CoInitializeEx() before it allows any managed code to run on the thread. The apartment type is selected by the [STAThread] or [MTAThread] on the Main() entrypoint for the startup thread, the Thread.SetApartmentState() call for a worker thread. Threadpool threads always join the MTA.
You'll need to look for another reason for the crash.
Provided you're using this from a thread marked STA with SetApartmentState within .NET, you shouldn't need to do this.
If you're calling this directly on a UI thread (ie: the main Windows Forms or WPF thread) this will be done for you already.

Multithreaded C++ application using Matlab Engine

I open Matlab engine in an initialization thread, doing :
bool MY_MATLAB_ENGINE_o::Open()
{
// Handle the case where engine is already open
if( MatlabEngine )
{
return true;
}
else if( !( MatlabEngine = engOpen( 0 ) ) )
{
return false;
}
IsEngineOpen.SetValue( true );
return true;
}
Function engOpen() opens a COM channel to Matlab.
Once the engine is open, the thread falls in wait event mode.
Then, in another thread, I do this :
bool MY_MATLAB_ENGINE_o::ChangeDirectory( QString strPath )
{
QString strPathToScript = "cd('" + strPath + "');";
QByteArray ba = strPathToScript.toLatin1();
const char* cPathToScript = ba.data();
if( MatlabEngine )
{
engEvalString( MatlabEngine, cPathToScript );
return true;
}
return false;
}
I get a CoInitialize has not been called first-chance exception on engEvalString( MatlabEngine, cPathToScript ); which seems to tell me that Matlab COM server isn't available (but Matlab engine is still up and running).
When I put everything in the same thread it works fine though, but that's not the kind of design I had in mind.
I find Matlab engine documentation lack information about engine+COM. Any idea how to have engine initialization and function calls in separated threads ?
Thanks !
EDIT following RobH's answer
I added this method to my class (instantiated in the second thread) :
bool MY_MATLAB_FUNCTION_CALL_o::PostThreadCreationHook()
{
HRESULT hr;
hr = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hr))
{
return false;
}
return true;
}
And now when I call engEvalString( MatlabEngine, cPathToScript ); I get The application called an interface that was marshalled for a different thread first-chance exception :) I have so much fun this morning ! :)
So, CoMarshalInterface() ?
CoInitialize has to be called from every thread where you use a COM object, not just the main thread.
It has been a decade since I last automated Matlab, so excuse rustiness in what follows. That you have received the CoInitialize error suggests that the engOpen call wraps underlying COM calls. Unfortunately, this exposes you unawares to the can of worms that is COM. I guess you are right and that engOpen includes a call to CoInitialize, which initialises the COM library on the current thread. To access COM objects from a thread CoInitialize must always have been called on that thread before any calls to COM (other than one permitted COM function, I forget which.)
My advice is to isolate all of your Matlab calls onto one thread now. If you do that you won't have to make the explicit CoInitialize call, and you avoid any later multithreaded COM issues. You might get your program working today by calling CoInitialize on the second thread but one day you'll be bitten by another COM problem.
[I spent about a decade elbows-deep on COM and it is full of bear traps. You could spend a few weeks reading up on a technology which Microsoft tried to hide / kill with .Net, but it is better just to take the easy (single-thread) path now and forget about it.]
Update
I'm afraid your edit has tripped you into the mire of COM threading models. COINIT_MULTITHREADED effectively tells COM that you're going to take care of all of the little nuances of threading, which is almost certainly not what you want to do. COM operates with several (last time I paid attention it was three) threading models and the parameter you pass to CoInitializeEx declares which of those models you wish to use.
Apologies to all if what follows is slightly off.
If you specify COINIT_MULTITHREADED you need to either know that the COM object you are calling is thread-safe or do the appropriate locking (and marshalling of interfaces and data between threads) yourself.
COINIT_APARTMENTTHREADED, which is probably what engOpen uses as in my experience it's the most common, lets the COM library deal with multithreading for you. The library may, for instance, create proxy and stub objects to mediate calls across threads (or process boundaries, which is what will happen when you call to Matlab.)
engOpen created a Matlab proxy object on your main thread. This proxy object can be called from the thread where it was created and, if I recall correctly, from any other thread in the 'apartment' (where CoInitializeEx has been called with COINIT_APARTMENTTHREADED.) You have tried to call through the proxy from a thread in a different threading model, the COM library has noticed, and has issued the error you mention.
In many ways COM is amazing, but the intricacies are a pain in the arse. Be thankful you are never likely to have to use Distributed COM, which is truly nasty!
Update 2
My ancient memory of COM threading models is wrong. This MSDN page states that there is one thread per apartment with COINIT_APARTMENTTHREADED. COM objects can be accessed using the same interface pointer from all threads in the apartment where they were created. For COINIT_APARTMENTTHREADED that means just the thread where the object was created. In COINIT_MULTITHREADED that would be all the threads in the multithreaded apartment but (1) you don't get to choose which thread the Matlab engine is created on if you use engOpen and (2) trying to call a COM object that you didn't write from a multithreaded apartment is risky. The original OLE threading model only allowed COM calls from the main GUI thread, BTW.

CoInitializeEx returning S_OK when called inside a COM object

Some time ago, I had to modify an old COM DLL (Visual C++ 2010, ATL) migrating it from "Apartment" threading model to "Both", i.e. it can now be called from both STA and MTA threads without serializing calls (of course, I had to add internal synchronization for shared data). This in turn caused problems when translating COM events (connection points) to .NET events when my DLL is called via Interop from a .NET application (I must support both STA and MTA even in .NET applications).
To tackle these problems, I changed the way events are fired.
1) If the DLL is called in a STA context, it works like before, i.e. it creates an invisible window, then, when the event must be raised, it calls PostMessage to that window, then the main STA thread calls the actual event-firing code, i.e. CProxy_IMyEventFiringInterface member functions (CProxy_IMyEventFiringInterface derives from IConnectionPointImpl).
2) if the DLL is called in a MTA context, I don't have a main COM thread and I cannot do PostMessage, so I use a custom thread I create and let that thread call IConnectionPointImpl functions.
But AFAIK there is no Windows API that detects if the calling thread is STA or MTA. Many websites suggest to use CoInitializeEx like this:
HRESULT hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
switch(hr)
{
case S_FALSE: // we are in a Multi-Threaded Apartment (MTA)
CoUninitialize(); // each successful call to CoInitialize or CoInitializeEx, including any call that returns S_FALSE, must be balanced by a corresponding call to CoUninitialize
break;
case RPC_E_CHANGED_MODE: // we are in a Single-Threaded Apartment (STA)
break;
default: // IMPOSSIBLE!!!!
}
I decided to put this call to CoInitializeEx in CMyComComponent::FinalConstruct.
Everything worked fine... till today. In a customer scenario, I see from my tracing tool that for a certain .NET EXE application (I do not have the source code) the above code ends up in the default branch because CoInitializeEx returned S_OK.
How can this be possible? Microsoft documentation says that S_OK means "The COM library was initialized successfully on this thread", but I am INSIDE a COM object, the COM library MUST be already initalized!
By the way, the default branch does not shut down the application, but, since S_OK was returned, it called CoUninitialize (each successful call to CoInitialize or CoInitializeEx, including any call that returns S_FALSE, must be balanced by a corresponding call to CoUninitialize) and then the DLL goes on assuming STA (a wrong move in hindsight). But it's not STA: in fact, a later PostMessage returns FALSE.
I can simply change the code to use MTA as the default if CoInitializeEx(NULL, COINIT_MULTITHREADED) returns S_OK, I should have done it right from the start.
But I also want to be SURE that this is the right thing to do, to avoid further problems in the future.
Thank you very much
Demetrio
This is possible when you are on implicit MTA thread. The correct function is like this:
BOOL IsMultiThreadedApartment() throw()
{
HRESULT nResult = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if(SUCCEEDED(nResult))
CoUninitialize();
return SUCCEEDED(nResult);
}
You are hitting this unusual situation because the caller application failed to initialize COM on the thread it instantiates your class on. However be aware that if later the caller initializes the thread as STA, you might get into tricky situation having your class running in MTA mode on STA thread. Doing CoInitializeEx yourself on the other hand might cause failure of the caller to do erroneously late COM initialization.