Megosztás a következőn keresztül:


Útmutató: Visszahívások és delegáltak kezelése C++ Interop segítségével

Ez a témakör bemutatja a visszahívások és meghatalmazottak (a visszahívás felügyelt verziója) közötti rendezést a felügyelt és a nem felügyelt kód között a Visual C++ használatával.

Az alábbi példakódok a felügyelt, nem felügyelt #pragma irányelveket használják a felügyelt és nem felügyelt függvények ugyanazon fájlban való implementálásához, de a függvények külön fájlokban is meghatározhatók. A csak nem felügyelt függvényeket tartalmazó fájlokat nem kell lefordítani a /clr (Common Language Runtime Compilation) használatával.

Példa: Felügyelt delegált aktiválásához nem felügyelt API konfigurálása

Az alábbi példa bemutatja, hogyan konfigurálhat nem felügyelt API-t felügyelt meghatalmazott aktiválásához. Létrejön egy felügyelt delegált, és az egyik interop metódust a delegált mögöttes belépési pontjának lekérésére használják. Ezt a címet ezután a rendszer átadja a nem felügyelt függvénynek, amely úgy hívja meg, hogy nem ismeri azt a tényt, hogy felügyelt függvényként van implementálva.

Vegye figyelembe, hogy lehetséges, de nem szükséges a delegált rögzítése a pin_ptr (C++/CLI) használatával annak érdekében, hogy megakadályozza a szemétgyűjtő általi áthelyezését vagy eltávolítását. A korai szemétgyűjtés elleni védelemre van szükség, de a rögzítés a szükségesnél nagyobb védelmet nyújt, mivel megakadályozza a begyűjtést, de megakadályozza az áthelyezést is.

Ha egy delegáltat egy szemétgyűjtés áthelyez, az nem befolyásolja a mögöttes kezelt callbacket, ezért a Alloc hivatkozás hozzáadására szolgál a delegálthoz, amely lehetővé teszi a delegált áthelyezését, de megakadályozza a törlést. A GCHandle használata pin_ptr helyett csökkenti a felügyelt halom töredezettségi potenciálját.

// MarshalDelegate1.cpp
// compile with: /clr
#include <iostream>

using namespace System;
using namespace System::Runtime::InteropServices;

#pragma unmanaged

// Declare an unmanaged function type that takes two int arguments
// Note the use of __stdcall for compatibility with managed code
typedef int (__stdcall *ANSWERCB)(int, int);

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

#pragma managed

public delegate int GetTheAnswerDelegate(int, int);

int GetNumber(int n, int m) {
   Console::WriteLine("[managed] callback!");
   return n + m;
}

int main() {
   GetTheAnswerDelegate^ fp = gcnew GetTheAnswerDelegate(GetNumber);
   GCHandle gch = GCHandle::Alloc(fp);
   IntPtr ip = Marshal::GetFunctionPointerForDelegate(fp);
   ANSWERCB cb = static_cast<ANSWERCB>(ip.ToPointer());
   Console::WriteLine("[managed] sending delegate as callback...");

// force garbage collection cycle to prove
// that the delegate doesn't get disposed
   GC::Collect();

   int answer = TakesCallback(cb, 243, 257);

// release reference to delegate
   gch.Free();
}

Példa: A nem felügyelt API által tárolt függvénymutató

Az alábbi példa hasonló az előző példához, de ebben az esetben a megadott függvénymutatót a nem felügyelt API tárolja, így bármikor meghívható, és a szemétgyűjtést tetszőleges ideig el kell tiltani. Ennek eredményeképpen az alábbi példa a GCHandle globális példányát használja a delegátus áthelyezésének megakadályozására, függetlenül a függvény hatáskörétől. Ahogy az első példában is szó volt róla, a pin_ptr használata nem szükséges ezekhez a példákhoz, de ebben az esetben egyébként sem működne, mivel a pin_ptr hatóköre egyetlen függvényre korlátozódik.

// MarshalDelegate2.cpp
// compile with: /clr
#include <iostream>

using namespace System;
using namespace System::Runtime::InteropServices;

#pragma unmanaged

// Declare an unmanaged function type that takes two int arguments
// Note the use of __stdcall for compatibility with managed code
typedef int (__stdcall *ANSWERCB)(int, int);
static ANSWERCB cb;

int TakesCallback(ANSWERCB fp, int n, int m) {
   cb = fp;
   if (cb) {
      printf_s("[unmanaged] got callback address (%d), calling it...\n", cb);
      return cb(n, m);
   }
   printf_s("[unmanaged] unregistering callback");
   return 0;
}

#pragma managed

public delegate int GetTheAnswerDelegate(int, int);

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

   return n + m + x;
}

static GCHandle gch;

int main() {
   GetTheAnswerDelegate^ fp = gcnew GetTheAnswerDelegate(GetNumber);

   gch = GCHandle::Alloc(fp);

   IntPtr ip = Marshal::GetFunctionPointerForDelegate(fp);
   ANSWERCB cb = static_cast<ANSWERCB>(ip.ToPointer());
   Console::WriteLine("[managed] sending delegate as callback...");

   int answer = TakesCallback(cb, 243, 257);

   // possibly much later (in another function)...

   Console::WriteLine("[managed] releasing callback mechanisms...");
   TakesCallback(0, 243, 257);
   gch.Free();
}

Lásd még

C++ Interop használata (Implicit PInvoke)