【发布时间】:2018-12-14 11:53:36
【问题描述】:
我有一个用 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)
以上只是简化版。您会明白,param1 在 C 中的地址在不同的调用期间会发生变化。
有没有办法解决这个问题?
谢谢。
【问题讨论】:
-
在 C 中存储该指针也是一个非常值得怀疑的做法。也许更容易逃脱,但是必须将该指针也传递给 dosomething() 就没有多大意义了。因为你已经有了指针。基于句柄的设计会更明智,init() 函数然后 返回 指针。无论如何,您必须将参数更改为 ByVal param As IntPtr 并在您的 vb.net 代码中编组结构。哎呀,如果 dosomething() 进行了更改,您必须编组回来。你实际上做了 C 代码应该做的事情,更痛苦的是因为它只是 C 中的 memcpy()。
-
@HansPassant 原始的 C 代码是遗留的,由 VB6 使用。我们正在将其升级到 VB.Net(也使用 VC++2017 重新编译 C 代码)。除非绝对必要,否则最好不要修改 C 部分,因为了解它背后的所有内存混乱需要时间,而且超出了我们的预算。我知道遗留的 C(20 多年前写的)不应该真的期望传入的内存地址总是相同的,如果在 .Net 中没有办法,那么修改 C 可能是我们唯一的解决方案。跨度>
标签: .net vb.net pinvoke marshalling