C#使用CPP中未知数量的args调用CPP函数

时间:2008-10-18 11:56:05

标签: c# c++ interop pinvoke variadic-functions

我在CPP中有一个函数,其中包含以下原型:

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

我使用DLLImport属性从C#导入它。 问题是: 我如何在C#中定义原型(在DLLImport属性下)? 我如何将参数传递给这个函数? 感谢

1 个答案:

答案 0 :(得分:3)

这称为可变函数。 P / Invoke对它们的支持信息相当稀少,这就是我发现的。

我找不到直接DllImport具有可变数量参数的函数的方法。我不得不将DllImport 参数的所有变体作为不同的重载。

我们以wsprintf为例。它在winuser.h中有以下原型:

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

它可以像C#一样在C#中使用:

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);
  }
}

现在解决您的complexFunction

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

它的varargs列表应该以相同的方式解决:提供所有有用的重载。但是还有另一种并发症 - 返回类型。我假设complexFunction分配并返回char的数组。在这种情况下,调用者最有可能负责数组的释放。为此,您还应该导入释放例程,我们称之为void free(void*)

假设已经假设了所有内容,使用complexFunction的C#代码将如下所示:

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);
  }
}