Modifying a C struct in VB.NET

1.1k views Asked by At

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?

0

There are 0 answers