Aracılığıyla paylaş


Nasıl yapılır: C++ Birlikte Çalışmayı Kullanarak Geri Çağrıları ve Temsilcileri Sıralama

Bu konu başlığında, Visual C++ kullanılarak yönetilen ve yönetilmeyen kod arasında geri çağırmaların ve temsilcilerin (geri çağırmanın yönetilen sürümü) yapılandırılması gösterilmektedir.

Aşağıdaki kod örnekleri yönetilen ve yönetilmeyen işlevleri aynı dosyada uygulamak için yönetilen, yönetilmeyen #pragma yönergelerini kullanır, ancak işlevler ayrı dosyalarda da tanımlanabilir. Yalnızca yönetilmeyen işlevleri içeren dosyaların /clr (Ortak Dil Çalışma Zamanı Derlemesi) ile derlenmesi gerekmez.

Örnek: Yönetilmeyen API'yi yönetilen temsilciyi tetikleme amacıyla yapılandırma

Aşağıdaki örnekte yönetilen bir temsilciyi tetikleme amacıyla yönetilmeyen BIR API'nin nasıl yapılandırıldığı gösterilmektedir. Yönetilen bir temsilci oluşturulur ve birlikte çalışma yöntemlerinden biri olan , GetFunctionPointerForDelegatetemsilcinin temel giriş noktasını almak için kullanılır. Bu adres daha sonra yönetilmeyen işleve geçirilir ve bu işlev yönetilen işlev olarak uygulandığını bilmeden çağrılır.

Çöp toplayıcı tarafından yeniden konumlandırılmasını veya atılmasını önlemek için temsilciyi pin_ptr (C++/CLI) kullanarak sabitlemenin mümkün olduğunu ancak gerekli olmadığını fark edin. Erken çöp toplamaya karşı koruma gereklidir, ancak sabitleme, toplamayı engellediğinden ve aynı zamanda yeniden konumlandırmayı önlediğinden gerekenden daha fazla koruma sağlar.

Bir temsilci çöp toplama tarafından yeniden konumlandırılırsa, temel alınan yönetilen geri aramayı etkilemez, bu nedenle Alloc temsilciye başvuru eklemek için kullanılır, temsilcinin yeniden yerleştirilmesine izin verir, ancak elden çıkarma engellenir. pin_ptr yerine GCHandle kullanılması yönetilen yığının parçalanma potansiyelini azaltır.

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

Örnek: Yönetilmeyen API tarafından depolanan işlev işaretçisi

Aşağıdaki örnek önceki örneğe benzer, ancak bu durumda sağlanan işlev işaretçisi yönetilmeyen API tarafından depolanır, bu nedenle herhangi bir zamanda çağrılabilir ve bu nedenle çöp toplamanın rastgele bir süre boyunca gizlenmesi gerekir. Sonuç olarak aşağıdaki örnek, işlev kapsamından bağımsız olarak temsilcinin yeniden yerleştirilmesini önlemek için genel örneğini GCHandle kullanır. İlk örnekte açıklandığı gibi, pin_ptr kapsamı tek bir işlevle sınırlı olduğundan, pin_ptr kullanılması bu örnekler için gereksizdir, ancak bu durumda yine de çalışmaz.

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

Ayrıca bkz.

C++ Birlikte Çalışabilirliği Kullanma (Örtük PInvoke)