Aracılığıyla paylaş


Nasıl yapılır: PInvoke Kullanarak Yapıları Sıralama

Bu belgede, C stili yapıları kabul eden yerel işlevlerin P/Invoke kullanılarak yönetilen işlevlerden nasıl çağrılabileceği açıklanmaktadır. P/Invoke çok az derleme zamanı hata raporlaması sağladığından, tür açısından güvenli olmadığından ve yönetilmeyen API BIR DLL olarak paketlenmişse ve kaynak kodu kullanılamıyorsa uygulama zahmetli olabileceğinden P/Invoke yerine C++ Birlikte Çalışma özelliklerini kullanmanızı öneririz ancak tek seçenek P/Invoke'tır. Aksi takdirde aşağıdaki belgelere bakın:

Varsayılan olarak, yerel ve yönetilen yapılar bellekte farklı şekilde düzenlenir, bu nedenle yapıları yönetilen/yönetilmeyen sınıra başarıyla geçirmek, veri bütünlüğünü korumak için ek adımlar gerektirir.

Bu belgede, yerel yapıların yönetilen eşdeğerlerini tanımlamak için gereken adımlar ve sonuçta elde edilen yapıların yönetilmeyen işlevlere nasıl geçirilebileceği açıklanmaktadır. Bu belgede, dize veya işaretçi içermeyen basit yapıların kullanıldığı varsayılır. Bölümlenebilir olmayan birlikte çalışabilirlik hakkında bilgi için bkz . C++ Birlikte Çalışma Kullanma (Örtük PInvoke). P/Invoke,dönüş değeri olarak blittable olmayan türlere sahip olamaz. Blittable türleri yönetilen ve yönetilmeyen kodda aynı gösterime sahiptir. Daha fazla bilgi için bkz . Blittable ve Blittable Olmayan Türler.

Yönetilen/yönetilmeyen sınır genelinde basit, yarıtlanabilir yapıların sıralanması için öncelikle her yerel yapının yönetilen sürümlerinin tanımlanması gerekir. Bu yapıların herhangi bir yasal adı olabilir; veri düzeni dışında iki yapının yerel ve yönetilen sürümü arasında ilişki yoktur. Bu nedenle, yönetilen sürümün yerel sürümle aynı boyutta ve aynı sırada alanlar içermesi çok önemlidir. (Yapının yönetilen ve yerel sürümlerinin eşdeğer olmasını sağlamaya yönelik bir mekanizma yoktur, bu nedenle uyumsuzluklar çalışma süresine kadar belirgin olmaz. İki yapının aynı veri düzenine sahip olduğundan emin olmak programcının sorumluluğundadır.)

Yönetilen yapıların üyeleri bazen performans amacıyla yeniden düzenlendiğinden StructLayoutAttribute , yapının sırayla düzenlendiğini belirtmek için özniteliğinin kullanılması gerekir. Ayrıca, yapı paketleme ayarının yerel yapı tarafından kullanılanla aynı olacak şekilde açıkça ayarlanması da iyi bir fikirdir. (Varsayılan olarak Visual C++ her iki yönetilen kod için de 8 baytlık bir yapı paketleme kullanır.)

  1. Ardından, yapıyı kabul eden yönetilmeyen işlevlere karşılık gelen giriş noktalarını bildirmek için kullanın DllImportAttribute , ancak yapının her iki sürümü için de aynı adı kullanırsanız, işlev imzalarında yapının yönetilen sürümünü kullanın.

  2. Artık yönetilen kod, yapının yönetilen sürümünü yönetilmeyen işlevlere gerçekten yönetilen işlevlermiş gibi geçirebilir. Bu yapılar, aşağıdaki örnekte gösterildiği gibi değere veya başvuruya göre geçirilebilir.

Yönetilmeyen ve yönetilen modüller

Aşağıdaki kod yönetilmeyen ve yönetilen bir modülden oluşur. Yönetilmeyen modül, Konum adlı bir yapıyı ve Konum yapısının iki örneğini kabul eden GetDistance adlı bir işlevi tanımlayan bir DLL'dir. İkinci modül, GetDistance işlevini içeri aktaran, ancak Bunu Konum yapısı MLocation'ın yönetilen eşdeğeri olarak tanımlayan yönetilen bir komut satırı uygulamasıdır. Pratikte aynı ad muhtemelen yapının her iki sürümü için de kullanılabilir; ancak burada DllImport prototipinin yönetilen sürüm açısından tanımlandığını göstermek için farklı bir ad kullanılır.

DLL'nin hiçbir bölümünün, geleneksel #include yönergesi kullanılarak yönetilen koda sunulmadığını unutmayın. Aslında, DLL'ye yalnızca çalışma zamanında erişilir, bu nedenle DllImport ile içeri aktarılan işlevlerle ilgili sorunlar derleme zamanında algılanmaz.

Örnek: Yönetilmeyen DLL modülü

// TraditionalDll3.cpp
// compile with: /LD /EHsc
#include <iostream>
#include <stdio.h>
#include <math.h>

#define TRADITIONALDLL_EXPORTS
#ifdef TRADITIONALDLL_EXPORTS
   #define TRADITIONALDLL_API __declspec(dllexport)
#else
   #define TRADITIONALDLL_API __declspec(dllimport)
#endif

#pragma pack(push, 8)
struct Location {
   int x;
   int y;
};
#pragma pack(pop)

extern "C" {
   TRADITIONALDLL_API double GetDistance(Location, Location);
   TRADITIONALDLL_API void InitLocation(Location*);
}

double GetDistance(Location loc1, Location loc2) {
   printf_s("[unmanaged] loc1(%d,%d)", loc1.x, loc1.y);
   printf_s(" loc2(%d,%d)\n", loc2.x, loc2.y);

   double h = loc1.x - loc2.x;
   double v = loc1.y = loc2.y;
   double dist = sqrt( pow(h,2) + pow(v,2) );

   return dist;
}

void InitLocation(Location* lp) {
   printf_s("[unmanaged] Initializing location...\n");
   lp->x = 50;
   lp->y = 50;
}

Örnek: Yönetilen komut satırı uygulama modülü

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

[StructLayout(LayoutKind::Sequential, Pack=8)]
value struct MLocation {
   int x;
   int y;
};

value struct TraditionalDLL {
   [DllImport("TraditionalDLL3.dll")]
   static public double GetDistance(MLocation, MLocation);
   [DllImport("TraditionalDLL3.dll")]
   static public double InitLocation(MLocation*);
};

int main() {
   MLocation loc1;
   loc1.x = 0;
   loc1.y = 0;

   MLocation loc2;
   loc2.x = 100;
   loc2.y = 100;

   double dist = TraditionalDLL::GetDistance(loc1, loc2);
   Console::WriteLine("[managed] distance = {0}", dist);

   MLocation loc3;
   TraditionalDLL::InitLocation(&loc3);
   Console::WriteLine("[managed] x={0} y={1}", loc3.x, loc3.y);
}
[unmanaged] loc1(0,0) loc2(100,100)
[managed] distance = 141.42135623731
[unmanaged] Initializing location...
[managed] x=50 y=50

Ayrıca bkz.

C++'ta Açık PInvoke Kullanma (DllImport Özniteliği)