いくつかのC#からWin32DLLを呼び出そうとしています。DLL関数は次のように宣言されています。
extern "C" __declspec(dllexport) UINT foo(TCHAR** list[], int& listSize, TCHAR* error);
C#では、次のように外部関数を宣言します。
[DllImport("foo.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
static extern uint foo(StringBuilder[] list, ref int listSize, StringBuilder error);
私の問題は、StringBuilderクラスの配列であるlistパラメーターに関係しています。
DLL関数を呼び出すいくつかのテストコードは次のとおりです(注:境界チェックが欠落しているなどのことに気づきました。この段階では、物事を機能させようとしています)。
// allocate a buffer for a possible error message being returned
StringBuilder error = new StringBuilder(1000);
// allocate buffers for the list of strings returned
StringBuilder[] list = new StringBuilder[10];
for (int i = 0; i < 10; i++)
{
list[i] = new StringBuilder(1000);
}
int listSize = list.Length;
uint result = foo(list, ref listSize, error);
StringBuilderをエラーパラメータのバッファとして渡すと、正常に機能します。DLLの内容を次のように設定できます。
_tcscpy(error, _T("Something went wrong");
fooへのC#呼び出しが返されると、文字列エラー変数には、DLLで設定したテキストが含まれます。
しかし、StringBuilder[]リストパラメーターをマーシャリングする方法を理解できません。
C ++では、リスト配列の内容を設定できます。
_tcscpy((*list)[0], _T("First item"));
// and so on...
また、問題のあるマーシャリングが原因でクラッシュが発生することはありませんが、 foo()の呼び出しが返されるとき、C#のリストには、C++で設定した文字列が含まれていません。
問題はDllImportにあり、リストパラメータをどのように宣言したかをマーシャリングする必要があると推測しています。
ちなみに、サンプルDLLには、上記のサンプルfooによって返される「TCHAR**リスト」の割り当てを解除するために呼び出すマッチング関数があります。