c#调用c++ 回调
场景:怎么封装C++的中的回调函数供C#调用
求助:如何封装C++的中的回调函数供C#调用
我现在有一个C++写的dll文件,以及和它相关的.h文件,没有.cpp文件。我的问题描述如下:
.h中定义了一个unmanaged class
其中CThostFtdcRspInfoField定义为:
还有个专门的方法注册派生自回调接口类的实例
上面那个CThostFtdcMdSpi是所谓回调接口类,OnRspError是回调函数。调用这个回调函数的函数指针在dll内部实现,我没有源代码。
现在我想用C++/CLI把这个dll封装一下,供C#程序调用。但是不知道如何处理这个回调函数。我想最好是能把这个回调函数转换成.net中的事件。还望各位大神指导,谢谢。
我本人不是专门搞程序的,为了方便自己的工作才想这样搞一下,请见谅。
------解决方案--------------------
参考: C#调用C++动态库一些重点问题
具体内容,包括C#回掉函数的处理,见上面链接的文章
------解决方案--------------------
有点奇怪,如果单纯的要注册回调的话,用函数指针就可以了,特地用一个接口类来实现回调不像是C/C++的实现方式,反而更接近Java。
抛开疑问,要使用这样的回调需要:
1.继承这个接口类,重写OnRspError方法。
由于在C++/CLI中托管类不能继承非托管类,必须由一个非托管类(假设为CThostFtdcMdSpiImpl)继承CThostFtdcMdSpi。
2.注册回调时,传递一个CThostFtdcMdSpiImpl实例。
注意对象的生存期管理。
非托管类中不能储存托管句柄,但可以调用静态托管函数,或者使用Marshal类提供的GetFunctionPointerForDelegate获取并储存一个委托对应的函数指针。在OnRspError方法的实现中,你可以通过调用静态托管函数来间接引发托管事件,或者使用函数指针。
参考实现(需要dll对应的lib文件方能通过链接,假定RegisterSpi是一个全局函数):
C#调用:
求助:如何封装C++的中的回调函数供C#调用
我现在有一个C++写的dll文件,以及和它相关的.h文件,没有.cpp文件。我的问题描述如下:
.h中定义了一个unmanaged class
class CThostFtdcMdSpi
{
virtual void OnRspError(CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {};
}
其中CThostFtdcRspInfoField定义为:
struct CThostFtdcRspInfoField
{
int ErrorID;
char ErrorMsg[81];
};
还有个专门的方法注册派生自回调接口类的实例
virtual void RegisterSpi(CThostFtdcMdSpi *pSpi) = 0;
上面那个CThostFtdcMdSpi是所谓回调接口类,OnRspError是回调函数。调用这个回调函数的函数指针在dll内部实现,我没有源代码。
现在我想用C++/CLI把这个dll封装一下,供C#程序调用。但是不知道如何处理这个回调函数。我想最好是能把这个回调函数转换成.net中的事件。还望各位大神指导,谢谢。
我本人不是专门搞程序的,为了方便自己的工作才想这样搞一下,请见谅。
------解决方案--------------------
参考: C#调用C++动态库一些重点问题
具体内容,包括C#回掉函数的处理,见上面链接的文章
------解决方案--------------------
有点奇怪,如果单纯的要注册回调的话,用函数指针就可以了,特地用一个接口类来实现回调不像是C/C++的实现方式,反而更接近Java。
抛开疑问,要使用这样的回调需要:
1.继承这个接口类,重写OnRspError方法。
由于在C++/CLI中托管类不能继承非托管类,必须由一个非托管类(假设为CThostFtdcMdSpiImpl)继承CThostFtdcMdSpi。
2.注册回调时,传递一个CThostFtdcMdSpiImpl实例。
注意对象的生存期管理。
非托管类中不能储存托管句柄,但可以调用静态托管函数,或者使用Marshal类提供的GetFunctionPointerForDelegate获取并储存一个委托对应的函数指针。在OnRspError方法的实现中,你可以通过调用静态托管函数来间接引发托管事件,或者使用函数指针。
参考实现(需要dll对应的lib文件方能通过链接,假定RegisterSpi是一个全局函数):
#include "dll.h"
using namespace System;
using namespace System::Runtime::InteropServices;
typedef void (*RspErrorCallback)(CThostFtdcRspInfoField*, int, bool);
namespace CppInvoke
{
public ref class RspErrorEventArgs : public EventArgs
{
public:
int ErrorID;
String^ ErrorMsg;
int RequestID;
bool IsLast;
RspErrorEventArgs(CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
this->ErrorID = pRspInfo->ErrorID;
this->ErrorMsg = gcnew String(pRspInfo->ErrorMsg);
this->RequestID = nRequestID;
this->IsLast = bIsLast;
}
};
class CThostFtdcMdSpiImpl : public CThostFtdcMdSpi
{
public:
CThostFtdcMdSpiImpl(RspErrorCallback ecb)
{
this->RaiseRspError = ecb;
}
virtual void OnRspError(CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
this->RaiseRspError(pRspInfo, nRequestID, bIsLast);
}
void Test(void)
{
Console::WriteLine("Test");
}
private:
RspErrorCallback RaiseRspError;
};
delegate void RspErrorDel(CThostFtdcRspInfoField*, int, bool);
public ref class CThostFtdcMdSpiWrapper
{
private:
CThostFtdcMdSpiImpl* nestImplClass;
public:
CThostFtdcMdSpiWrapper()
{
this->nestImplClass = new CThostFtdcMdSpiImpl(
(RspErrorCallback)Marshal::GetFunctionPointerForDelegate(
gcnew RspErrorDel
(
this,
&CppInvoke::CThostFtdcMdSpiWrapper::RaiseRspError
)
).ToPointer()
);
}
~CThostFtdcMdSpiWrapper()
{
delete nestImplClass;
}
event EventHandler<RspErrorEventArgs^>^ RspError;
void RaiseRspError(CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
RspError(this, gcnew RspErrorEventArgs(pRspInfo, nRequestID, bIsLast));
}
static void RegisterSpi(CThostFtdcMdSpiWrapper^ spi)
{
::RegisterSpi(spi->nestImplClass);
}
};
}
C#调用:
using System;
using CppInvoke;
class Program
{
static void Main(string[] args)
{
using (var c = new CThostFtdcMdSpiWrapper())
{
CThostFtdcMdSpiWrapper.RegisterSpi(c);
c.RspError += (_, e) =>
{
Console.WriteLine("ErrorId = {0}, ErrorMsg = \"{1}\", RequestId = {2}, IsLast = {3}", e.ErrorID, e.ErrorMsg, e.RequestID, e.IsLast);
};
//其他操作
}
}
}