我有一个用C编写的DLL(使用VC ++ 2017编译)。有几个函数接受指向结构的指针。
在init调用期间,它将保存传入的地址。在以后的调用中,DLL期望传入的地址与第一个init调用相同。
在vb.net中,我定义了一个结构(打包为4),检查了内存布局,将其传递给DLL后,它与C完全相同。
但是,每次我使用结构(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)
以上仅为简化版本。您会想到在不同的调用过程中C中的param1的地址会发生变化。
有没有办法解决这个问题?
谢谢。
答案 0 :(得分:2)
在每个调用中,封送处理的结构的地址都不同是很自然的。那是因为封送程序必须创建一个非托管结构才能发送到非托管代码。托管结构与非托管结构的布局不同,因此这是必需的。即使托管和非托管结构具有兼容的布局(即该结构是可蓝调的),该地址也可能会更改,因为.net内存管理器可以移动对象。
但是,您可以负责封送处理。分配一些非托管内存(例如,通过调用Marshal.AllocHGlobal
,然后使用Marshal.StructureToPtr
用该结构的封送版本填充该内存。然后,您可以将该非托管内存的地址传递给非托管代码。您已经完成了对非托管代码的所有调用,请调用Marshal.PtrToStructure
以读取对该结构所做的任何修改。
也许更大的问题是,为什么在两次通话之间感到需要稳定地址。我发现很难想象这样的情况,即可以合理地期望呼叫者。您的非托管代码是否有可能因为要求调用者而获得自由?