1

Possible Duplicate:
unsigned char ** equivalent in c# and have to write the return value in a file

I have to call a win32 dll function

int func1(int arg1, unsigned char *arg2, int *arg3);

and i wrote wrapped c# as

public extern int fuc1(int arg1, out IntPtr arg2, out IntPtr arg3);

The arg2 has to allocate 2048 bytes and send it to the win32 dll. I'll get arg2 and arg3 as output.

how can i declare in c# test application as well as c# wrapper. am i doing it right ?

Community
  • 1
  • 1
Narayan
  • 1,189
  • 6
  • 15
  • 33

2 Answers2

4

byte in C# is unsigned 8-bit int. byte[] is an array of them. To get a pointer to this array, use:

 var myArray = new byte[2048];
 fixed(byte* arg2 = myArray)
 {
      // use arg2
 }

or:

 var myArray = new byte[2048];
 GCHandle pinnedRawData = GCHandle.Alloc(myArray, GCHandleType.Pinned);
 try
 {  
    // Get the address of the data array
    IntPtr pinnedRawDataPtr = pinnedRawData.AddrOfPinnedObject();
 }
 finally
 {
    // must explicitly release
    pinnedRawData.Free(); 
 } 

Alternatively, if the called function will not cache a pointer to the array, you can simply do this:

 public static extern int fuc1(int arg1, [In,Out] byte[] arg2, ref int arg3);

 var arg1 = 0;
 var arg2 = new byte[2048];
 int arg3 = 42; // If this value won't be used, you can skip initializing arg3 and mark arg3 as out instead of ref (of course, this is pedantic and extraneous, and C# shouldn't even have 'out' as a keyword)

 func1(arg1, arg2, ref arg3);

P/Invoke will pin it automatically.

MSDN Marshaling Arrays of Types

Related SO question

Community
  • 1
  • 1
Aleksandr Dubinsky
  • 22,436
  • 15
  • 82
  • 99
1

Declare the function in C# like this:

[DllImport(@"MyDll.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern int func1(
    int arg1, 
    StringBuilder arg2, 
    out int arg3
);

And then call it like this:

int arg1 = ...;
StringBuilder sb = new StringBuilder(2048);
int arg3;
int retVal = func1(arg1, sb, out arg3);
string arg2 = sb.ToString();

Note that C# IntPtr does not match C int. You need C# int to match that because IntPtr is the same size as a pointer, either 32 or 64 bits. But int is always 4 bytes.

I am assuming that your DLL uses the cdecl calling convention. If you are using stdcall, you can make the obvious alteration.

I also assumed that your data is in fact text data. If it is just a plain old byte array then the code is simpler.

[DllImport(@"MyDll.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern int func1(
    int arg1, 
    byte[] arg2, 
    out int arg3
);

And then to call:

int arg1 = ...;
byte[] arg2 = new byte[2048];
int arg3;
int retVal = func1(arg1, arg2, out arg3);
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490