共用方式為


如何:使用 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 匯入的函式問題。

另請參閱

在 C++ 中使用明確的 P/Invoke ( DllImport 屬性)