I looked in to this a little bit, and the first issue seems that you pass an array into the Marshal.SizeOf
method (it is this call that throws the exception). Since all members of your structure have a fixed size, you know that all instances of that type will have the same size. So, you can instead ask Marshal.SizeOf
to return the size for one such instance:
Dim structSize As Integer = Marshal.SizeOf(GetType(dx_entry))
The next thing is that Marshal.StructureToPtr
copies the data from a structure, not an array of structures. So you will need some other way of copying your structure array to the allocated memory. There is no method that will do this for you in one call, but what you can do is to copy each of the structure instances in your array into a byte array (using the Marshal.Copy
method), and then copying that byte array to the memory pointed to by the pointer.
This is easiest to do as a two step rocket. First, let's make a method that converts the array of structures to a byte array:
Private Shared Function GetByteArray(ByVal array As dx_entry()) As Byte()
Dim structSize As Integer = Marshal.SizeOf(GetType(dx_entry))
Dim size As Integer = structSize * array.Length
Dim dataBuffer As Byte() = New Byte(size - 1) {}
For i As Integer = 0 To array.Length - 1
Dim pTemp As IntPtr = Marshal.AllocHGlobal(structSize)
Marshal.StructureToPtr(array(i), pTemp, True)
Marshal.Copy(pTemp, dataBuffer, 0 + (i * structSize), structSize)
Marshal.FreeHGlobal(pTemp)
Next
Return dataBuffer
End Function
Second, use the GetByteArray
method and copy the returned byte array to the memory pointed to by the pointer:
Dim data As Byte() = GetByteArray(stpDx)
Dim pDxBuf As IntPtr = Marshal.AllocHGlobal(data.Length)
Marshal.Copy(data, 0, pDxBuf, data.Length)
ezg_Block.pDx = pDxBuf
I hope that does what you are looking for...
As a side note; since you in your structure have specified the fixed size for each of the fields, you don't need to pad the values with spaces in your code; this is taken care of by the framework when marshalling your data.
Update
To read the data back, you basically need to do the same thing, but backwards:
Private Shared Function GetStructArray(ByVal dataBuffer() As Byte) As dx_entry()
Dim structSize As Integer = Marshal.SizeOf(GetType(dx_entry))
If dataBuffer.Length Mod structSize <> 0 Then
Throw New ArgumentException("Argument is of wrong length", "dataBuffer")
End If
Dim elementCount As Integer = Convert.ToInt32(dataBuffer.Length / structSize)
Dim size As Integer = structSize * elementCount
Dim result() As dx_entry = New dx_entry(elementCount - 1) {}
For i As Integer = 0 To elementCount - 1
Dim pTemp As IntPtr = Marshal.AllocHGlobal(structSize)
Marshal.Copy(dataBuffer, 0 + (i * structSize), pTemp, structSize)
result(i) = DirectCast(Marshal.PtrToStructure(pTemp, GetType(dx_entry)), dx_entry)
Marshal.FreeHGlobal(pTemp)
Next
Return result
End Function
Called like that:
Dim structSize As Integer = Marshal.SizeOf(GetType(dx_entry))
Dim newdata() As Byte = New Byte(structSize * numberOfElements -1) {}
Marshal.Copy(ezg_Block.pDx, newdata, 0, newdata.Length)
Dim newstruct() As dx_entry = GetStructArray(data)
Note: To get all this to work properly, you will need to tweak the structure a bit: it seems you need to increase the SizeConst by 1. This is since the strings are null-terminated, so there need to be a position for the null byte as well:
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
Public Structure dx_entry
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=11)> _
Public dx As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=4)> _
Public type As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=2)> _
Public narray As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=2)> _
Public ctier As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=2)> _
Public poa As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=2)> _
Public poa_rsvd As String
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=82)> _
Public filler As String
End Structure