如何在C ++ / CLI中使用boost :: bind绑定托管类的成员

时间:2020-03-06 15:02:28  来源:igfitidea点击:

我在本机C ++类中使用boost :: signal,现在我在C ++ / CLI中编写.NET包装器,以便可以将本机C ++回调公开为.NET事件。当我尝试使用boost :: bind来获取托管类的成员函数的地址时,出现编译器错误3374,表示除非获得委托实例,否则无法获取成员函数的地址。有谁知道如何使用boost :: bind绑定托管类的成员函数?

为了澄清起见,以下示例代码会导致编译器错误3374:

#include <boost/bind.hpp>

public ref class Managed
{
public:
    Managed()
    {
        boost::bind(&Managed::OnSomeEvent, this);
    }

    void OnSomeEvent(void)
    {
    }
};

解决方案

经过更多搜索之后,我终于找到了一篇不错的博客文章,介绍了如何执行此操作。那篇文章中的代码比我需要的多了一点,但是主要的要点是使用全局自由函数,该函数接受包装在gcroot <>模板中的托管指针的参数。有关示例,请参见下面的代码中的SomeEventProxy(...)。然后,此函数转过来并调用我尝试绑定的受管成员。我的解决方案显示在下面,以供将来参考。

#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;
}

当答案起作用时,它将向世界展示某些实现(Managed :: OnSomeEvent)。如果我们不希望人们通过调用OnSomeEvent()随意引发OnChange事件,则可以如下更新Managed类(基于此建议):

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();
}

请注意,使用了另一种bind &lt;R>()形式。