I'm trying to call a DLL function (written in C) that expects a pointer to an Outer structure, which in turn contains an array of Inner structures. The C structures look like this:
typedef struct Inner {
int x;
int y;
} Inner;
typedef struct Outer {
Inner ArrayOfInners[20];
unsigned char b;
} Outer;
I defined the VB.NET structures as follows:
<StructLayout(LayoutKind.Sequential)> _
Public Structure Inner
Public x As Integer
Public y As Integer
End Structure
<StructLayout(LayoutKind.Sequential)> _
Public Structure Outer
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=20)> Public ArrayOfInners() As Inner
Public b As Byte
End Structure
However, when I instantiate an Outer and try to access the nested Inner array like this ...
Dim s As Outer
s.ArrayOfInners(2).x = 5
... the VS editor complains Variable 'ArrayOfInners' is used before it has been assigned a value. A null reference exception could result at runtime. And indeed, at runtime I see that the value of s.ArrayOfInners
is Nothing
-- vs. what I expected: a nested array of Inner structures.
What's the problem here, and how can I instantiate an Outer structure that's compatible with the DLL?
In case someone else runs into this issue, here's the solution (thanks to user Ry):
Dim s As Outer
s.ArrayOfInners = New Inner(19) {} ' Must manually create every array in structure!
s.ArrayOfInners(2).x = 5
Apparently it's necessary to explicitly create every array within s
because the .NET structure s
is not what is passed to the DLL function. Instead, when the DLL function is called, VB will automatically allocate memory for a DLL-compatible struct and then copy all of s
's members (including its referenced, non-contiguous ArrayOfInners
) to the struct. The struct is passed to the DLL function and, when the function returns, VB will copy all of the struct's members back to s
.
VB.NET cannot do these scatter/gather operations unless ArrayOfInners
has first been explicitly created, because Dim s As Outer
only initializes ArrayOfInners
to Nothing
(effectively a NULL pointer), and it's not possible to copy Nothing
to/from a DLL-compatible struct.