共用方式為


如何:使用 P/Invoke 封送處理內嵌指標

在 Unmanaged DLL 中實作的函式可以使用平台叫用 (P/Invoke) 功能,從 Managed 程式碼呼叫。 如果 DLL 的原始程式碼無法使用,P/Invoke 是交互操作的唯一選項。 不過,與其他 .NET 語言不同,Visual C++ 提供 P/Invoke 的替代方案。 如需詳細資訊,請參閱 使用 C++ Interop (隱含 P/Invoke) 如何:使用 C++ Interop 封送處理內嵌指標。

範例

將結構傳遞至原生程式碼時,需要建立與原生結構的資料配置相等的 Managed 結構。 不過,包含指標的結構需要特殊處理。 針對原生結構中的每個內嵌指標,結構的 Managed 版本應該包含 類型的實例 IntPtr 。 此外,這些實例的記憶體必須使用 、 StructureToPtrFreeCoTaskMem 方法明確配置、初始化和釋放 AllocCoTaskMem

下列程式碼包含 Unmanaged 和 Managed 模組。 Unmanaged 模組是一個 DLL,定義可接受包含指標之結構的 ListString 函式,以及稱為 TakesListStruct 的函式。

// TraditionalDll6.cpp
// compile with: /EHsc /LD
#include <stdio.h>
#include <iostream>
#define TRADITIONALDLL_EXPORTS
#ifdef TRADITIONALDLL_EXPORTS
#define TRADITIONALDLL_API __declspec(dllexport)
#else
#define TRADITIONALDLL_API __declspec(dllimport)
#endif

#pragma pack(push, 8)
struct ListStruct {
   int count;
   double* item;
};
#pragma pack(pop)

extern "C" {
   TRADITIONALDLL_API void TakesListStruct(ListStruct);
}

void TakesListStruct(ListStruct list) {
   printf_s("[unmanaged] count = %d\n", list.count);
   for (int i=0; i<list.count; i++)
      printf_s("array[%d] = %f\n", i, list.item[i]);
}

Managed 模組是命令列應用程式,會匯 TakesListStruct 入函式,並定義稱為 MListStruct 的 結構,其與原生 ListStruct 相等,但 實例所 IntPtr 表示的 除外 double* 。 在呼叫 TakesListStruct 之前,函 main 式會配置並初始化此欄位所參考的記憶體。

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

[StructLayout(LayoutKind::Sequential, Pack=8)]
value struct MListStruct {
   int count;
   IntPtr item;
};

value struct TraditionalDLL {
    [DllImport("TraditionalDLL6.dll")]
   static public void TakesListStruct(MListStruct);
};

int main() {
   array<double>^ parray = gcnew array<double>(10);
   Console::WriteLine("[managed] count = {0}", parray->Length);

   Random^ r = gcnew Random();
   for (int i=0; i<parray->Length; i++) {
      parray[i] = r->NextDouble() * 100.0;
      Console::WriteLine("array[{0}] = {1}", i, parray[i]);
   }

   int size = Marshal::SizeOf(double::typeid);
   MListStruct list;
   list.count = parray->Length;
   list.item = Marshal::AllocCoTaskMem(size * parray->Length);

   for (int i=0; i<parray->Length; i++) {
      IntPtr t = IntPtr(list.item.ToInt32() + i * size);
      Marshal::StructureToPtr(parray[i], t, false);
   }

   TraditionalDLL::TakesListStruct( list );
   Marshal::FreeCoTaskMem(list.item);
}

DLL 的一部分不會使用傳統 #include 指示詞向 Managed 程式碼公開。 事實上,DLL 只會在執行時間存取,因此無法在編譯時期偵測使用 DllImportAttribute 匯入的函式問題。

另請參閱

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