After you’ve built and registered the .NET assembly, and installed it into the global assembly cache, you can build a client application by using the event sources. Implementing a callback or sink object that
implements the IDispatch interface was – using Visual Basic 6.0 – just a matter of adding the with Events keyword, very similar to how Visual Basic deals with .NET events today.
It’s more work with C++, but here the Active Template Library helps.
Open the C++ Console application created previously and add the following includes to the file 5 tdafx.h:
extern CComModule _Module;
The file stdafx. cpp requires an include of the ATL implementation file atlimpl. cpp:
Add the new class CEventHandler to the file COMClient. cpp.
This class contains the implementation of the IDispatch interface to be ‘Called by the component.
The implementation of the IDispatch interface is done by the base class IDispEventImpl.
This class reads the type library to match the dispatch IDs of the methods and the parameters to the methods of the class.
The template parameters of the class IDispatchEventImpl requires an ID of the sink object (here the 10 4 is used), the class that implements the callback methods (CEventHandler), the interface ID of the callback interface (DIID_IMathEvents), the 10 of the type library (LIBID_DotnetComponent), and the version number of the type library.
You can find the named IDs DIID_IMathEvents and LIBID_DotnetComponer:t in the file dotnetcomponent.
tlh that was created from the #import statement.
The sink map that is surrounded by BEGIN_SINlCMAP and END_SINK_MAPdefines the methods that are implemented by the sink object.
SINK_ENTRY_EXmaps the method OnCalcCompleted to the dispatch 1046200.
This dispatch ID was defined with the method CalculationCompleted of the IMathEvents interface in the .NET component.
class CEventHandler : public IDispEventlmpl<4, CEventHandler,
&DIID_IMathEvents, &LIBID_DotnetComponent, 1, 0>
SINK_ENTRY_EX(4, DIID_IMathEvents, 46200, OnCalcCompleted)
cout « ‘calculation c·ompleted· « endl;
The main method now needs a change to advise the event sink object to the component, so that the component can call back into the sink.
This can be done with the method DispEventAdvise () of the CEventHandler class by passing an IUnknown interface pointer.
The method DispEVentUnadvise.( )
unregisters the sink object again.
int _tmain(int argc, _TCHAR*argv[J)·
hr = Colnitialize(NULL);
hr ~ spWelcome.Createlnstance(·Wrox.DotnetComponent·);
IUnknownPtr spUnknown = spWelcome;
cout « spwelcome-·>Greeting (. Isabella’) « endl;
.-“” hCrEv=enetHveanntdHlearn*dlere-v>eDnitsHpaEnvdelnetrAdv=isenew C(sEpvUennktHnoawndnl)e;r();
spMath = spWelcome; II QueryInterface()
long result = spMath->Add(4, 5);
cout « ‘~esult:’ « result « endl;
catch (_co~error& e)
cout « e.ErrorMessage() « endl;