방법: P/Invoke를 사용하여 포함된 포인터 마샬링

관리되지 않는 DLL에서 구현되는 함수는 P/Invoke(Platform Invoke) 기능을 사용하여 관리 코드에서 호출할 수 있습니다. DLL에 대한 소스 코드를 사용할 수 없는 경우 P/Invoke만 상호 운용할 수 있습니다. 그러나 다른 .NET 언어와 달리 Visual C++는 P/Invoke에 대한 대안을 제공합니다. 자세한 내용은 C++ Interop 사용(암시적 P/Invoke)방법: C++ Interop을 사용하여 포함된 포인터 마샬링을 참조하세요.

예시

네이티브 코드에 구조를 전달하려면 네이티브 구조에 대한 데이터 레이아웃과 동일한 관리되는 구조가 만들어집니다. 그러나 포인터를 포함하는 구조에는 특별한 처리가 필요합니다. 네이티브 구조의 포함된 각 포인터에 대해 구조체의 관리되는 버전에는 형식의 인스턴스가 IntPtr 포함되어야 합니다. 또한 이러한 인스턴스에 대한 메모리는 , 및 메서드를 사용하여 AllocCoTaskMemStructureToPtr명시적으로 할당, 초기화 및 FreeCoTaskMem 해제되어야 합니다.

다음 코드는 관리되지 않는 모듈과 관리되는 모듈로 구성됩니다. 관리되지 않는 모듈은 포인터를 포함하는 구조체를 허용하는 함수와 호출 ListStringTakesListStruct된 함수를 정의하는 DLL입니다.

// 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]);
}

관리되는 모듈은 함수를 TakesListStruct 가져오고 인스턴스로 표현 IntPtr 된다는 점을 제외하고 double* 네이티브 ListStruct 와 동일한 구조체를 MListStruct 정의하는 명령줄 애플리케이션입니다. 함수는 main 호출TakesListStruct하기 전에 이 필드에서 참조하는 메모리를 할당하고 초기화합니다.

// 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);
}

기존 #include 지시문을 사용하여 관리 코드에 DLL 부분이 노출되지 않습니다. 실제로 DLL은 런타임에만 액세스되므로 컴파일 시간에 사용하여 DllImportAttribute 가져온 함수의 문제를 검색할 수 없습니다.

참고 항목

C++에서 명시적 P/Invoke 사용(DllImport 특성)