代码之家  ›  专栏  ›  技术社区  ›  Brian Stewart

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

  •  11
  • Brian Stewart  · 技术社区  · 16 年前

    我在BASIC C++类中使用Boo::信号,现在我在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)
        {
        }
    };
    
    2 回复  |  直到 11 年前
        1
  •  10
  •   BKewl    11 年前

    当您的答案有效时,它会向全世界公开您的一些实现(managed::onsomeevent)。如果不希望人们通过调用onsomeEvent()随意地引发onchange事件,则可以按如下方式更新托管类(基于 this advice ):

    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<R>() 使用的表单。

        2
  •  4
  •   Brian Stewart    16 年前

    在谷歌搜索了更多之后,我终于找到了一个 nice blog post 关于如何做到这一点。这篇文章中的代码比我需要的要多一点,但是主要的核心是使用一个全局自由函数,该函数接受一个用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;
    }