views:

1134

answers:

2

i have a function in CPP with the following prototype:

char* complexFunction(char* arg1, ...);

i import it from a C# using DLLImport attribute. the questions are: how do i define the prototype in the C# (under the DLLImport attribute)? how do i pass the arguments to this function? thanks

+1  A: 

This is called variadic function. The information on P/Invoke support for them is rather scarce, here's what I found out.

I couldn't find a way to directly DllImport a function with variable number of arguments. I had to DllImport all variations of arguments as different overloads.

Let's take for example wsprintf. It has the following prototype in winuser.h:

int WINAPIV wsprintf(      
    LPTSTR lpOut,
    LPCTSTR lpFmt,
    ...);

It can be used from C# like this:

using System;
using System.Text;
using System.Runtime.InteropServices;

class C {

  // first overload - varargs list is single int
  [DllImport("user32.dll", CallingConvention=CallingConvention.Cdecl)]
  static extern int wsprintf(
    [Out] StringBuilder buffer,
    string format,
    int arg);

  // second overload - varargs list is (int, string)
  [DllImport("user32.dll", CallingConvention=CallingConvention.Cdecl)]
  static extern int wsprintf(
    [Out] StringBuilder buffer,
    string format,
    int arg1,
    string arg2);

  public static void Main() {
    StringBuilder buffer = new StringBuilder();
    int result = wsprintf(buffer, "%d + %s", 42, "eggs!");
    Console.WriteLine("result: {0}\n{1}", result, buffer);
  }
}

Now to address your complexFunction.

char* complexFunction(char* arg1, ...);

Its varargs list should be addressed in the same way: by providing all useful overloads. But there is also another complication - return type. I assume that complexFunction allocates and returns array of char. In this case it's most likely that the caller is responsible for array's deallocation. To allow for this you should import deallocation routine as well, let's call it void free(void*).

Assuming all that's been assumed, C# code using complexFunction would look like this:

using System;
using System.Text;
using System.Runtime.InteropServices;

class C {

  [DllImport("your.dll",
             CallingConvention=CallingConvention.Cdecl,
             CharSet=CharSet.Ansi)]
  static extern IntPtr complexFunction(
    string format,
    int arg1, int arg2);

  [DllImport("your.dll", CallingConvention=CallingConvention.Cdecl)]
  static extern void free(IntPtr p);

  public static void Main() {
    IntPtr pResult = complexFunction("%d > %s", 2, 1);
    string sResult = Marshal.PtrToStringAnsi(pResult);
    free(pResult);
    Console.WriteLine("result: {0}", sResult);
  }
}
Constantin
A: 

thanks Constantin, the prototype of the CPP function cannot be changed. it has to be extern "C" __declspec(dllexport) char* myFunc(char*, ...);

is there a way to invoke it from C# using the DLLImport?

thanks a lot!

I expanded my answer a little.
Constantin