I'm trying to use someone else's DLL coded in C in my VB.NET application. My VB.NET application sends some callbacks pointers to the DLL and DLL then calls back to functions inside my VB.NET application.
The DLL is calling a function inside VB.NET and passing a pointer of a C struct. My VB.NET application has to modify the struct values, so the DLL can work with the new struct values. I can't modify the DLL's code because it is someone else's DLL.
typedef struct {
uint8_t index;
uint8_t value;
uint8_t leds[4];
struct {
int8_t x;
int8_t y;
int8_t z;
} input[10];
} REPORT;
My VB.NET structure definition is
<StructLayout(LayoutKind.Sequential)> _
Public Structure INPUTS
Public x As SByte
Public y As SByte
Public z As SByte
End Structure
<StructLayout(LayoutKind.Sequential)> _
Public Structure REPORT
Public index As Byte
Public value As Byte
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=4)>
Public leds() As Byte
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=10)>
Public input() As INPUTS
Sub New(numleds As Integer, numinputs As Integer)
ReDim Me.leds(numleds)
ReDim Me.input(numinputs)
End Sub
End Structure
My VB.NET delegate is declared as
Public Delegate Function Del_Read(ByVal lpReport As IntPtr) As Byte
vb.net sends vb.net delegate to C DLL
Public Ext_Read As Del_Read = New Del_Read(AddressOf Read)
SendToDll(Marshal.GetFunctionPointerForDelegate(Ext_Read))
My VB.NET function is declared as
Public Function Read(ByVal lpReport As IntPtr) As Byte
Dim report As New REPORT(3, 9)
report.index = 0
report.value = 5
report.input(0).x = 90
report.input(0).y = 0
report.input(0).z = 0
report.input(1).x = 180
report.input(1).y = 0
report.input(1).z = 0
Dim size As Integer = Marshal.SizeOf(report)
Dim ptrMem As IntPtr = Marshal.AllocCoTaskMem(size)
Marshal.StructureToPtr(report, ptrMem, False)
Dim bytes As Byte() = New Byte(size - 1) {}
Marshal.Copy(ptrMem, bytes, 0, bytes.Length)
Marshal.FreeCoTaskMem(ptrMem)
Marshal.Copy(bytes, 0, lpReport, size)
Return 1
End Function
I get the following error when the function ends and nothing else.
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
I have tried different codes, like Marshal.AllocHGlobal
or declaring the function as
Public Function Read(ByRef localReport As REPORT) As Byte
Even though the code compiles just fine, the error is because of Marshal.StructureToPtr somehow, because if I change the code to the one as below, I get no errors and the DLL obtains the new values. The only problem is that I have to calculate manually the offsets for report.input(0)
, report.input(1)
, etc.
Public Function Read(ByVal lpReport As IntPtr) As Byte
Dim report As New REPORT(3, 9)
report.index = 0
report.value = 5
Dim size As Integer = Marshal.SizeOf(report)
Dim bytes As Byte() = New Byte(size - 1) {}
bytes(0) = report.index
bytes(1) = report.value
Marshal.Copy(bytes, 0, lpReport, size)
Return 1
End Function
Any ideas why the code fails? Or a simpler way to modify the structure sent from the DLL?