2

I'm trying to write a wrapper for C library but I'm really struggling with this error.

I tried many approaches, here is one of them:

    [DllImport(DRIVER_FILENAME)]
    [return: MarshalAs(UnmanagedType.U4)]
    private static extern uint GetData(IntPtr handle,
        [MarshalAs(UnmanagedType.LPArray), In()] int[] buffer,
        [MarshalAs(UnmanagedType.U4)] uint size);

Here is function GetData from the library documentation:

LONG GetData( 
  IN HANDLE Handle,
  OUT PULONG Buffer, 
  IN ULONG Size
); 

Function returns continuous data (about 16KB/s) in buffer which size is given in bytes. Buffer is int[16384]. My code looks like this:

public static uint GetLibData(IntPtr handle, int[] buffer, uint size)
    {
        size *= 4;            
        uint sizeRead = GetData(handle, buffer, size);

        sizeRead /= 4;

        return sizeRead;
    }

Problematic argument is buffer, I tried manage it previously in other ways, such as IntPtr bufferPtr and then allocating memory by Marshal.AllocHGlobal but I was getting the same error:

Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

How to correctly invoke this function?

msu
  • 75
  • 3
  • 9
  • You didn't specify the CallingConvention, good odds it is Cdecl. – Hans Passant Jan 18 '13 at 14:18
  • @HansPassant: thanks. I've just tried all possible coventions but none of them changed this error ("_Attempted to read or write protected memory. This is often an indication that other memory is corrupt._") – msu Jan 18 '13 at 17:54
  • 1
    You'll need to start debugging the C code to narrow down why it crashed. If you don't have it then ask for help from the owner. – Hans Passant Jan 18 '13 at 17:57
  • Attach native debugger to see what is going on. – leppie Jan 18 '13 at 17:58

2 Answers2

1

The appropriate p/invoke declaration is

[DllImport(DRIVER_FILENAME)]
private static extern uint GetData(
    IntPtr handle,
    [Out] uint[] buffer,
    uint size
);

It is your responsibility to allocate the buffer before you call the function:

uint[] buffer = new uint[16384];
uint bufferSize = buffer.Length*Marshal.SizeOf(typeof(uint));
uint sizeRead = GetData(handle, buffer, bufferSize);
uint lenRead = sizeRead/Marshal.SizeOf(typeof(uint));

The only thing that's not 100% clear is the calling convention. I'd guess that this library uses cdecl which would mean your DllImport should be

[DllImport(DRIVER_FILENAME, CallingConvention=CallingConvention.Cdecl)]
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
0

Try with the following PInvoke:

[DllImport(DRIVER_FILENAME)]
private static extern Int32 GetData
(
    [In] IntPtr handle,
    [Out] out IntPtr buffer,
    [In] UInt32 size
);
Tommaso Belluzzo
  • 23,232
  • 8
  • 74
  • 98
  • The second parameter is `PULONG`. That's a point to `uint` passed by value. So, one fewer levels of indirection than in your answer. – David Heffernan Jan 18 '13 at 20:50