0

現在、C#でExcelアドインを開発しており、C++ライブラリとの相互運用を使用しています。どちらも私が開発したものです。C ++ライブラリはCOMコンポーネントではなく、いくつかの関数をエクスポートするDLLにすぎません。

1つのC#関数があり、C ++関数に数値と2つの文字列を渡したいのですが、C++関数は文字列を返します。最初に文字列を直接返そうとしたので、プロトタイプは次のようになります

//C#
[return: MarshalAs(UnmanagedType.LPStr)]
private static extern string Function([MarshalAs(UnmanagedType.I4)] int number,
                                      [MarshalAs(UnmanagedType.LPStr)]string str1,
                                      [MarshalAs(UnmanagedType.LPStr)] string str2);
//C++
extern "C" __declspec(dllexport) string Function(int, char*, char*);

(ところで、私はすでにこの関数のC#の呼び出し規約をCdeclとして設定しています)

次に、C#バージョンを呼び出し、(デバッグ時に)C ++にステップインすると、パラメーターがシフトされていることがわかりました。したがって、整数は最初の文字列へのポインターの値であり、最初の文字列は2番目の文字列です。 2番目の文字列は別の場所を指しています。また、メモリを確認したところ、_cdecl規則に従ってパラメーターが渡されなかったことがわかりました。整数は、スタックにプッシュされた最後の整数でした(これは問題ありません)が、2つの文字列の位置が入れ替わっていました。コンパイラーが追加した情報は他にもたくさんあるので、これ以上深く掘り下げたくはありません。

ただし、後で戻り文字列をパラメーターとして変更すると、プロトタイプは次のようになります。

//C#
private static extern void Function([MarshalAs(UnmanagedType.I4)]int number,
                                    [MarshalAs(UnmanagedType.LPStr)] string str1,
                                    [MarshalAs(UnmanagedType.LPStr)] string str2,
                                    [MarshalAs(UnmanagedType.LPStr), Out] StringBuilder returnStr);
//C++
extern "C" __declspec(dllexport) void Function(int, char*, char*, string&);

そして今、パラメータは正しく渡されます。

だから私の最初の質問は、これはどのように起こるのですか?

2番目の質問は、2番目のメソッドを使用しても、プログラムを正しく実行できず、C ++関数から戻るときにプログラムがクラッシュしたことです(実際にはC ++関数では、クラスの別のメンバー関数を呼び出すだけです。したがって、この関数はメンバー関数のラッパーのようであり、メンバー関数に戻るときにプログラムが正確にクラッシュしました。ワーパー関数はメンバー関数を呼び出すだけなので、問題がどこにあるのかわかりません)。

誰かがこれを行う方法を知っていますか?したがって、この関数の主なポイントは、数値と2つの文字列を取得し、別の文字列を返すことです。

よろしくお願いします。

4

1 に答える 1

0

アンマネージコードでのstringbuilderの使用法に関するこの記事をご覧ください

次のようなものを試してください:

//C#
public string Function(int number, string str1, string str2)
{
    StringBuilder sbStr1 = new StringBuilder(str1);
    StringBuilder sbStr2 = new StringBuilder(str2);
    StringBuilder sbReturnStr = new StringBuilder(1024);
    Function(number, sbStr1 , sbStr2 , sbReturnStr , sbReturnStr.Capacity);
    return sbReturnStr.ToString();
}

//C# p/invoke
private static extern void Function(int number, StringBuilder str1, StringBuilder str2, StringBuilder returnStrBuffer, int size);

//C++
extern "C" __declspec (dllexport) void __stdcall Function(int number, const char* str1, const char* str2, char* returnStrBuffer, int size)
{
     //fill the returnStrBuffer
     strncpy(returnStrBuffer, "blablalb", size); //example!!
}
于 2012-08-24T08:20:17.733 に答える