Aracılığıyla paylaş


Nasıl yapılır: P/Invoke kullanarak işlev işaretçilerini hazırlama

Yönetilen temsilciler, .NET Framework P/Invoke özellikleri kullanılarak yönetilmeyen işlevlerle birlikte çalışırken işlev işaretçileri yerine kullanılabilir. Ancak mümkün olduğunda bunun yerine C++ Birlikte Çalışma özelliklerini kullanmanızı öneririz. P/Invoke çok az derleme zamanı hata raporlaması sağlar, tür açısından güvenli değildir ve uygulanması yorucu olabilir. Yönetilmeyen API bir DLL olarak paketlenmişse ve kaynak kodu kullanılamıyorsa, P/Invoke tek seçenektir. Aksi takdirde şu makalelere bakın:

İşlev işaretçilerini bağımsız değişken olarak alan yönetilmeyen API'ler, yerel işlev işaretçisi yerine yönetilen bir temsilci kullanılarak yönetilen koddan çağrılabilir. Derleyici, temsilciyi otomatik olarak yönetilmeyen işlevlere işlev işaretçisi olarak sıralar. Gerekli yönetilen/yönetilmeyen geçiş kodunu ekler.

Örnek

Aşağıdaki kod yönetilmeyen ve yönetilen bir modülden oluşur. Yönetilmeyen modül, işlev işaretçisini kabul eden adlı TakesCallback bir işlevi tanımlayan bir DLL'dir. Bu adres işlevi yürütmek için kullanılır.

// TraditionalDll5.cpp
// compile with: /LD /EHsc
#include <iostream>
#define TRADITIONALDLL_EXPORTS
#ifdef TRADITIONALDLL_EXPORTS
#define TRADITIONALDLL_API __declspec(dllexport)
#else
#define TRADITIONALDLL_API __declspec(dllimport)
#endif

extern "C" {
   /* Declare an unmanaged function type that takes two int arguments
      Note the use of __stdcall for compatibility with managed code */
   typedef int (__stdcall *CALLBACK)(int);
   TRADITIONALDLL_API int TakesCallback(CALLBACK fp, int);
}

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

Yönetilen modül, yerel koda işlev işaretçisi olarak sıralanmış bir temsilci tanımlar. Yerel işlevi yönetilen koda göstermek TakesCallback için özniteliğini kullanırDllImportAttribute. işlevinde main temsilcinin bir örneği oluşturulur ve işleve TakesCallback geçirilir. Program çıkışı, bu işlevin yerel TakesCallback işlev tarafından yürütüldüğünü gösterir.

Yönetilen işlev, yerel işlev yürütülürken .NET Framework çöp toplama işleminin temsilciyi yeniden konumlandırmasını önlemek için yönetilen temsilci için çöp toplamayı engeller.

// MarshalDelegate.cpp
// compile with: /clr
using namespace System;
using namespace System::Runtime::InteropServices;

public delegate int GetTheAnswerDelegate(int);
public value struct TraditionalDLL {
   [DllImport("TraditionalDLL5.dll")]
   static public int TakesCallback(GetTheAnswerDelegate^ pfn, int n);
};

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

int main() {
   GetTheAnswerDelegate^ fp = gcnew GetTheAnswerDelegate(GetNumber);
   pin_ptr<GetTheAnswerDelegate^> pp = &fp;
   Console::WriteLine("[managed] sending delegate as callback...");

   int answer = TraditionalDLL::TakesCallback(fp, 42);
}

Dll'nin hiçbir bölümü, geleneksel #include yönerge kullanılarak yönetilen koda sunulmaz. Aslında DLL'ye yalnızca çalışma zamanında erişilir, bu nedenle kullanılarak DllImportAttribute içeri aktarılan işlevlerle ilgili sorunlar derleme zamanında algılanamaz.

Ayrıca bkz.

C++ içinde açık P/Invoke kullanma (DllImport öznitelik)