Udostępnij za pośrednictwem


Porady: kierowanie wskaźników funkcji za pomocą funkcji PInvoke

W tym temacie wyjaśniono sposób zarządzany delegatów można używać zamiast wskaźników funkcji współdziałania niezarządzanych funkcje za pomocą funkcji.NET Framework P i Invoke.Jednakże programistów języka Visual C++ zachęca się zamiast korzystać z funkcji C++ Interop (jeśli możliwe) ponieważ P i Invoke zawiera niewiele kompilacji raportowanie błędów, nie jest typu palety i może być uciążliwe do wdrożenia.Jeśli API niezarządzanego, jest dostarczana w bibliotece DLL i kod źródłowy nie jest dostępny, P/Invoke jest jedyną opcją.W przeciwnym razie zobacz następujące tematy:

Niezarządzane interfejsów API, które wziąć wskaźniki funkcje jako argumenty mogą być wywoływane z kodu zarządzanego z zarządzanych pełnomocnik zamiast wskaźnik funkcji macierzystego.Kompilator marszałków pełnomocnika do niezarządzanego funkcji jako wskaźnik funkcji i automatycznie wstawia kod przejściowy niezbędny zarządzanych/niezarządzanych.

Przykład

Poniższy kod składa się z modułu zarządzane i niezarządzane.Moduł niezarządzanych to biblioteki DLL, która zawiera definicję funkcji o nazwie TakesCallback, która akceptuje wskaźnika funkcji.Ten adres jest używany do wykonania funkcji.

Moduł zarządzanych definiuje pełnomocnika, który jest przekazywane do kodu macierzystego jako wskaźnik funkcji i używa DllImportAttribute atrybut narazić macierzystych funkcji TakesCallback do kodu zarządzanego.Wystąpienie pełnomocnika główną funkcją jest tworzone i przekazany do funkcji TakesCallback.Dane wyjściowe programu pokazuje, że ta funkcja pobiera wykonywane przez funkcję TakesCallback macierzystego.

Funkcja zarządzanych pomija wyrzucania elementów bezużytecznych zarządzanych pełnomocnikowi zapobiegające.NET Framework wyrzucania elementów bezużytecznych od przeniesienia pełnomocnika, gdy wykonuje funkcję macierzystego.

Moduł zarządzany jest skompilowany z/CLR, ale/CLR: pure działa jak również.

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

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

Należy zauważyć, że żadna część biblioteki DLL jest narażony na kod zarządzany przy użyciu tradycyjnych # dyrektywy include.W rzeczywistości, biblioteka DLL jest dostępny tylko w czasie wykonywania, więc problemów z funkcjami importowane z DllImportAttribute nie zostaną wykryte w czasie kompilacji.

Zobacz też

Inne zasoby

Używanie jawnej funkcji PInvoke w języku C++ (atrybut DllImport)