方法: P/Invoke を使用して配列をマーシャリングする

プラットフォーム呼び出し (P/Invoke) サポートを使用する場合は、CLR 文字列型Stringを使用して C スタイルの文字列を受け入れるネイティブ関数.NET Framework呼び出すことができます。 可能な場合は、P/Invoke ではなく C++ 相互運用機能を使用することをお勧めします。 P/Invoke では、コンパイル時のエラー報告がほとんど提供されず、型セーフではなく、実装するのが面倒な場合があります。 アンマネージ API が DLL としてパッケージ化されていて、ソース コードが使用できない場合は、P/Invoke が唯一のオプションです。 それ以外の場合は、「 C++ 相互運用機能の使用 (暗黙的な P/Invoke)」を参照してください。

ネイティブ配列とマネージド配列はメモリ内でレイアウトが異なるため、マネージド/アンマネージド境界を越えて正常に渡す場合は、変換または マーシャリングが必要です。 この記事では、マネージド コードから単純な (blitable) 項目の配列をネイティブ関数に渡す方法を示します。

マネージド/アンマネージド データ マーシャリングの一般的な場合と同様に、この属性は、 DllImportAttribute 使用される各ネイティブ関数のマネージド エントリ ポイントを作成するために使用されます。 配列を引数として受け取る関数では、属性を MarshalAsAttribute 使用してデータをマーシャリングする方法を指定する必要があります。 次の例では、列挙型を UnmanagedType 使用して、マネージド配列が C スタイルの配列としてマーシャリングされることを示します。

次のコードは、アンマネージド モジュールとマネージド モジュールで構成されています。 アンマネージド モジュールは、整数の配列を受け取る関数を定義する DLL です。 2 番目のモジュールは、この関数をインポートするマネージド コマンド ライン アプリケーションですが、マネージド配列の観点から定義します。 この属性を MarshalAsAttribute 使用して、呼び出されたときに配列をネイティブ配列に変換するように指定します。

// TraditionalDll4.cpp
// compile with: /LD /EHsc
#include <iostream>

#define TRADITIONALDLL_EXPORTS
#ifdef TRADITIONALDLL_EXPORTS
#define TRADITIONALDLL_API __declspec(dllexport)
#else
#define TRADITIONALDLL_API __declspec(dllimport)
#endif

extern "C" {
   TRADITIONALDLL_API void TakesAnArray(int len, int[]);
}

void TakesAnArray(int len, int a[]) {
   printf_s("[unmanaged]\n");
   for (int i=0; i<len; i++)
      printf("%d = %d\n", i, a[i]);
}

マネージド モジュールは、次を使用 /clrしてコンパイルされます。

// MarshalBlitArray.cpp
// compile with: /clr
using namespace System;
using namespace System::Runtime::InteropServices;

value struct TraditionalDLL {
   [DllImport("TraditionalDLL4.dll")]
   static public void TakesAnArray(
   int len,[MarshalAs(UnmanagedType::LPArray)]array<int>^);
};

int main() {
   array<int>^ b = gcnew array<int>(3);
   b[0] = 11;
   b[1] = 33;
   b[2] = 55;
   TraditionalDLL::TakesAnArray(3, b);

   Console::WriteLine("[managed]");
   for (int i=0; i<3; i++)
      Console::WriteLine("{0} = {1}", i, b[i]);
}

DLL の一部は、従来 #include のディレクティブを介してマネージド コードに公開されません。 実際、DLL は実行時にのみアクセスされるため、使用 DllImportAttribute してインポートされた関数の問題はコンパイル時に検出できません。

関連項目

C++ での明示的な P/Invoke の使用 (DllImport 属性)