存档

2012年12月 的存档

c# 调用 c++ dll 问题的解决

2012年12月3日 没有评论

上一个星期,都在解决一个问题,c# 调用 c++ 的 dll 。

问题出现在字符串上,在 win8 64位+vs2012 环境下,64位的c#去调用64位的 c++ dll。在调试的时候,总是自动退出调试,没有进入异常,也没有什么输出。dll 方法是接收2个参数,并返回一个字符串。c# 通过调用获得返回的字符串。

一开始的时候,我以为是由于 c# 和 c++ 之间不同的类型转换时,我给设置错了类型导致,然后又仔细拿网上的好几篇文章做对比,发现这块没有问题。dll 文件并不是我们这边提供的,没有源码所以也不好联调。我就给 dll 那边发邮件,描述情况,并期待他们的反馈。

对方那边就只会c++,我提供的c#代码他们看不太懂,再加上对方没有64位环境,同时也不愿意提供dll的源码给我这边调试,进度比较慢。白天就是邮件来邮件去,晚上的时候我就各种安装系统,发现这问题只在64 位系统上出现,在 32 位系统上是可以正确调用的。

后来突然想到,如果我这边新建一个 c++ 项目的话,能不能够复现呢?果然,问题复现了,现在抛开对方的 dll 文件,也可以进行调试了。经过跟踪,发现 c++ 代码完全成功执行了,但是在 c# 调用这边就崩溃了。这么看起来,似乎和 c++ 代码方面的关系不大。于是又仔细检查了 c++ 的导出函数设置,没有问题。我以为是我c#项目的问题,删掉重建了个简单的,还是不行。

接下来,我又怀疑是不是 vs 本身的问题,因为是用的 2012 的版本,恰好这个时候,vs2012 sp1补丁包出来了,果断地升级。升级后发现还是崩溃了。

到这里似乎没有进展了,最后我请教了 c++ 方面的救兵。雪飞同学果然很是强悍,不多会就给出了我一个解决方法。在 c# 这边的函数申明这里设置返回类型为 IntPtr 类型,然后使用 Marshal.PtrToStringAuto 方法进行转换为托管字符串。问题就解决了。

我们一起还讨论这个问题出现的原因,一个可能的原因是在64位平台上,c++ 返回的是一个64位的指针,但是c#在调用的时候,并没有作为64位指针来获取,或者说拿了一个错误的指针,导致字符串获取失败。有可能在 c# 64位平台上字符串的初始化的时候,从非托管代码到托管代码的构造函数里存在缺陷。当然这个问题,是不是这样的,我们就不清楚了。获取给 vs 的开发team发个邮件可以得到更详细的信息。

在今天的时候,我越想越愤懑,为什么别的语言可以,c# 就非得这样,在32位和64位平台上还要做区分代码编写。碰巧下午我测试时先申明了字符串,然后再调用,发现问题居然解决了。似乎验证了和雪飞同学一起讨论的结果。

可是,最好的一个解决方法居然是这样的。这一刻,我觉得太蛋疼了。真的。

string s=””;s=GetInfo(); 的写法和 string s=GetInfo(); 之间对于托管代码和非托管代码居然有这样的区别。

 

还有另外一个问题,就是结构体转换成字节时,进入了异常。也是字符串的问题,后来根据 google 上面的搜索解决了。如果结构体里包含字符数组,在转换成字节时,需要先定义长度,不然会转换失败。具体来说就是在结构体里字符数组前面添加属性定义。例如

[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 6)]             public char[] device ;  //这里的 device 为 “iphone”,长度为6,所以 SizeConst=6

 

分类: 日常 标签: , , , , ,