VB.NET Pinvoke: Как исправить адрес структуры, передаваемой в DLL? - PullRequest
0 голосов
/ 14 декабря 2018

У меня есть DLL, написанная на C (скомпилированная с использованием VC ++ 2017).Есть несколько функций, принимающих указатели на структуру.

Во время вызова инициализации он сохраняет переданный адрес. А во время последующих вызовов DLL ожидает, что переданные адреса совпадают с первым вызовом инициализации.

В vb.net, я определяю структуру (упакована как 4), я проверил структуру памяти, она точно такая же, как C при передаче в DLL.

Однако каждый раз, когда я вызывал функцию, используя структуру (ByRef), адрес может или не может измениться (сдвиг на 4 байта).

Я что-то пропустил или возможно ли это сделать в VB.NET?

Коды следующие,структура c (это устаревший код, и я бы предпочел не изменять его),

struct A
{
    char a[9] ;
    char b[9] ;
    char c[2] ;
    char d[9] ;
    int e;
    int f;
    char g[2] ;
    char h[9] ;
    int i;
    int j;
    char k[2] ;
    int l;
    char m[41] ;
    char n[41] ;
    char o[10] ;
} ;

Это то, что я определил в VB.NET,

<StructLayout(LayoutKind.Sequential, Pack:=4)>
Structure A
    <VBFixedArray(9), System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=9)> Dim a() As Byte
    <VBFixedArray(9), System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=9)> Dim b() As Byte
    <VBFixedArray(2), System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=2)> Dim c() As Byte
    <VBFixedArray(9), System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=9)> Dim d() As Byte
    Dim e As Integer
    Dim f As Integer
    <VBFixedArray(2), System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=2)> Dim g() As Byte
    <VBFixedArray(9), System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=9)> Dim h() As Byte
    Dim i As Integer
    Dim j As Integer
    <VBFixedArray(2), System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=2)> Dim k() As Byte
    Dim l As Integer
    <VBFixedArray(41), System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=41)> Dim m() As Byte
    <VBFixedArray(41), System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=41)> Dim n() As Byte
    <VBFixedArray(10), System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=10)> Public o() As Byte
End Structure

Это Cпрототип:

__declspec( dllexport ) int __stdcall init(struct A * param1)
__declspec( dllexport ) int __stdcall dosomething(struct A * param1)

Это прототип VB.NET

Public Declare Function init Lib "A.dll" (ByRef param1 As A) As Integer
Public Declare Function dosomething Lib "A.dll" (ByRef param1 As A) As Integer

Dim a As New A
'ok
init(a)
' ok
dosomething(a)
' The second call to dosomething, the param1's address changed by 4 bytes
dosomething(a)

Выше приведен только упрощенный вариант.Вы понимаете, что адрес param1 в C изменяется во время различных вызовов.

Есть ли способ решить эту проблему?

Спасибо.

1 Ответ

0 голосов
/ 14 декабря 2018

Совершенно естественно, что адрес маршаллированной структуры отличается в каждом вызове.Это потому, что маршалер должен создать неуправляемую структуру для отправки в неуправляемый код.Управляемая структура не имеет той же структуры, что и неуправляемая структура, что делает это необходимым.И даже если управляемые и неуправляемые структуры имеют совместимую компоновку (т. Е. Структура может быть прозрачной), адрес может измениться, поскольку диспетчер памяти .net может перемещать объекты.

Однако вы можете взять на себя ответственность за процесс маршалинга.Выделите некоторую неуправляемую память (например, вызвав Marshal.AllocHGlobal, а затем используйте Marshal.StructureToPtr, чтобы заполнить эту память маршалированной версией структуры. Затем вы можете передать адрес этой неуправляемой памяти в неуправляемый код. Когда вы закончите всеваши звонки на неуправляемый код, звоните Marshal.PtrToStructure, чтобы прочитать любые изменения, внесенные в структуру.

Возможно, больший вопрос заключается в том, почему чувствуется необходимость стабильности адреса между вызовами. Я нахожу это оченьТрудно представить сценарий, когда это разумное ожидание для вызывающего абонента. Возможно ли, что ваш неуправляемый код получает свободу, требуя этого от вызывающего абонента?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...