使用本机函数指针来监听托管事件/封送问题

时间:2016-05-27 14:48:08

标签: c++-cli function-pointers marshalling

我正在编写一个混合模式C ++ / CLI程序集桥,以便能够从旧的C ++应用程序调用我的.NET类库。

在我的.NET库中的一个类中,每当需要显示某些消息时(无论是根据调用应用程序还是控制台),都可以附加到事件。

class NetApi
{
    public event EventHandler<MessageEventArgs> MessageReported;
} 

要从本机C ++应用程序调用它,我定义了以下指针/委托桥:

typedef void(*MessageHandler)(const char* msg);
delegate void ManagedMessageHandler([MarshalAs(UnmanagedType::LPStr)] String^ msg);

从胶水中省略连接所有内容(附加到MessageReported,从sender删除EventHandler等等),以下是我如何从本机函数指针创建托管委托: / p>

class NetApiBridge
{
    public:
      void SetMessageHandler(MessageHandler handler)
      {
          wrappedListener = (ManagedMessageHandler^)Marshal::GetDelegateForFunctionPointer((IntPtr)handler, ManagedMessageHandler::typeid);        
      }          

    private:
        msclr::auto_gcroot<NetApi^ > wrappedApi;
        msclr::auto_gcroot<ManagedMessageHandler^ > wrappedListener;

        // In another helper ref class in fact, but here pseudo code to simplify
        void onMessageReported(Object^ sender, MessageEventArgs^ e)
        {
            if (!wrappedListener) { return; }

            wrappedListenter(e->Message); // Send message to native function pointer
        }
}

在创建虚拟C ++测试代码时我几乎就在那里:

void messageHandler(const char* s)
{
    cout << s; 
}
void main()
{
   NetApiBridge api = new NetApiBridge();
   api->SetMessageHandler(&messageHandler);

   api->Measure();
   delete api;
}

一切顺利,事件报告正确,除了....除了我从托管调试助手离开本机处理程序时收到PInvokeStackImbalance,我显然不知道为什么?

const char* UnmanagedType::LPStrGetDelegateForFunctionPointer编组在一起有什么问题?

注意:如果在这里知道重要的话,C ++桥是在x86中编译的。

1 个答案:

答案 0 :(得分:4)

typedef void(*MessageHandler)(const char* msg);
delegate void ManagedMessageHandler([MarshalAs(UnmanagedType::LPStr)] String^ msg);

您的委托声明与32位代码中的函数指针声明不兼容。本机代码中的默认调用约定几乎总是__cdecl。代表的默认值为__stdcall。这是一个有点古怪的选择但受到启发,因为假设interop对于调用OS有用,Windows和COM使用__stdcall。

现在不匹配导致委托存根从堆栈中弹出参数。原生代码也是如此,因此堆栈不平衡4个字节。 MDA可以帮助您诊断这种常见的事故。

你必须帮助并让他们同意。使用委托声明:

   using namespace System::Runtime::InteropServices;
   ...
   [UnmanagedFunctionPointer(CallingConvention::Cdecl)]
   delegate void ManagedMessageHandler(String^ msg);

或函数指针声明:

   typedef void (__stdcall * MessageHandler)(const char* msg);