11

私は、C ++ APIでいくつかの関数を呼び出す小さなC#アプリを書いています。DLLにC++コードを組み込み、C#コードはDllImportを使用してAPIを呼び出します。(私はC ++ DLLに.DEFファイルを使用しているので、extern "C"は必要ありません。)

これまでのところ、APIには1つの関数がありますが、現在はまったく何もしていません。

bool Foo()
{
  return false;
}

C#では、次のものがあります。

public class FooAPI
{
    [DllImport("Foo.dll")]
    public static extern bool Foo();
}

...

bool b = FooAPI.Foo(); 
if (!b) 
{ 
    // Throw an exception 
} 

私の問題は、何らかの理由で、bが常にTRUEと評価されていることです。if(!b)にブレークポイントがあり、デバッガーはそれを「true」として報告します。これは、C++関数が返すものとは関係ありません。

C#ブール値はC ++ブール値と同じですか?そうでない場合でも、戻り値が「true」であるとどのように検出されるかはわかりません:)

誰かがこの奇妙な矛盾を手伝ってくれる?

前もって感謝します!

4

3 に答える 3

16

試してみてください[return: MarshalAs (UnmanagedType.I1)]。デフォルトでは、C# 相互運用機能はC#を Win32 としてマーシャリングboolBOOLします。これは と同じですがint、C++boolは 1 バイト AFAIR です。したがって、C# の既定のマーシャリングでは、戻り値がレジスタBOOL内の a であることが想定され、C++が で返されるeaxため、ゼロ以外のガベージがいくつかピックアップされます。boolal

于 2009-11-24T20:31:02.157 に答える
3

投稿されたコード スニペットは機能しません。これが C++ コンパイラでコンパイルされた場合、関数名は ?Foo@@YA_NXZ になり、C# コードはそれを見つけることができません。呼び出し規約も重要です。コンパイラに指示しない限り、既定 (CallingConvention.StdCall) ではありません。そしてどこかで、リンカーに関数をエクスポートするように指示する必要があります。

デフォルトの P/Invoke 属性と互換性があるように、エクスポートされた関数を宣言することから始めます。

extern "C" __declspec(dllexport) 
bool __stdcall Foo() {
    return false;
}

次の問題は、C++ コンパイラが bool を格納するために 1 バイトしか使用しないことです。return ステートメント用に生成されたマシン コードは次のとおりです。

013D138E  xor         al,al

ただし、P/Invoke マーシャラーは、それが 32 ビット整数であると想定し、eax レジスターの値をチェックします。関数の戻り値の型を int または BOOL として宣言するか、C# 宣言で [return: MarshalAs(UnmanagedType.U1)] 属性を使用します。

于 2009-11-24T20:22:31.347 に答える