It is possible to exposed managed events written in C# to be exposed and used in a COM object written using c++. not being that familiar with com and atl. Can you please show what would the C++ side of things would look like for the example shown in the MSDN article
http://msdn.microsoft.com/en-us/library/dd8bf0x3.aspx
The VB6 code shown proves that it is doable.
The solution proposed by Zdeslav Vojkovic was almost the complete answer for me, however I ran into stability issues, when implementing the sink in an Outlook add-in. After the first unadvise the system became unstable and could crash at the next advise. The solution for me was to make the sink as a COM object.
For brevity I have only added the ATL side of the solution, as the managed code can be left exactly as Zdeslav Vojkovic proposed.
I followed these steps in Visual Studio 2017:
Create ATL Simple Object
Fill in the sink interface details
In the generated idl add handlers for initialization and shutdown:
Fill in the header file (MyClient.h)
Some of the generated code has been left as "..."
Fill in the C++ code (MyClient.cpp)
Notice that the Advise/Unadvise calls are done differently here.
The easiest way in C++ would be, IMO, to implement an event sink with help of ATL's
IDispEventImpl
andIDispEventSimpleImpl
templates. An explanation with sample project can be found here.There are many online resources about how to do this, e.g. this or this, but here is the list of required steps:
First let's take a look at managed side.
In order to provide events, we must do the following:
IDispatch
-based)ComSourceInterfaces
attribute to bind the event interface to coclassHere are is the managed code:
Now, back to unmanaged side. I will use ATL, as I find it the most effective way to write COM clients, but you can try MFC or do it 'manually'.
The following steps are required:
IDispEventSimpleImpl
(orIDispEventImpl
)Here's the code in an ATL C++ client:
}
Now, we need to define the type info members in the cpp file (i.e. the
someEvent
instance from example above):This can be tricky as type mappings are not always obvious (e.g. a it might be clear that managed
int
maps toVT_I4
, but it is less obvious thatDateTime
maps toVT_DECIMAL
). You need to declare each event you plan to use in the sink map - if you don't need all of them, don't map them.Now you need to connect your sink to the event source:
This is it, more or less. Using
IDispEventImpl
instead ofIDispEventSimpleImpl
results in a bit less code, as you don't need to supply the type info objects which might be the ugliest part. However, it has two drawbacks:If you can use C++/CLI you can just do (source):