I'm implementing a COM interface to an existing VS2010 C++ MFC-application. Most parts of the COM interface interaction works great, but I am confused of how to trigger COM events from another thread that the one where the COM interface is running / defined. The application is multi-threaded with one main thread running the COM interface and handling GUI changes (thread 1) and one thread to receive incoming messages from a C-library (thread 2).
For certain messages received in thread 2 I want to notify the COM clients by sending a COM event. I have read many threads (Firing COM Event From Another Thread is one of them) and CoMarshalInterThreadInterfaceInStream / CoGetInterfaceAndReleaseStream is mentioned. Using Google I can't seem to find any usage of these methods that makes any sense to me; I just don't understand how to implement these functions and if they really will help me.
Relevant code parts:
TestCOM.idl: (the interface definition)
interface ITestCOM: IDispatch
{
[id(1), helpstring("method Test")] HRESULT Test();
};
dispinterface _ITestCOMEvents
{
properties:
methods:
[id(1), helpstring("event ExecutionOver")] HRESULT TestEvent();
};
coclass TestAppCOM
{
[default] interface ITestCOM;
[default, source] dispinterface _ITestCOMEvents;
};
ITestCOMEvents_CP.h (VS generated class for Connection Points / events)
template<class T>
class CProxy_ITestCOMEvents :
public ATL::IConnectionPointImpl<T, &__uuidof(_ITestCOMEvents)>
{
public:
HRESULT Fire_TestEvent()
{
HRESULT hr = S_OK;
T * pThis = static_cast<T *>(this);
int cConnections = m_vec.GetSize();
for (int iConnection = 0; iConnection < cConnections; iConnection++)
{
pThis->Lock();
CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
pThis->Unlock();
...
TestCOM.h (class implementing the methods and CProxy_ITestCOMEvents class)
class ATL_NO_VTABLE CTestCOM :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CTestCOM, &CLSID_TestCOM>,
public IConnectionPointContainerImpl<CTestCOM>,
public CProxy_ITestCOMEvents<CTestCOM>,
public IDispatchImpl<IMecAppCOM, &IID_ITestCOM, &LIBID_TestLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
static CTestCOM * p_CTestCOM;
CTestCOM()
{
p_CTestCOM = this;
}
Incoming.CPP (a class running on thread 2 that should trigger an event in the following case statement)
case INCOMING_EVENT_1:
// Trigger Fire_TestEvent in thread 1
// CTestCOM::p_CTestCOM->Fire_TestEvent(); trigger event on thread 2
In the code above you can find my current workaround for this problem which is to create a pointer object p_CTestCOM that will allow any class running on thread 1 to trigger the COM events. Thread 2 can access that object but it would trigger it in thread 2, which wouldn't work. To solve this all methods defined in Incoming.CPP could post a message (using PostMessage()) to thread 1 which would use p_CTestCOM to access and send the COM event. This would work, but I am sure there must be a better (and safer) solution that more accurately follows the COM design principles.
I someone could shed some light I would be most grateful!