方法: P/Invoke を使用して配列をマーシャリングする
.NET Framework プラットフォーム呼び出し (P/Invoke) のサポートを使用する場合は、
例
ネイティブ配列とマネージド配列はメモリ内でレイアウトが異なるため、マネージド/アンマネージド境界を越えて正常に渡すためには、変換または marshalingが必要です。 この記事では、マネージド コードから単純な (blitable) 項目の配列をネイティブ関数に渡す方法について説明します。
マネージド/アンマネージド データ マーシャリングの一般的な場合と同様に、 DllImportAttribute 属性は、使用される各ネイティブ関数のマネージド エントリ ポイントを作成するために使用されます。 配列を引数として受け取る関数では、 MarshalAsAttribute 属性を使用してデータをマーシャリングする方法を指定する必要があります。 次の例では、マネージド配列が C スタイルの配列としてマーシャリングされることを示すために、 UnmanagedType 列挙体を使用します。
次のコードは、アンマネージド モジュールとマネージド モジュールで構成されています。 アンマネージド モジュールは、整数の配列を受け取る関数を定義する 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 を使用してインポートされた関数の問題はコンパイル時に検出できません。