Introduction
If you have to write interop code, should you use C# and P/Invoke, or should you use C++/CLI? The clients for a COM connection point server can be written in C++ and in C# managed code.
Recently, I got a query about the possibility of a managed C++/CLI client for a COM connection point server. A search on the web gave
many samples of C++ and C# managed code but none for a C++/CLI client. It is a topic of debate; refer to this
blog. It says “With C++/CLI, you can use the API
natively exactly like it's meant to be used, and then "expose" the code to the managed world via C++/CLI”. This motivated me to write an article
on how to implement a COM connection point callback for a C++/CLI client.
COM Server with a Connection Point
To start, I needed a COM server with a connection point. In my scenario, the server exposes a COM method:
HRESULT Add(int nFirst, int nSecond)
The server also defines ConnectionPointContainer
and connection points so that clients can register with it. In addition, the server
defines an interface, _IAddEvents
, which has two methods in it:
HRESULT AdditionCompleted(int nResult)
HRESULT AdditionStarted()
You should have a server interface IAdd
that can be called from the client. If you build the server, you will notice that there are
two interfaces defined here. One is IAdd
, which implements IDispatch
, and the other is the dispinterface _IAddEvents
.
The client provides the implementation for _IAddEvents
and invokes the Add
method on the server. The server fires the AdditionStarted
and AdditionCompleted
methods on the client to notify it appropriately. Then the client performs the appropriate actions associated with these events.
ATLConnectionPointServer.idl should add methods AdditionStarted
and AdditionCompleted
to the _IAddEvents
interface, as shown in figure:
Implement the Add
method on the server and the trigger points for firing events from the server.
Now just compile the solution and your server is ready.
C++/CLI Client
Create a new project Visual C++ => CLR => CLR Console Application.
Import the server DLL to managed code to obtain ATLConnectionPointServerLib.dll by using the Microsoft® .NET Framework Type
Library to Assembly Converter tool, tlbimp.exe, running the following command:
tlbimp ATLConnectionPointServer.dll
Reference the resulting assembly in your managed project, as shown in the figure below:
Provide an implementation for the sink interface on the client, such as the one shown here:
You have to register the sink with the server so the server can invoke the sink when firing the events. With the managed client, you
register individual methods as delegates with the server. To accomplish this, you create an instance of the sink object:
Create an instance of the server object and add the AdditionStarted
and AdditionCompleted
event handlers separately, like this:
AddClass^ a = gcnew AddClass();
if(a == nullptr) Console::WriteLine("reference not allocated to handle");
ManagedSink^ ms = gcnew ManagedSink();
if(ms == nullptr) Console::WriteLine("reference not allocated to handle");
a->AdditionStarted += gcnew _IAddEvents_AdditionStartedEventHandler
(ms, &ManagedSink::AdditionStarted );
a->AdditionCompleted += gcnew _IAddEvents_AdditionCompletedEventHandler
(ms, &ManagedSink::AdditionCompleted );
a->Add(1, 5);
a->AdditionStarted -= gcnew _IAddEvents_AdditionStartedEventHandler
(ms, &ManagedSink::AdditionStarted );;
a->AdditionCompleted -= gcnew _IAddEvents_AdditionCompletedEventHandler
(ms, &ManagedSink::AdditionCompleted );
Now just compile the solution and your C++/CLI client is ready.
Run the MC++ project. You should see the following output:
History
- 15 Nov 2011: Corrected image links.
- 20 Oct 2011: Initial release.