最近完成了一个C++版本的对外sdk程序,其中有部分回调函数使用。
C++程序使用时没有异常,但是在C#环境下使用时出了点问题,简单总结下。
感谢博客:http://blog.csdn.net/songjinshi/article/details/8153635 帮助我解决了问题。
C++中的回调函数原型如下:
typedef void (STDCALL *fCallback)(const char* csDetail, void *pUser);
其中有一个参数是char * ,就是字符指针,这里需要特别注意。
在C#中需要以委托完成相应回调操作,心路历程如下:
1,开始使用如下形式的委托函数:
public delegate void MSGCALLBACK(ref byte pBuffer, UIntPtr pUser);
出现问题,回调函数仅能接收到一个字符,而非整个字符数组的值。
2,使用如下形式的委托函数:
public delegate void MSGCALLBACK(ref byte[] pBuffer, UIntPtr pUser);
出现如1 的问题,回调函数仅能接收到一个字符,而非整个字符数组的值。
3,使用string代替byte数组,委托函数如下:
public delegate void MSGCALLBACK(string pBuffer, UIntPtr pUser);
正常情况下接收数据均正常,但是在接收中文字符“面”是,出现异常,查看内存整个内存地址位置的值都异常了,如下:
,乱码问题是一个“面”子,相应xml格式中的“<”也不存在了,导致解析xml异常,
相应内存地址内容如下:
2f表示字符“/” 45是表示“E”,可以看到内存地址“/”前面的信息已经面目全非了,
这里具体什么原因确实没有找到,希望有大神可以帮忙解答。
4,最终正确的委托函数如下:
需要包含包 “using System.Runtime.InteropServices;
public delegate void MSGCALLBACK([MarshalAs(UnmanagedType.LPArray, SizeConst = 8000)]byte[] pBuffer, UIntPtr pUser);
成功的接收回调消息并完成消息解析,没有出现任何异常。
解释如下:
在给c++传入数组参数时,必须得用 [MarshalAs(UnmanagedType.LPArray,SizeConst=8000)] 处理一下,相当于是告诉c++,c#传入的是一个长度为8000的数组类型,如果不写这句话的话,你回调函数接收到的参数将只有一条数据。
对于MarshalAs,MarshalAs属性指示如何在托管代码和非托管代码之间封送数据。
当 MarshalAsAttribute.Value 设置为 LPArray时,必须设置 SizeConst 以指示数组中的元素数。当需要区分字符串类型时,ArraySubType 字段可以选择包含数组元素的 UnmanagedType。此 UnmanagedType 只可用于作为结构中的字段的数组。而SizeConst则是指数组中的元素个数。
转载一个链接,用以帮助理解MarshalAs如何使用:
http://blog.csdn.net/xiaobai1593/article/details/7025775