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

관리되는 대리자는 .NET Framework P/Invoke 기능을 사용하여 관리되지 않는 함수와 상호 운용할 때 함수 포인터 대신 사용할 수 있습니다. 그러나 가능하면 C++ Interop 기능을 대신 사용하는 것이 좋습니다. P/Invoke는 컴파일 시간 오류 보고를 거의 제공하지 않으며 형식이 안전하지 않으며 구현하는 데 지루할 수 있습니다. 관리되지 않는 API가 DLL로 패키지되고 소스 코드를 사용할 수 없는 경우 P/Invoke가 유일한 옵션입니다. 그렇지 않으면 다음 문서를 참조하세요.

함수 포인터를 인수로 사용하는 관리되지 않는 API는 네이티브 함수 포인터 대신 관리되는 대리자를 사용하여 관리 코드에서 호출할 수 있습니다. 컴파일러는 자동으로 대리자를 관리되지 않는 함수에 함수 포인터로 마샬링합니다. 필요한 관리/관리되지 않는 전환 코드를 삽입합니다.

예시

다음 코드는 관리되지 않는 모듈과 관리되는 모듈로 구성됩니다. 관리되지 않는 모듈은 함수 포인터를 허용하는 함수를 TakesCallback 정의하는 DLL입니다. 이 주소는 함수를 실행하는 데 사용됩니다.

// TraditionalDll5.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" {
   /* Declare an unmanaged function type that takes two int arguments
      Note the use of __stdcall for compatibility with managed code */
   typedef int (__stdcall *CALLBACK)(int);
   TRADITIONALDLL_API int TakesCallback(CALLBACK fp, int);
}

int TakesCallback(CALLBACK fp, int n) {
   printf_s("[unmanaged] got callback address, calling it...\n");
   return fp(n);
}

관리되는 모듈은 네이티브 코드에 마샬링되는 대리자를 함수 포인터로 정의합니다. 이 특성은 네이 DllImportAttribute 티브 TakesCallback 함수를 관리 코드에 노출하는 데 사용됩니다. 함수에서 main 대리자의 인스턴스가 만들어지고 함수에 TakesCallback 전달됩니다. 프로그램 출력은 이 함수가 네이티브 TakesCallback 함수에 의해 실행됨을 보여 줍니다.

관리되는 함수는 네이티브 함수가 실행되는 동안 .NET Framework 가비지 수집이 대리자를 재배치하지 못하도록 관리되는 대리자의 가비지 수집을 표시하지 않습니다.

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

public delegate int GetTheAnswerDelegate(int);
public value struct TraditionalDLL {
   [DllImport("TraditionalDLL5.dll")]
   static public int TakesCallback(GetTheAnswerDelegate^ pfn, int n);
};

int GetNumber(int n) {
   Console::WriteLine("[managed] callback!");
   static int x = 0;
   ++x;
   return x + n;
}

int main() {
   GetTheAnswerDelegate^ fp = gcnew GetTheAnswerDelegate(GetNumber);
   pin_ptr<GetTheAnswerDelegate^> pp = &fp;
   Console::WriteLine("[managed] sending delegate as callback...");

   int answer = TraditionalDLL::TakesCallback(fp, 42);
}

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

참고 항목

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