delegates - servidor - Cómo usar boost:: bind en C++/CLI para vincular a un miembro de una clase administrada
socket en c cliente servidor (2)
Estoy usando boost :: signal en una clase nativa de C ++, y ahora estoy escribiendo un contenedor .NET en C ++ / CLI, de modo que pueda exponer las devoluciones de llamada nativas de C ++ como eventos .NET. Cuando trato de usar boost :: bind para tomar la dirección de una función miembro de mi clase administrada, obtengo el error 3374 del compilador, que dice que no puedo tomar la dirección de una función miembro a menos que esté creando una instancia delegada. ¿Alguien sabe cómo vincular una función miembro de una clase administrada usando boost :: bind?
Para aclarar, el siguiente código de ejemplo causa el error 3374 del compilador:
#include <boost/bind.hpp>
public ref class Managed
{
public:
Managed()
{
boost::bind(&Managed::OnSomeEvent, this);
}
void OnSomeEvent(void)
{
}
};
Después de buscar en Google un poco más, finalmente encontré una buena publicación en el blog sobre cómo hacer esto. El código en esa publicación era un poco más de lo que necesitaba, pero el nugget principal era usar una función libre global que toma un argumento de la manejada este puntero envuelto en una plantilla gcroot <>. Consulte SomeEventProxy (...) en el siguiente código para ver un ejemplo. Esta función da la vuelta y llama al miembro administrado que estaba tratando de vincular. Mi solución aparece a continuación para referencia futura.
#include <msclr/marshal.h>
#include <boost/bind.hpp>
#include <boost/signal.hpp>
#include <iostream>
#using <mscorlib.dll>
using namespace System;
using namespace msclr::interop;
typedef boost::signal<void (void)> ChangedSignal;
typedef boost::signal<void (void)>::slot_function_type ChangedSignalCB;
typedef boost::signals::connection Callback;
class Native
{
public:
void ChangeIt()
{
changed();
}
Callback RegisterCallback(ChangedSignalCB Subscriber)
{
return changed.connect(Subscriber);
}
void UnregisterCallback(Callback CB)
{
changed.disconnect(CB);
}
private:
ChangedSignal changed;
};
delegate void ChangeHandler(void);
public ref class Managed
{
public:
Managed(Native* Nat);
~Managed();
void OnSomeEvent(void);
event ChangeHandler^ OnChange;
private:
Native* native;
Callback* callback;
};
void SomeEventProxy(gcroot<Managed^> This)
{
This->OnSomeEvent();
}
Managed::Managed(Native* Nat)
: native(Nat)
{
native = Nat;
callback = new Callback;
*callback = native->RegisterCallback(boost::bind( SomeEventProxy, gcroot<Managed^>(this) ) );
}
Managed::~Managed()
{
native->UnregisterCallback(*callback);
delete callback;
}
void Managed::OnSomeEvent(void)
{
OnChange();
}
void OnChanged(void)
{
Console::WriteLine("Got it!");
}
int main(array<System::String ^> ^args)
{
Native* native = new Native;
Managed^ managed = gcnew Managed(native);
managed->OnChange += gcnew ChangeHandler(OnChanged);
native->ChangeIt();
delete native;
return 0;
}
Mientras su respuesta funciona, expone parte de su implementación al mundo (Managed :: OnSomeEvent). Si no desea que las personas puedan plantear el evento OnChange de cualquier manera invocando OnSomeEvent (), puede actualizar su clase administrada de la siguiente manera (en base a este consejo ):
public delegate void ChangeHandler(void);
typedef void (__stdcall *ChangeCallback)(void);
public ref class Managed
{
public:
Managed(Native* Nat);
~Managed();
event ChangeHandler^ OnChange;
private:
void OnSomeEvent(void);
Native* native;
Callback* callback;
GCHandle gch;
};
Managed::Managed(Native* Nat)
: native(Nat)
{
callback = new Callback;
ChangeHandler^ handler = gcnew ChangeHandler( this, &Managed::OnSomeEvent );
gch = GCHandle::Alloc( handler );
System::IntPtr ip = Marshal::GetFunctionPointerForDelegate( handler );
ChangeCallback cbFunc = static_cast<ChangeCallback>( ip.ToPointer() );
*callback = native->RegisterCallback(boost::bind<void>( cbFunc ) );
}
Managed::~Managed()
{
native->UnregisterCallback(*callback);
delete callback;
if ( gch.IsAllocated )
{
gch.Free();
}
}
void Managed::OnSomeEvent(void)
{
OnChange();
}
Tenga en cuenta la forma de bind<R>()
alternativa bind<R>()
que se utiliza.