私は次のプロトタイプを持つCPPの関数を持っています:
char* complexFunction(char* arg1, ...);
DLLImport 属性を使用して C# からインポートします。質問は次のとおりです。C# で (DLLImport 属性の下で) プロトタイプを定義するにはどうすればよいですか? この関数に引数を渡すにはどうすればよいですか? ありがとう
私は次のプロトタイプを持つCPPの関数を持っています:
char* complexFunction(char* arg1, ...);
DLLImport 属性を使用して C# からインポートします。質問は次のとおりです。C# で (DLLImport 属性の下で) プロトタイプを定義するにはどうすればよいですか? この関数に引数を渡すにはどうすればよいですか? ありがとう
これを可変個関数と呼びます。それらの 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*)
。
すべてが想定されていると仮定すると、使用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);
}
}