Aracılığıyla paylaş


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

Yönetilmeyen DLL'lerde uygulanan işlevler, Platform Çağırma (P/Invoke) işlevi kullanılarak yönetilen koddan çağrılabilir. DLL'nin kaynak kodu kullanılamıyorsa, birlikte çalışmak için tek seçenek P/Invoke'tır. Ancak, diğer .NET dillerinden farklı olarak, Visual C++ P/Invoke'a bir alternatif sağlar. Daha fazla bilgi için bkz . C++ Birlikte Çalışma Kullanma (Örtük P/Invoke) ve Nasıl yapılır: C++ Birlikte Çalışma kullanarak eklenmiş işaretçileri hazırlama.

Örnek

Yapıların yerel koda geçirilmesi, veri düzeni açısından yerel yapıya eşdeğer bir yönetilen yapının oluşturulmasını gerektirir. Ancak, işaretçiler içeren yapılar özel işleme gerektirir. Yerel yapıdaki her eklenmiş işaretçi için, yapının yönetilen sürümü türün bir örneğini IntPtr içermelidir. Ayrıca, bu örnekler için bellek açıkça ayrılmalı, başlatılmalı ve , StructureToPtrve FreeCoTaskMem yöntemleri kullanılarak AllocCoTaskMemserbest bırakılmalıdır.

Aşağıdaki kod yönetilmeyen ve yönetilen bir modülden oluşur. Yönetilmeyen modül, işaretçi içeren adlı bir yapıyı ve adlı ListString TakesListStructbir işlevi kabul eden bir işlevi tanımlayan bir DLL'dir.

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

#pragma pack(push, 8)
struct ListStruct {
   int count;
   double* item;
};
#pragma pack(pop)

extern "C" {
   TRADITIONALDLL_API void TakesListStruct(ListStruct);
}

void TakesListStruct(ListStruct list) {
   printf_s("[unmanaged] count = %d\n", list.count);
   for (int i=0; i<list.count; i++)
      printf_s("array[%d] = %f\n", i, list.item[i]);
}

Yönetilen modül, işlevini içeri aktaran TakesListStruct ve yerel ile eşdeğer ListStruct olarak adlandırılan MListStruct bir yapıyı tanımlayan bir komut satırı uygulamasıdır, ancak double* örneğiyle IntPtr temsil edilir. çağrısından TakesListStructmain önce işlev, bu alanın başvurduğunu belleği ayırır ve başlatır.

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

[StructLayout(LayoutKind::Sequential, Pack=8)]
value struct MListStruct {
   int count;
   IntPtr item;
};

value struct TraditionalDLL {
    [DllImport("TraditionalDLL6.dll")]
   static public void TakesListStruct(MListStruct);
};

int main() {
   array<double>^ parray = gcnew array<double>(10);
   Console::WriteLine("[managed] count = {0}", parray->Length);

   Random^ r = gcnew Random();
   for (int i=0; i<parray->Length; i++) {
      parray[i] = r->NextDouble() * 100.0;
      Console::WriteLine("array[{0}] = {1}", i, parray[i]);
   }

   int size = Marshal::SizeOf(double::typeid);
   MListStruct list;
   list.count = parray->Length;
   list.item = Marshal::AllocCoTaskMem(size * parray->Length);

   for (int i=0; i<parray->Length; i++) {
      IntPtr t = IntPtr(list.item.ToInt32() + i * size);
      Marshal::StructureToPtr(parray[i], t, false);
   }

   TraditionalDLL::TakesListStruct( list );
   Marshal::FreeCoTaskMem(list.item);
}

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şlevlerdeki sorunlar derleme zamanında algılanamaz.

Ayrıca bkz.

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