我正在编写一个混合模式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::LPStr
与GetDelegateForFunctionPointer
编组在一起有什么问题?
注意:如果在这里知道重要的话,C ++桥是在x86中编译的。
答案 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);