【发布时间】:2014-09-11 18:27:59
【问题描述】:
我正在使用 Nikon 的 API 来控制显微镜。当我在 C# 中实现驱动程序时,API 是用 C++ 编写的。要打开与显微镜的连接,我必须使用具有以下语法的 Open 方法:
lx_result MIC_Open ( const lx_int32 iDeviceIndex, lx_uint64& uiConnectedAccessoryMask, const lx_uint32 uiErrMsgMaxSize, lx_wchar* pwszErrMsg)
如果我按如下方式编组该技术,则每当执行垃圾收集时代码都会崩溃:
[DllImport("/filepath/Ni_Mic_Driver.dll")]
protected static extern int MIC_Open ( int deviceIndex , ref ulong accessoryMask , uint errorMessageMaxSize , [MarshalAsAttribute(UnmanagedType.LPWStr)] string error);
抛出 0xc000005 异常,错误代码为 80131506,表示垃圾收集器已尝试使用无效指针处理对象。 Visual Studio 2013 产生的错误消息表明:
“此错误可能是 CLR 中的错误或用户代码的不安全或不可验证部分中的错误。 此错误的常见来源包括 COM-Interop 或 PInvoke 的用户编组错误,这可能会损坏堆栈。”
按照消息建议,我将编组调整为以下内容,这不会导致 CLR 崩溃。
[DllImport("/filepath/Ni_Mic_Driver.dll")]
protected static extern int MIC_Open ( int deviceIndex , ref ulong accessoryMask , uint errorMessageMaxSize , [MarshalAsAttribute(UnmanagedType.LPStr)] string error);
我很困惑,因为我的理解是 wchar* 表示一个指向以 null 结尾的 16 位 Unicode 字符字符串的指针,它应该映射到 UnmagedType.LPWStr。但是,代码只有在我使用 UnmanagedType.LPStr 时才有效。
以下也可以,但需要更多的工作才能提取相应的字符串。
[DllImport("/filepath/Ni_Mic_Driver.dll")]
protected static extern int MIC_Open ( int deviceIndex , ref ulong accessoryMask , uint errorMessageMaxSize , IntPtr errorPointer );
关于为什么 UnmagedType.LPWStr 在与 UnmanagedType.LPStr 或 IntPtr 一起运行时会导致崩溃的任何想法?
【问题讨论】:
-
MIC_Open对指针有什么作用?它是试图释放它,还是在它返回后继续持有它?我还应该指出,将lx_uint64&编组为指针会导致未定义的行为;不保证引用具有与指针相同的特性。 -
您使用的最后一个参数允许 GC 堆被本机代码破坏。它必须是容量足够大的 StringBuilder(不是 ref)。并确保在第三个参数中传递它的容量。 -1 为了安全起见。
-
@cdhowie:我不确定 MIC_Open 对指针的作用。他们没有在 API 文档中指定,我也无权访问底层源代码。你会建议我用什么替换 ref ulong?
-
@HansPassant:我理解正确吗:我应该在第四个参数中使用 StringBuilder 而不是 String?我将尝试将第四个参数替换为
[MarshalAsAttribute(UnmanagedType.LPWStr)] string和[MarshalAsAttribute(UnmanagedType.LPWStr] StringBuilder,并在调用编组函数的地方进行必要的更改。我会报告结果。 -
查看我在下面发布的解决方案。感谢您的帮助!
标签: c# c++ .net marshalling unmanaged