방법: P/Invoke를 사용하여 배열 마샬링
.NET Framework Platform Invoke(P/Invoke) 지원을 사용할 때 CLR 문자열 형식 String 을 사용하여 C 스타일 문자열을 허용하는 네이티브 함수를 호출할 수 있습니다. 가능한 경우 P/Invoke 대신 C++ Interop 기능을 사용하는 것이 좋습니다. P/Invoke는 컴파일 시간 오류 보고를 거의 제공하지 않으며 형식이 안전하지 않으며 구현하는 데 지루할 수 있습니다. 관리되지 않는 API가 DLL로 패키지되고 소스 코드를 사용할 수 없는 경우 P/Invoke가 유일한 옵션입니다. 그렇지 않으면 C++ Interop 사용(암시적 P/Invoke)을 참조하세요.
예시
네이티브 배열과 관리되는 배열은 메모리에 다르게 배치되므로 관리/관리되지 않는 경계를 성공적으로 통과하려면 변환 또는 마샬링이 필요합니다. 이 문서에서는 관리 코드에서 단순(블릿 가능) 항목의 배열을 네이티브 함수에 전달하는 방법을 보여 줍니다.
일반적으로 관리/관리되지 않는 데이터 마샬링의 경우와 마찬가지로 이 DllImportAttribute 특성은 사용되는 각 네이티브 함수에 대한 관리되는 진입점을 만드는 데 사용됩니다. 배열을 인수 MarshalAsAttribute 로 사용하는 함수에서 특성을 사용하여 데이터를 마샬링하는 방법을 지정해야 합니다. 다음 예제 UnmanagedType 에서 열거형은 관리되는 배열이 C 스타일 배열로 마샬링됨을 나타내는 데 사용됩니다.
다음 코드는 관리되지 않는 모듈과 관리되는 모듈로 구성됩니다. 관리되지 않는 모듈은 정수 배열을 허용하는 함수를 정의하는 DLL입니다. 두 번째 모듈은 이 함수를 가져오지만 관리되는 배열을 기준으로 정의하는 관리되는 명령줄 애플리케이션입니다. 이 특성은 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
지시문을 통해 관리 코드에 노출되지 않습니다. 실제로 DLL은 런타임에만 액세스되므로 컴파일 시간에 사용하여 DllImportAttribute 가져온 함수의 문제를 검색할 수 없습니다.