Sdílet prostřednictvím


Postupy: Zařazování ukazatelů na funkce pomocí volání nespravovaného kódu

Spravované delegáty je možné použít místo ukazatelů funkcí při spolupráci s nespravovanými funkcemi pomocí funkcí P/Invoke rozhraní .NET Framework. Pokud je to ale možné, doporučujeme místo toho používat funkce interoperability C++. Volání nespravovaného kódu poskytuje zasílání zpráv o chybách v době kompilace, není typově bezpečné a nelze je implementovat. Pokud je nespravované rozhraní API zabalené jako knihovna DLL a zdrojový kód není k dispozici, je jediným parametrem volání nespravovaného kódu. V opačném případě si přečtěte tyto články:

Nespravovaná rozhraní API, která přebírají ukazatele na funkce jako argumenty, je možné volat ze spravovaného kódu pomocí spravovaného delegáta místo ukazatele nativní funkce. Kompilátor automaticky zařadí delegáta na nespravované funkce jako ukazatel funkce. Vloží potřebný spravovaný nebo nespravovaný přechodový kód.

Příklad

Následující kód se skládá z nespravovaného a spravovaného modulu. Nespravovaný modul je knihovna DLL, která definuje funkci s názvem TakesCallback , která přijímá ukazatel funkce. Tato adresa se používá ke spuštění funkce.

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

Spravovaný modul definuje delegáta, který je zařazený do nativního kódu jako ukazatel funkce. Pomocí atributu DllImportAttribute zveřejňuje nativní TakesCallback funkci spravovanému kódu. main Ve funkci se vytvoří instance delegáta a předá funkciTakesCallback. Výstup programu ukazuje, že tato funkce se spustí nativní TakesCallback funkcí.

Spravovaná funkce potlačí uvolňování paměti spravovaného delegáta, aby zabránila uvolnění paměti rozhraní .NET Framework v přemístění delegáta při spuštění nativní funkce.

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

Žádná část knihovny DLL není vystavena spravovanému kódu pomocí tradiční #include direktivy. Knihovna DLL je ve skutečnosti přístupná pouze za běhu, takže problémy s funkcemi importovanými pomocí DllImportAttribute nelze zjistit v době kompilace.

Viz také

Použití explicitního volání nespravovaného kódu v jazyce C++ (DllImport atribut)