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.
Related
I get access to the IAudioEndpointVolume interface in the main worker thread of a service like this (error checks omitted):
CoInitialize(NULL);
CoCreateGuid(&g_guidMyContext);
CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, (void**)&m_pEnumerator);
IMMDevice *pEndpoint = NULL;
m_pEnumerator->GetDevice(&deviceID[0], &pEndpoint);
IAudioEndpointVolume *pAudioVol = NULL;
pEndpoint->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL, (void**)&pAudioVol);
CAudioEndpointVolumeCallback *pVolumeCallback = new CAudioEndpointVolumeCallback(pAudioVol, 100, TRUE, m_debugLog, m_logMutex);
The CAudioEndpointVolumeCallback class then stores the IAudioEndpointVolume pointer in a member variable and calls RegisterControlChangeNotify(this) on it in its constructor.
This class may also start a thread to smoothly change the volume from one value to another over a short time period. So at the end I make calls to the IAudioEndpointVolume interface from different threads. In general all of this works as intended, but I am experiencing some strange behavior in some edge cases. When checking the code again I stumbled across the comments about threading in the MSDN documentation (I don't have any prior experience with COM objects) and wondered if what I am doing is correct.
So, is it safe to make calls to the IAudioEndpointVolume interface from different threads with the code above? Do I have to protect those calls with a mutex?
I am a bit confused and am not sure if I really understood the behavior of the COM Threading Models.
CoInitialize(NULL) initializes single threaded apartment (STA) and interface pointers you have there are only [supposed to be] valid on this thread only. You can pass them to another thread through GIT, or by CoMarshalInterThreadInterfaceInStream on this thread and getting a "duplicate" of it back with CoGetInterfaceAndReleaseStream on the target thread, where you are going to use it.
Depending on implementation behind the interface pointer in question you might eventually obtain the same pointer (in which case the whole trick would be equal to simply using the pointer on another thread), however this is not safe in general case.
Another option is to use MTA (as opposed to STA) and then you are allowed to pass pointers directly among all/any MTA threads.
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.
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.
I'm maintaining an application which uses Windows Explorer overlay icons. Occasionally some operations require me to forcibly refresh explorers view for a particular folder. I do so using the following function which uses COM:
void RefreshExplorerView(CString strPath)
{
CComPtr<IShellWindows> pShellWindows;
CoInitialize(NULL);
if(SUCCEEDED(pShellWindows.CoCreateInstance(CLSID_ShellWindows)))
{
IDispatch* pFolder=NULL;
VARIANT variant;
V_VT(&variant) = VT_I4;
for(V_I4(&variant) = 0; pShellWindows->Item(variant, &pFolder) == S_OK; V_I4(&variant)++)
{
CComPtr<IWebBrowserApp> pWebBrowserApp;
if(SUCCEEDED(pFolder->QueryInterface(IID_PPV_ARGS(&pWebBrowserApp))))
{
BSTR LocationURL = NULL;
pWebBrowserApp->get_LocationURL(&LocationURL);
if(LocationURL != NULL && strPath.CompareNoCase(LocationURL) == 0)
{
CComPtr<IServiceProvider> pServiceProvider;
if(SUCCEEDED(pWebBrowserApp->QueryInterface(IID_PPV_ARGS(&pServiceProvider))))
{
CComPtr<IShellBrowser> pShellBrowser;
if(SUCCEEDED(pServiceProvider->QueryInterface(IID_PPV_ARGS(&pShellBrowser))))
{
IShellView* pShellView;
if(SUCCEEDED(pShellBrowser->QueryActiveShellView(&pShellView)))
{
pShellView->Refresh();
pShellView->Release();
}
}
}
}
SysFreeString(LocationURL);
}
pFolder->Release();
pFolder = NULL;
}
}
CoUninitialize();
}
I've noticed that when my program does this refresh regularly it slowly grows in size and UMDH has shown me that I appear to be leaking pFolder and pShellWindow instances every time this runs. I can't work out why on earth this happens since as far as I can tell these are released properly. Can anyone see what I'm missing?
You release pShellWindows after CoUninitialize, which is incorrect.
The rest of interfaces seem to be released fine. Note that you could improve cleanless and readability greatly by using CComQIPtr instead of QueryInterface, and not using raw pointers at all (BSTR, IFoo*) and replace them with smart auto-releasing wrappers.
pFolder might be leaking too, if Item call is successful but returns code other than S_OK. Again, use of CComPtr<IFolder> instead of IFolder* would immediately resolve this problem without even drawing any attention to it.
CoInitialize(NULL);
There's more than one problem with this statement. #Roman explained how you can leak by uninitializing too soon. But this will also go bad in more than one way, the apartment state of a thread is a Really Big Deal in COM:
You are not checking the return value of CoInitialize(). This will blow up the client app that calls this function if it has already called CoInitializeEx() and selected MTA instead of STA. That will make CoInitialize() fail, you cannot change the thread state after it was committed. Your CoUninitialize() call will blow the client app to smithereens, making all of its subsequent COM calls fail.
Selecting STA also requires that you implement the contract for a single threaded apartment. Which states that you never block the thread, you're okay with that. And that you pump a message loop. The message loop is crucial to marshaling calls to the single-threaded apartment. You are not okay with that, nor can you reasonably ensure that this is taken care of in a function like this. Particularly important for the shell interfaces, the vast majority of them are not thread-safe. The consequence of not pumping is deadlock. You may get away with not pumping, it is not a guaranteed deadlock. You'll get a bit of leeway here since these are probably out-of-process interfaces.
Particularly the last requirement can only be met by the code that created the thread that calls this function, only it is in control over what the thread does beyond calling your function. If you cannot get the guarantee that the client app initializes COM correctly then the only truly safe thing to do is to create a thread yourself.
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, ¶ms, 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.