방법: P/Invoke를 사용하여 포함된 포인터 마샬링
관리되지 않는 DLL에서 구현되는 함수는 P/Invoke(Platform Invoke) 기능을 사용하여 관리 코드에서 호출할 수 있습니다. DLL에 대한 소스 코드를 사용할 수 없는 경우 P/Invoke만 상호 운용할 수 있습니다. 그러나 다른 .NET 언어와 달리 Visual C++는 P/Invoke에 대한 대안을 제공합니다. 자세한 내용은 C++ Interop 사용(암시적 P/Invoke) 및 방법: C++ Interop을 사용하여 포함된 포인터 마샬링을 참조하세요.
예시
네이티브 코드에 구조를 전달하려면 네이티브 구조에 대한 데이터 레이아웃과 동일한 관리되는 구조가 만들어집니다. 그러나 포인터를 포함하는 구조에는 특별한 처리가 필요합니다. 네이티브 구조의 포함된 각 포인터에 대해 구조체의 관리되는 버전에는 형식의 인스턴스가 IntPtr 포함되어야 합니다. 또한 이러한 인스턴스에 대한 메모리는 , 및 메서드를 사용하여 AllocCoTaskMemStructureToPtr명시적으로 할당, 초기화 및 FreeCoTaskMem 해제되어야 합니다.
다음 코드는 관리되지 않는 모듈과 관리되는 모듈로 구성됩니다. 관리되지 않는 모듈은 포인터를 포함하는 구조체를 허용하는 함수와 호출 ListString
TakesListStruct
된 함수를 정의하는 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 가져온 함수의 문제를 검색할 수 없습니다.