Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Det här avsnittet visar hur marshaling av callbacks och delegater (den hanterade versionen av en callback) sker mellan hanterad och ohanterad kod med hjälp av Visual C++.
I följande kodexempel används de hanterade, ohanterade #pragma-direktiven för att implementera hanterade och ohanterade funktioner i samma fil, men funktionerna kan också definieras i separata filer. Filer som endast innehåller ohanterade funktioner behöver inte kompileras med /clr (Common Language Runtime Compil).
Exempel: Konfigurera ohanterat API för att utlösa hanterat ombud
I följande exempel visas hur du konfigurerar ett icke-hanterat API för att utlösa en hanterad delegat. En hanterad delegat skapas och en av interopmetoderna, GetFunctionPointerForDelegate, används för att hämta den underliggande ingångspunkten för delegaten. Den här adressen skickas sedan till den ohanterade funktionen, som anropar den utan att känna till det faktum att den implementeras som en hanterad funktion.
Observera att det är möjligt, men inte nödvändigt, att fästa den delegerade med hjälp av pin_ptr (C++/CLI) för att förhindra att den flyttas eller tas bort av skräpinsamlaren. Skydd mot för tidig skräpinsamling behövs, men att fästa ger mer skydd än vad som är nödvändigt, eftersom det förhindrar insamling men också förhindrar omlokalisering.
Om en delegering flyttas av en skräpsamling påverkar det inte det underliggande hanterade återanrop, så Alloc används för att lägga till en referens till delegeringen, vilket tillåter omlokalisering av delegeringen och förhindrar bortskaffande. Om du använder GCHandle i stället för pin_ptr minskar fragmenteringspotentialen för den hanterade heapen.
// 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();
}
Exempel: Funktionspekare som lagras av ohanterat API
Följande exempel liknar föregående exempel, men i det här fallet lagras den tillhandahållna funktionspekaren av det ohanterade API:et, så det kan anropas när som helst, vilket kräver att skräpinsamlingen undertrycks under en godtycklig tidsperiod. Därför använder följande exempel en global instans av GCHandle för att förhindra att ombudet flyttas, oberoende av funktionsomfånget. Som beskrivs i det första exemplet är det onödigt att använda pin_ptr för dessa exempel, men i det här fallet skulle det inte fungera ändå, eftersom omfattningen för en pin_ptr är begränsad till en enda funktion.
// 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();
}