Handling COM events in C ++ (ATL, MFC or pure C ++) to interact with Java

I'm currently trying to create a C ++ library (DLL file) that interacts with a COM component to make it suitable for use in Java. The idea was that I built a very small C ++ DLL with a class that wraps around a COM component and then exports it using SWIG. I got pretty far using the #import operator:

#import "ComponentName.dll" 

And calling CoInitialize () and instantiating the component (via the IComponentNamePtr class that Visual Studio generated). This worked for all the usual calls to the COM method, which was good.

However, I cannot figure out how to make events work. I see IComponentNameEventsPtr there, which complements the main class "smart pointer", but I could not figure out what to do to make it work.

I tried all of the following to make events work:

  • Pure C ++ - I could not figure out how to do this. I tried to create a new class inherited from the IComponentNameEvents class, creating stubs for all abstract functions and overriding functions, except that the functions are not marked as virtual, so this did not work.
  • MFC - I could not call AfxOleInit correctly. Googling told me that the call failed when calling from the DLL, as it assumes that OLE is already initialized. I was not sure how to fix this. My library crashed every time I tried to instantiate a COM component (I assume that COM was not properly initialized)
  • ATL - I could not understand how to do events in ATL. I could create a class (through the Simple ATL wizard, then the Implementation Interface wizard), but I could not figure out how to use it. I read Using IDispEventImpl on MSDN , but couldn't figure out how to use the class created in this way. Do I need to also use the COM object via ATL (or can I use the classes generated by #import)? How to "attach" an event listener class?
  • I read Event Handling in COM , which uses the event_receiver attribute (part of the new Visual C ++ event model). Initially, I could not figure out how to combine this using a COM component created using the #import operator. Finally, I developed (and it was indicated on the page) that I need to use the "embedded_idl" flag in the #import statement, but this violated other things (I got a bunch of "pending type specifications near" errors in the .tlh file)

Does anyone know how to do this? What is the easiest approach? My background is in C # and PHP, so I don't have much experience using COM in C ++.

TL; DR: What is the easiest way to use COM events in a C ++ DLL?

+8
c ++ visual-studio com
source share
2 answers

I really got this job using a single event model. Some notes from my experience:

Then add

 typedef struct StructName StructName; 

For each structure that throws an error

  • After that, you can initialize COM and instantiate your object. Awful code example:

     IComponentName blah; HRESULT hr = CoInitialize(NULL); if (FAILED(hr)) { MessageBox(NULL, "Failed to initialize COM", "Hi!", 0); throw "Failed to initialize COM"; } try { hr = blah.CreateInstance("Something.Something"); if (FAILED(hr)) { CoUninitialize(); MessageBox(NULL, "Failed to initialize the COM library!!", "Hi!", 0); throw "Failed to initialize the COM library"; } } catch (...) { MessageBox(NULL, "Exception occured when initialising library!", "Error", 0); CoUninitialize(); throw "Exception occured when initialising library!"; } 

After you have a COM object, you can hook up events according to the MSDN article "Handling Events in COM":

 __hook(&IComponentNameEvents::OnWhatever, blah, &EventHandlerClass::OnWhatever); 

Be sure to cancel all events before calling CoUninitialize (), otherwise you will get errors.

+1
source share

Embed the source interface in your code (using any mechanism, including, possibly, generating simple C code using the midl compiler). In your external library (the one you consume). Look at the interface, which looks like this:

  [source] interface IOutGoing; 

After you have implemented it, register it using the Advise object that sends events (unregister using Unadvise )

Here is a snippet that shows typical usage, assuming you have taken the MIDL path (with ATL / MFC you will have to write less code, but know more macros / templates)

 class CSink : public IOutGoing { public: // IUnknown ULONG __stdcall AddRef(); ULONG __stdcall Release(); HRESULT __stdcall QueryInterface(REFIID riid, void** ppv); // IOutGoing HRESULT __stdcall GotMessage(int Message); CSink() : m_cRef(0) { } ~CSink() { } private: long m_cRef; }; IUnknown* pUnknown; CoCreateInstance(CLSID_XXXXXXXXX, NULL, CLSCTX_LOCAL_SERVER, IID_IUnknown, (void**)&pUnknown); IConnectionPointContainer* pConnectionPointContainer; hr = pUnknown->QueryInterface(IID_IConnectionPointContainer, (void**)&pConnectionPointContainer); hr = pConnectionPointContainer->FindConnectionPoint(IID_IOutGoing, &pConnectionPoint); // Instantiate the sink object. CSink* mySink = new CSink; // Give the connectable object a pointer to the sink. DWORD dwCookie; pConnectionPoint->Advise((IUnknown*)mySink, &dwCookie); 
+3
source share

All Articles