16

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?

user1219801
  • 169
  • 4
  • 17
Messias
  • 161
  • 3
  • 1
    The code is fairly hacked to death, but it just takes Marshal.StructureToPtr(report, lpReport, False). Exactly what the C function pointer looks like is important. – Hans Passant Nov 11 '14 at 19:01
  • Hi, yes i also tried Marshal.StructureToPtr(report, lpReport, False) but it fails as well at runtime when the functions end with the same error message. Additional information: Attempted to read or write protected memory. 'This is often an indication that other memory is corrupt.' – Messias Nov 11 '14 at 22:01
  • according to the author of the dll the c function pointer is `typedef uint8_t (_stdcall *API_Read)(REPORT *);` `API_Read Read=NULL;` `REPORT report;` `Read(&report);` – Messias Nov 11 '14 at 22:11
  • There's nothing wrong. You need support from the author, send him a small repro project. – Hans Passant Nov 11 '14 at 22:15
  • yes i will send him one. the code works, or seems to work (just tested it for a few seconds) if i don't use Marshal.StructureToPtr(...) and manually copy the structure to the array of bytes, and then copy the array of bytes to lpReport. but will have to calculate the offsets manually. the C dll is allocating the report structure in the stack, maybe thats why Marshal.StructureToPtr complains after the function ends... i cant seem to find the Marshal.StructureToPtr implementation using ILSPy the code just says external but doesnt says where the code is for analysis. – Messias Nov 11 '14 at 22:28
  • 2
    sorry guys i have fix it, code is good as Hans Passant suggested, the problem was with another bad delegate callback declaration that are being called right after Read() returns to C DLL, sorry for waisting your time. – Messias Nov 11 '14 at 23:51
  • 2
    I'm voting to close this question as off-topic because author says problem was due to a defect. See author's comment "sorry guys i have fix it, code is good as Hans Passant suggested, the problem was with another bad delegate callback declaration that are being called right after Read() returns to C DLL, sorry for waisting your time. – Messias Nov 11 '14 at 23:51" – Richard Chambers May 20 '16 at 02:49

0 Answers0