Hello all.
I've got a bunch of existing, non managed, C++ DLLs that export types
with, among other things, public events implemented using the
boost::signals library.
Now, I need to have these DLL interoperate with managed code. Among
others things, the managed code need to be able to register for
notification with the boost signals. I've tried different approaches
(trying to register a pinned delegate with the boost::signal, etc...),
but the only thing I could make to work is the ugly code below :
///Unmanaged DLL, compiled without /clr
///file event_source_lib.h
#ifdef EVENT_SOURCE_LIB_EXPORTS
#define EVENT_SOURCE_LIB_API __declspec(dllexport)
#else
#define EVENT_SOURCE_LIB_API __declspec(dllimport)
#endif
#include <boost/signals.hpp>
// This class is exported from the event_source_lib.dll
class EVENT_SOURCE_LIB_API EventSource {
public:
boost::signal<void (int)> event;
void RaiseEvent();
};
///Unmanaged DLL, compiled without /clr
///file event_source_lib.cpp
#include "event_source_lib.h"
void EventSource::RaiseEvent()
{
event(3);
}
///managed C++ console app
///file event_sink.cpp
#include "event_source_lib.h"
#include <boost/bind.hpp>
#include <vcclr.h>
#using <mscorlib.dll>
using namespace System;
__gc class EventSink
{
public:
void Sink(int a);
};
void EventSink::Sink(int a)
{
System::Console::WriteLine(S"In managed handler");
}
static void ManagedHandler(gcroot<EventSink*> instance, int a)
{
instance->Sink(a);
}
#pragma unmanaged
static void UnmanagedHandler(gcroot<EventSink*> instance, int a)
{
ManagedHandler(instance, a);
}
//If I do this directly in the _tmain funcion (managed code), I've got
an SEH exception at runtime.
static boost::signals::connection RegisterEventSink(EventSource&
source, gcroot<EventSink*> instance)
{
return source.event.connect(boost::bind(&UnmanagedHandler ,
instance, _1));
}
#pragma managed
int _tmain()
{
EventSource source;
EventSink* sink=new EventSink;
boost::signals::connection con=RegisterEventSink(source,
gcroot<EventSink*>(sink)); //(1)
source.RaiseEvent();
con.disconnect();
return 0;
}
This solution requires *3* static functions (2 unmanaged and 1
managed) to be able to register a member funcion of a __gc class with
the boost signal. My real librarie has tens of different signals, with
different signatures, and the managed wrapper code would soon be an
horrible mess of macros hack if I use this technique.
A curiosity about this code : If I do not declare the unmanaged
RegisterEventSink and call boost::signal::connect directly from
_tmain, I've got an SEHException at runtime. However, if I declare
RegisterEventSink *but do not call it*, the code run smooth. The line
(1) can therefore be replaced with:
boost::signals::connection
con=source.event.connect(boost::bind(&UnmanagedHan dler,
gcroot<EventSink*>(sink), _1));
I suspect that the boost::bind specialization is (correctly) build
when compiling RegisterEventSink, and the same specialization is used
in _tmain. But if RegisterEventSink is commented out, the compiler is
unable to compile the bind specialization when in a managed context.
Does anyone have another cleaner solution for this problem?
Thanks.
Arnaud
MVP - VC