the easiest approach would be to write a COM object in the DLL - create an ATL simple object with a methods (say) HRESULT Register(IUnknown *eventCallback), HRESULT UnRegister(void)
(don't bother with dual/dispatch, custom is fine, but make it automation safe)
Use tlbimp (on the generated) tlb file to get C# to 'see' it via the interop assembly
Create a com object in the C#, use regasm to create the tlb for the c++ object to #import it
(tlb's are meta for interface description interchange)
in your c# 'master', create one of your C# com objects, create one of the c++ com objects, call register and pass it your c# object
Now the c++ can store that pointer (in a CComQIPtr<yourc#interface> m_remoteEventSink) and call up to it whenever
c++ code
#import "tlbCreatedFromRegAsm.tlb" raw_interfaces_only no_namespace
HRESULT Register(IUnknown *eventSink)
{
m_eventSink=eventSink;
return S_OK;
}
HRESULT Unregister()
{
m_eventSink.Release();
}
void CoolFunctionalLoop()
{
while(1)
{
m_eventSink->FireSomethingInteresting()
}
}
private:
CComQIPtr<c#interface> m_eventSink;
This Article[
^] covers it almost completely