C # вызывает функцию CPP с неизвестным числом аргументов из CPP - PullRequest
3 голосов
/ 18 октября 2008

У меня есть функция в CPP со следующим прототипом:

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

Я импортирую его из C #, используя атрибут DLLImport. вопросы: Как определить прототип в C # (под атрибутом DLLImport)? как передать аргументы этой функции? спасибо

1 Ответ

3 голосов
/ 18 октября 2008

Это называется вариадной функцией. Информация о поддержке P / Invoke для них довольно скудна, вот что я узнал.

Я не смог найти способ напрямую DllImport функции с переменным числом аргументов. Мне пришлось DllImport все варианты аргументов как различные перегрузки.

Давайте возьмем для примера wsprintf . Имеет следующий прототип в winuser.h:

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

Может использоваться из 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*).

Предполагая, что все, что предполагалось, код C # с использованием complexFunction будет выглядеть так:

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