Udostępnij za pośrednictwem


Porady: kierowanie wywołań zwrotnych i delegatów za pomocą międzyoperacyjności języka C++

W tym temacie przedstawia dla kierowania wywołań zwrotnych oraz deleguje (wersja zarządzanych wywołanie zwrotne) między kod zarządzany i niezarządzany przy użyciu języka Visual C++.

Następujące przykłady użycia kodu zarządzane, niezarządzane #pragma dyrektyw do wdrożenia zarządzane i niezarządzane funkcji w tym samym pliku, ale można również zdefiniować funkcje w oddzielnych plikach.Pliki zawierające tylko niezarządzanych funkcje nie są zestawiane z /clr (Kompilacja środowiska uruchomieniowego języka wspólnego).

Przykład

Poniższy przykład pokazuje, jak skonfigurować interfejs API niezarządzanego wyzwolić zarządzanych pełnomocnik.Zarządzane delegata jest tworzony i jednej z metod współdziałania, GetFunctionPointerForDelegate, jest używana do pobierania podstawowy punkt wejścia dla pełnomocnika.Ten adres jest następnie przekazywany do funkcji niezarządzanych, która wywołuje go bez wiedzy o fakt, że jest zaimplementowana jako funkcja zarządzanych.

Należy zauważyć, że jest to możliwe, ale nie jest to konieczne, do pinu delegowanego przy użyciu pin_ptr zapobiegające jej ponownie znajduje się lub usuwane przez moduł garbage collector.Konieczna jest ochrona z kolekcji garbage przedwczesne, ale Przypinanie zapewnia ochronę więcej niż jest to konieczne, jak zapobiega kolekcji, ale zapobiega także przeniesienie.

Jeżeli pełnomocnik ponownie znajduje się kolekcja garbage, nie wpłynie to wywołanie zwrotne którym zarządzane, tak Alloc jest używana do dodawania odwołania do delegata, pozwalając przeniesienie pełnomocnika, ale uniemożliwia usuwanie.Przy użyciu dojścia GCHandle zamiast pin_ptr zmniejsza potencjał fragmentacji sterty zarządzanych.

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

W poniższym przykładzie jest podobny do poprzedniego przykładu, ale w tym przypadku funkcja podany wskaźnik jest przechowywana przez niezarządzanych API, więc może on zostać wywołany w dowolnym momencie, wymagające pominięte wyrzucania elementów bezużytecznych dla dowolnej długości czasu.W rezultacie w poniższym przykładzie użyto globalnego wystąpienie GCHandle uniemożliwi pełnomocnik przeniesionego, niezależnie od zakresu funkcji.Omówionego w pierwszym przykładzie, za pomocą pin_ptr nie jest konieczne dla tych przykładów, ale w tym przypadku nie będzie działać tak, jak zakres pin_ptr jest ograniczony do jednej funkcja.

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

Zobacz też

Informacje

Korzystanie z międzyoperacyjności języka C++ (niejawna funkcja PInvoke)