导入的本机函数在 .NET 4.0 中不起作用

发布于 2025-01-06 11:25:29 字数 1305 浏览 0 评论 0原文

我正在将项目从 .net 3.5 迁移到 .net 4.0 并遇到以下问题。 有 2 个 DllImport 语句:

<DllImport("hid64.dll")> _
Public Sub GenerateHardwareID( _
        <MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=1)> ByVal Buffer As Byte(), _
        ByVal BufferLength As Int32)
End Sub

<DllImport("hid64.dll")> _
Public Function BufferToString( _
        <MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=1)> ByVal Buffer As Byte(), _
        ByVal BufferLength As Int32) As <MarshalAs(UnmanagedType.LPWStr)> String
End Function

对于 .NET 3.5,这两个函数都可以很好地工作。但对于 .NET 4.0,BufferToString 函数的调用会中断程序的执行,而不会引发任何异常。
我尝试了 DllImport 属性的 CallingConvention、CharSet 等字段: http://msdn.microsoft.com/en-us /library/system.runtime.interopservices.dllimportattribute.aspx 没有成功。

此变体:

<DllImport("hid64.dll", CharSet:=CharSet.Auto, PreserveSig:=False, SetLastError:=True)> _
Public Function BufferToString( _
        <MarshalAs(UnmanagedType.LPArray)> ByVal Buffer As Byte(), _
        ByVal BufferLength As Int32) As <MarshalAs(UnmanagedType.LPWStr)> String
End Function 

不会中断程序的执行,但函数返回“Nothing”。

I am migrating project from .net 3.5 to .net 4.0 and faced the following issue.
There are 2 DllImport statements:

<DllImport("hid64.dll")> _
Public Sub GenerateHardwareID( _
        <MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=1)> ByVal Buffer As Byte(), _
        ByVal BufferLength As Int32)
End Sub

<DllImport("hid64.dll")> _
Public Function BufferToString( _
        <MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=1)> ByVal Buffer As Byte(), _
        ByVal BufferLength As Int32) As <MarshalAs(UnmanagedType.LPWStr)> String
End Function

For the .NET 3.5 both functions work well. But for the .NET 4.0 the call of the BufferToString function breaks execution of the programm without raising any exception.
I played around with CallingConvention, CharSet and so on fields of the DllImport attribute:
http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.dllimportattribute.aspx
without success.

This variant:

<DllImport("hid64.dll", CharSet:=CharSet.Auto, PreserveSig:=False, SetLastError:=True)> _
Public Function BufferToString( _
        <MarshalAs(UnmanagedType.LPArray)> ByVal Buffer As Byte(), _
        ByVal BufferLength As Int32) As <MarshalAs(UnmanagedType.LPWStr)> String
End Function 

does not break execution of the programm but the function returns 'Nothing'.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

懵少女 2025-01-13 11:25:29

这是我认为最有可能的解释。

BufferToString 函数的返回值是一个字符串。 p/invoke 编组器必须将其从本机编组为托管。它通过假设本机代码返回由 COM 分配器分配的空终止字符指针来实现这一点。当它完成将内容传输到 .net 字符串时,它会在指针上调用 CoTaskMemFree。如果该内存不是由 COM 分配器分配的,那么此时您可能会看到失败。

为了解决这个问题,您有几种选择。您可以更改 BufferToString 的 p/invoke 以返回 IntPtr。使用 Marshal.PtrToStringUni 将内容复制到 .net 字符串。然后,您就需要负责处理非托管内存。据推测,非托管库为您提供了一种机制来做到这一点。

如果您编写了非托管库,那么您可以使用替代解决方案。将 p/invoke 保留为当前状态,但更改非托管库以使用 CoTaskMemAlloc 分配返回值。这将与 p/invoke 编组器的假设相匹配。

Here's what I believe to be the most likely explanation.

The BufferToString function has a return value that is a string. The p/invoke marshaller has to marshal that from native to managed. It does that by assuming that the native code returns a null-terminated character pointer that was allocated by the COM allocator. When it has finished transferring the content to a .net string it calls CoTaskMemFree on the pointer. If that memory was not allocated by the COM allocator then you may see failures at this point.

To get around the problem you have a few options. You could change the p/invoke for BufferToString to return IntPtr. Copy the contents to a .net string with Marshal.PtrToStringUni. This then leaves you with the responsibility of disposing of the unmanaged memory. Presumably the unmanaged library offers you a mechanism to do that.

If you wrote the unmanaged library then you can use an alternative solution. Leave the p/invoke exactly as it currently is but change the unmanaged library to allocate the return value using CoTaskMemAlloc. That then will match with the p/invoke marshaller's assumptions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文