2

いくつかの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**リスト」の割り当てを解除するために呼び出すマッチング関数があります。

4

2 に答える 2

0

私はしばらくこれをしていませんが、配列リストを正しくマーシャリングするために次のことを試してみてください:

リスト[MarshalAs(UnmanagedType.LPArray, ArraySubType.LPTStr, SizeParamIndex=1)]に 属性を追加し ます。データはC++コードで割り当てられるため、を追加する必要があります。out

于 2013-01-28T13:17:46.500 に答える
0

OK、質問の解決策を見つけました。答えはIntPtrにあるようです。C関数は、「TCHAR **list[]」に文字列の配列を作成して返しました。

まず、C#の宣言を次のように変更しました。

[DllImport("foo.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
static extern uint foo(out IntPtr[] list, ref int listSize, StringBuilder error);

次に、DLLの呼び出しが戻ったときに、配列から文字列を抽出する必要がありました。

string[] returnedList = new string[listSize];
IntPtr[] ptrArray = new IntPtr[listSize];

Marshal.Copy(list, ptrArray, 0, listSize);

for (int i = 0; i < listSize; i++)
{
    returnedList[i] = Marshal.PtrToStringAuto(ptrArray[i]);
}

その結果、CDLLから文字列の配列が返されました。

于 2013-01-29T12:18:22.680 に答える