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

Use native function pointer for listening to managed event / marshaling issue

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

在我的 .NET 库中的一个 classes 中,只要需要显示某些消息(到控制台或任何取决于调用应用程序的内容),就可以附加到事件。

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

为了从本机 C++ 应用程序调用它,我定义了以下 pointer/delegate 桥:

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

省略用于连接所有内容的胶水(附加到 MessageReported,从 EventHandler 中删除 sender,等等...),这是我从本机函数指针创建托管委托的方法:

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 中编译的,如果在这里知道很重要的话。

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

您的委托声明与 32 位代码中的函数指针声明不兼容。本机代码中的默认调用约定几乎总是 __cdecl。代表的默认值为 __stdcall。一个有点古怪的选择但受到启发,因为互操作被认为对进行 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);