【问题标题】:P/Invoke method broken just by updating from .Net 4.5 to .Net 4.5.1仅通过从 .Net 4.5 更新到 .Net 4.5.1 就破坏了 P/Invoke 方法
【发布时间】:2013-12-04 13:12:31
【问题描述】:

我的应用程序中有一个 P/Invoke 调用,它通过用 C++ 编写的 API(一个 .dll 文件)与外部硬件进行通信

在我安装了最新的 .Net 4.5.1 之前,此方法运行良好,并且在不进行任何代码更改的情况下,它现在会引发异常:“无法将类型 'void' 隐式转换为 'object'”

我应该检查什么以使我的应用程序与 .Net 4.5.1 兼容?回滚到以前的框架是我发现使它工作的唯一方法!

[DllImport("TestAPI", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
internal static extern bool OMBOpen(int VID, int PID, int CID,
   StringBuilder description,
   int bufferSize);

C++中方法的原生声明

TESTAPI_API 
bool OMBOpen(int VID,int PID,int IID,char* buffer,int bufferSize);

编辑:

最终,问题根本不在于上述方法调用本身,而在于将数据从指向数据结构的指针编组(参见接受的答案),正如 David Heffernan wiseley 所怀疑的那样,这在代码的其他地方.

【问题讨论】:

  • 尝试“TestAPI.dll”而不是“TestAPI”
  • @thefiloe 不高兴,但谢谢..
  • 你能显示函数的原生声明吗?
  • Cannot implicitly convert type 'void' to 'object'" 这不是运行时错误,而是编译器错误消息。
  • 我来自 Microsoft .NET Framework 团队。您能否向我发送适用于 .NET4.5 但不适用于 .NET 4.5.1 的详细重现代码,我想调查一下。将它发送到 Microsoft com 的 netfx45compat 谢谢!

标签: c# .net pinvoke .net-4.5


【解决方案1】:

尝试将 void 方法的结果分配给变量时,会引发异常“无法将类型 'void' 隐式转换为 'object'”。虽然这通常是编译器错误,但如果在执行过程中出现,则通常是动态调用方法的结果(例如,使用 dynamic 关键字或使用 IronPython 等动态语言)。

.NET 4.5.1 为 Marshal.SizeOfMarshal.PtrToStructure 引入了重载,并且在某些情况下动态方法调用可能会选择新的重载。请参阅 Microsoft KB2909958。上述异常不会来自 P/Invoke 本身,而是来自后续的封送操作。

这类问题的最简单解决方案是在调用中引入强制转换以确保解决正确的方法。

#Code from 4.5
dynamic dynamicVar = ...
object boxedStruct = Marshal.PtrToStructure(myPtr, dynamicVar.GetType());
// Above resolves to 'object Marshal.PtrToStructure(IntPtr, Type)' in 4.5
// and resolves to 'void Marshal.PtrToStructure<T>(IntPtr, T)' in 4.5.1
int size = Marshal.SizeOf(dynamicVar.GetType());
// Above resolves to 'object Marshal.SizeOf(Type)' in 4.5
// and resolves to 'void Marshal.SizeOf<T>(T)' in 4.5.1

#Fixed for 4.5.1
dynamic dynamicVar = ...
object boxedStruct = Marshal.PtrToStructure(myPtr, (Type)dynamicVar.GetType());
// Adding the cast forces the code to resolve to
// 'object Marshal.PtrToStructure(IntPtr, Type)'
int size = Marshal.SizeOf((Type)dynamicVar.GetType());
// Adding the cast forces the code to resolve to
// 'int Marshal.SizeOf(Type)'

【讨论】:

  • 解决了我的问题,非常高兴 .Net 作者这么快就找到了这个主题!
  • @Xavier 你是说实际错误出现在调用PtrToStructureSizeOf 的代码中,而该代码在Alex 的应用程序中而不是问题中?我只是想明白。
  • @DavidHeffernan:是的。这是正确的。该代码位于应用程序的其他位置,与 P/Invoke 调用之间的编组有关。
【解决方案2】:

我发现问题中的代码唯一有问题的是返回值。默认情况下,编组器将假定本机代码返回一个 4 字节 BOOL。你应该这样写 pinvoke:

[DllImport(...)]
[return: MarshalAs(UnmanagedType.I1)]
internal static extern bool OMBOpen(...);

但是,我不明白这会如何导致您报告的错误。我宁愿怀疑实际的问题在于不在问题中的代码。

参考资料:

  1. http://blogs.msdn.com/b/jaredpar/archive/2008/10/14/pinvoke-and-bool-or-should-i-say-bool.aspx
  2. http://www.greengingerwine.com/index.php/2011/08/always-marshal-bool-return-types-when-using-pinvoke/
  3. http://msdn.microsoft.com/en-us/library/ms182206.aspx

【讨论】:

    猜你喜欢
    • 2013-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-21
    • 1970-01-01
    • 2013-08-30
    相关资源
    最近更新 更多