如何:使用 P/Invoke 封送處理陣列
您可以使用 .NET Framework Platform Invoke (P/Invoke) 支援時,使用 CLR 字串串類型 String 呼叫接受 C 樣式字符串的原生函式。 建議您盡可能使用 C++ Interop 功能,而不是 P/Invoke。 P/Invoke 提供很少的編譯時間錯誤報告、不是類型安全,而且可能很繁瑣來實作。 如果 Unmanaged API 封裝為 DLL 且原始碼無法使用,P/Invoke 是唯一的選項。 否則,請參閱 使用 C++ Interop (隱含 P/Invoke))。
範例
由於原生和Managed數位在記憶體中配置的方式不同,因此成功跨 Managed/Unmanaged 界限傳遞這些數位需要轉換或 封送處理。 本文示範如何從 Managed 程式代碼將簡單項目陣列傳遞至原生函式。
一般而言,Managed/Unmanaged 數據封送處理也是如此, DllImportAttribute 屬性是用來為每個使用的原生函式建立受控進入點。 在採用數位作為自變數的函式中, MarshalAsAttribute 必須使用 屬性來指定如何封送處理數據。 在下列範例中 UnmanagedType ,列舉可用來表示 Managed 陣列會封送處理為 C 樣式陣列。
下列程式代碼包含 Unmanaged 和 Managed 模組。 Unmanaged 模組是 DLL,定義接受整數數位列的函式。 第二個模組是匯入此函式的 Managed 命令行應用程式,但以 Managed 陣列來定義它。 它會使用 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
指示詞向Managed程式碼公開。 事實上,由於 DLL 只會在運行時間存取,因此無法在編譯時期偵測使用 DllImportAttribute 匯入的函式問題。