Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
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();
}