22

Example C API signature:

void Func(unsigned char* bytes);

In C, when I want to pass a pointer to an array, I can do:

unsigned char* bytes = new unsigned char[1000];
Func(bytes); // call

How do I translate the above API to P/Invoke such that I can pass a pointer to C# byte array?

GEOCHET
  • 21,119
  • 15
  • 74
  • 98
Randy Sugianto 'Yuku'
  • 71,383
  • 57
  • 178
  • 228

3 Answers3

34

The easiest way to pass an array of bytes is to declare the parameter in your import statement as a byte array.

[DllImport EntryPoint="func" CharSet=CharSet.Auto, SetLastError=true]
public extern static void Func(byte[]);

byte[] ar = new byte[1000];
Func(ar);

You should also be able to declare the parameter as an IntPtr and Marshal the data manually.

[DllImport EntryPoint="func" CharSet=CharSet.Auto, SetLastError=true]
public extern static void Func(IntPtr p);

byte[] ar = new byte[1000];
IntPtr p = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(byte)) * ar.Length);
Marshal.Copy(ar, 0, p, ar.Length);
Func(p);
Marshal.FreeHGlobal(p);
asponge
  • 636
  • 5
  • 8
  • why would the first approach work, and the second not work. This is what i'm facing on a windows phone app. –  Nov 18 '14 at 15:29
  • 1
    I know this post is a little old but `Marshal.SizeOf(object)` does not work with arrays. I am pretty sure you will get an exception if you pass it an array but I do not have VS open in front of me right now to try. To correctly determine the size of an array, for your example the code would be `Marshal.SizeOf(typeof(byte)) * ar.Length`. – 9ee1 Mar 02 '15 at 06:44
  • 1
    Yes, you're right 9ee1. Marshal.SizeOf can be used for a structure but not an array. I've updated the example code accordingly. Thanks. – asponge Mar 18 '15 at 13:34
7

You can use unsafe code:

unsafe 
{
     fixed(byte* pByte = byteArray)
     IntPtr intPtr = new IntPtr((void *) pByte);
     Func(intPtr);
}

If you need to use safe code, you can use a few tricks:

IntPtr intPtr = Marshal.AllocHGlobal(Marshal.SizeOf(byteArray));
Marshal.Copy(byteArray, 0, intPtr, Marshal.SizeOf(byteArray));

Func(intPtr);

Marshal.FreeHGlobal(intPtr);

However, the safe code is going to be slow IMHO.

FlySwat
  • 172,459
  • 74
  • 246
  • 311
4

Here is the appropriate signature for the native function.

[System.Runtime.InteropServices.DllImportAttribute("<Unknown>", EntryPoint="Func")]
public static extern  void Func(System.IntPtr bytes) ;
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454