Импортированная нативная функция не работает в .NET 4.0 - PullRequest
1 голос
/ 16 февраля 2012

Я мигрирую проект из .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 прерывает выполнение программы без каких-либо исключений.
Я поиграл с CallingConvention, CharSet и т. Д. С полями атрибута DllImport: 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'.

1 Ответ

1 голос
/ 17 февраля 2012

Вот то, что я считаю наиболее вероятным объяснением.

Функция BufferToString имеет возвращаемое значение, которое является строкой.Маршаллер p / invoke должен маршалировать это от нативного до управляемого.Он делает это, предполагая, что собственный код возвращает нулевой символьный указатель, который был выделен COM-распределителем.Когда он завершает передачу содержимого в строку .net, он вызывает CoTaskMemFree для указателя.Если эта память не была выделена COM-распределителем, то в этот момент вы можете увидеть сбои.

Чтобы обойти проблему, у вас есть несколько вариантов.Вы можете изменить p / invoke для BufferToString, чтобы он возвращал IntPtr.Скопируйте содержимое в строку .net с помощью Marshal.PtrToStringUni.Это тогда оставляет вам ответственность за избавление от неуправляемой памяти.Предположительно, неуправляемая библиотека предлагает вам механизм для этого.

Если вы написали неуправляемую библиотеку, вы можете использовать альтернативное решение.Оставьте вызов p / точно таким, как он есть в настоящее время, но измените неуправляемую библиотеку, чтобы выделить возвращаемое значение, используя CoTaskMemAlloc.Тогда это будет соответствовать предположениям маршаллера p / invoke.

...