2013-01-16 5 views
6

ネイティブDLLからエクスポートされた以下のような純粋-Cインタフェースを備えたネイティブ関数があると仮定する:マーシャル配列のP/Invoke [In、Out]属性はオプションですか?

// NativeDll.cpp 

extern "C" void __stdcall FillArray(
    int fillValue, 
    int count, 
    int* data) 
{ 
    // Assume parameters are OK... 

    // Fill the array 
    for (int i = 0; i < count; i++) 
    { 
     data[i] = fillValue; 
    } 
} 

次のP /呼び出しは、(VS2010 SP1で試験)正常に動作:

[DllImport("NativeDll.dll", CallingConvention=CallingConvention.StdCall)] 
public static extern void FillArray(
    int fillValue, 
    int count, 
    [In, Out] int[] data 
); 

ならびに上記同様、このP /呼び出し、が、[In, Out]せずは属性:

[DllImport("NativeDll.dll", CallingConvention=CallingConvention.StdCall)] 
public static extern void FillArray(
    int fillValue, 
    int count, 
    int[] data 
); 

[In, Out]アトリビュートアライメントアレイの場合はですか? その目的は何ですか? P/Invoke宣言でそれらを省略することはできますか?

答えて

16

いいえ、彼らは正確にではありません。それはちょうど偶然に起こる。しかし、それは非常に一般的な事故です。これは配列が実際にマーシャリングされないために機能します。 pinvoke marshallerは、C#配列がネイティブ配列と互換性があることを確認して、そのステップをスキップしてそのコピーを作成します。単に配列を固定し、ポインタをネイティブコードに渡します。

これはもちろん非常に効率的です。ネイティブコードが配列要素を直接書き込んでいるため、必然的に結果が返されます。したがって、[In]属性も[Out]属性も重要ではありません。

配列要素の型がそれほど単純でない場合は、それほど暗くなります。 blitableではない構造体またはクラス型の要素型を識別するのは簡単ではないので、整列化後にピンボケ・マーシャラーにはがあり、配列のコピーを作成できます。特に、レイアウトの非互換性はと非常にとなります。これは、管理レイアウトが発見できないためです。使用されるジッタに応じて変更することができます。 x86では動作しますが、x64では動作しない可能性があります。AnyCPUが選択されているとかなり厄介です。変更されたコピーをC#配列にコピーするには、に[Out]が必要です。

宣言に明示的に言い表されていたために解雇された人以外は、何をアドバイスするか分かりません。おそらく、配列要素の型がシンプルではないので、事故を起こすことはないでしょう。

+1

私は人生の多くの時間をx86/x64/'Any CPU'の間のマーシャリングエフェクトのトラブルシューティングに費やしました... – JerKimball

関連する問題