求救:C# 调用C++ 回调函数的问题,将无效 VARIANT 传递给 CLR 会导致意外的异常
客户给的dll文件,用c#调用,其中有个方法是要传回调函数c++是这样定义的
1、On_exec_result SetExecResult(On_exec_result pHandler);
2、typedef void(CALLBACK* On_exec_result)(const TAnswer *pAnswer);
3、TAnswer{
char chInfo [64]
int nAnswer
int nMarkets
char chMarketFlag [32][4]
int nDynDate [32]
}
(真搞不明白搞不明白SetExecResult的返回值也是个On_exec_result函数?)
我c#是这样写的:
1、 [DllImport("TAPI.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void SetExecResult(On_exec_result pHandler);
2、public delegate void On_exec_result (TAnswer tAnswer);
3、public struct TAnswer
{
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 64)]
public byte[] chInfo;
[MarshalAs(UnmanagedType.I4)]
public int nAnswer;
[MarshalAs(UnmanagedType.I4)]
public int nMarkets;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 3 * 16)]
public byte[] chMarketFlag;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public byte[] nDynDate;
}
调用的地方:
On_exec_result tHandler = new On_exec_result(OnExecHandler);
SetExecResult(tHandler);
public void OnExecHandle(TAnswer tAnswer)
{
Logger.Info(tAnswer.nAnswer);
}
运行的时候错误:从非托管 VARIANT 转换为托管对象的过程中检测到无效 VARIANT。将无效 VARIANT 传递给 CLR 会导致意外的异常、损坏或数据丢失
C# C++ struct callback
[解决办法]
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 64)]
public byte[] chInfo;
[MarshalAs(UnmanagedType.I4)]
public int nAnswer;
[MarshalAs(UnmanagedType.I4)]
public int nMarkets;
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 3 * 16)]
public byte[] chMarketFlag; //二维数组尺寸似乎不对
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public byte[] nDynDate; //这里要求的 int ,
[解决办法]
应该是struct的定义有问题吧,楼上应该是正解
[解决办法]
楼主,嗯,花了我2小时,我在VS2010里面模拟了你的问题,得到正确结构返回了,不像你只传了一个整数。
问题就是在传递结构的时候出错,我建议你还是多搜索一下网上关于C#、C++互操作的文章。
1.SetExecResult返回是个函数指针是为了调用C#里面的相应函数(委托)。调用可以是双方的,而不只是C#单方向调用C++的函数。
2.正如楼上说的,你就托管代码转换成非托管代码时候用MarshalAs显示定义数组元素所占位置大小是可取的,但是你改后的SizeConst还有一个错的,没算对,最后一个是int型数组,应该定义成32*4。
3.最后在C#定义结构时显示的声明[structLayout(LayoutKind.Sequential)],虽然MSDN上说默认是这个选项,但我建议你还是显示写出来。字段顺序很重要。
4.在你引用DLL是声明可CallingConvention.Cdecl,但是DLL中的是函数是CALLBACK,这个在定义是#define CALLBACK __stdcall。
还有一些小问题就不讲了,你先试试看,不行的话,我给你贴我的代码。