2010-12-03 65 views
2

作为一名C#开发人员,我认为我们很多人都有从托管代码调用非托管代码的经验。开发人员应该知道什么与托管代码的互操作性

在处理托管代码和非托管代码之间的互操作性时,您遇到过的最困难的问题是什么? (您最好给出代码示例,如C++函数签名和C#包装)

如何调试运行时错误,因为Visual Studio在处理调用时没有提供高级调试信息?

回答

4

一般来说,如果对C没有足够的了解以获得正确的声明,那么寻找P/Invoke声明的权威参考是很困难的。互联网上有很多不好的声明。典型的陷阱是VB6声明,其中有批次,其中真正为int的参数声明为Long。 Long是VB6中的32位整数类型,由于历史原因Integer是16位。

另一个广泛的错误是在需要IntPtr的情况下使用int。这些声明在32位模式下工作正常,但在64位模式下运行不正常。特别麻烦的是带有4个或更少参数的函数,错误的参数类型不会生成PInvokeStackImbalance MDA警告,因为前4个函数参数在CPU寄存器中传递。在作者宣布这项工作完成后,这个bug往往会变得很长,很难再回到它并诊断问题。

接下来的麻烦是声明和维护P/Invoke声明或C++/CLI包装器的繁琐工作。当非托管API很大时,最终你会写出很多这样的代码。它们中的每一个都准备好让你很难诊断运行时错误,当你弄错了它。

真正难以互操作的是具有基于IUnknown接口的COM服务器。这样的服务器没有类型库,所以没有机会使用Tlbimp.exe来自动生成互操作库。你必须在C#代码中重新声明接口,并确保你得到了[Guid]和方法声明。缺少对多继承的支持需要在接口从基于中间IUnknown的接口继承时跳过额外的环节。 this author错误地称为“继承税”的问题。

这些类型的服务器是比较常见的方式,然后见面。例如,几乎所有你想用shell(explorer.exe)做的事情都是基于IUnknown的。 Vista和Win7扩展也是如此,它们都是由Windows API代码包顺带包装的。

是的,错误处理。太多的非托管代码在那里只返回一些不友好的错误代码,如E_FAIL或E_UNEXPECTED。并没有实现IErrorInfo,所以你得到的是一个无益的通用消息来看待。或者返回BOOL来指示失败的API,请程序员简单地忽略返回值。和AccessViolation或致命引擎执行错误,未经管理的代码在您的脸上炸毁,而不留下任何面包屑,以找出哪里出了问题。这不是C#interop特有的,这样的代码很难被任何人使用。

除此之外,它通常很简单,使其工作。 .NET中的P/Invoke编组器和COM互操作支持非常出色,比其他虚拟机中的可用性要好得多。

0

引用计数框架:虽然CLR可以收集不再使用的所有内存,但它知道非托管库中的内存zip。因此,您需要手动释放从非托管来源获取的资源。

相关问题