如何:使用 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 匯入的函式問題。
另請參閱
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應