Megosztás a következőn keresztül:


Hogyan: Kiszolgáljuk a struktúrákat PInvoke használatával

Ez a dokumentum bemutatja, hogyan hívhatók meg a C stílusú szerkezeteket elfogadó natív függvények a felügyelt függvényekből a P/Invoke használatával. Bár azt javasoljuk, hogy a P/Invoke helyett a C++ Interop funkciókat használja, mert a P/Invoke kevés fordítási idejű hibajelentést biztosít, nem típusbiztos, és nehézkes lehet implementálni, ha a nem felügyelt API DLL-ként van csomagolva, és a forráskód nem érhető el, a P/Invoke az egyetlen lehetőség. Ellenkező esetben tekintse meg a következő dokumentumokat:

Alapértelmezés szerint a natív és a felügyelt struktúrák eltérően vannak elhelyezve a memóriában, ezért a felügyelt/nem felügyelt határok közötti struktúrák sikeres átadásához további lépésekre van szükség az adatintegritás megőrzése érdekében.

Ez a dokumentum ismerteti a natív struktúrák felügyelt megfelelőinek meghatározásához szükséges lépéseket, valamint azt, hogy az eredményül kapott struktúrák hogyan továbbíthatók a nem felügyelt függvényeknek. Ez a dokumentum feltételezi, hogy egyszerű struktúrákat használnak – amelyek nem tartalmaznak sztringeket vagy mutatókat. A nem blittable interoperabilitásról további információt lásd a C++ Interop (Implicit PInvoke) használata című részt. A P/Invoke nem rendelkezhet nem blittelhető típusokkal visszatérési értékként. A Blittable típusok ugyanazzal a megjelenítéssel rendelkeznek a felügyelt és a nem felügyelt kódban. További információért lásd: Blittable és Non-Blittable típusok.

Az egyszerű, áthelyezhető struktúrák felügyelt és nem felügyelt környezet közötti kezeléséhez először meg kell határozni az egyes natív struktúrák felügyelt verzióit. Ezek a struktúrák bármilyen jogi névvel rendelkezhetnek; az adatelrendezésen kívül nincs kapcsolat a két struktúra natív és felügyelt verziója között. Ezért létfontosságú, hogy a felügyelt verzió olyan mezőket tartalmaz, amelyek mérete megegyezik a natív verzióval. (Nincs olyan mechanizmus, amely biztosítaná, hogy a struktúra felügyelt és natív verziói egyenértékűek legyenek, így a inkompatibilitások csak futási idő után válnak nyilvánvalóvá. A programozó feladata annak biztosítása, hogy a két struktúra azonos adatelrendezésű legyen.)

Mivel a felügyelt struktúrák tagjait néha teljesítmény szempontjából rendezik át, az StructLayoutAttribute attribútummal azt kell jelezni, hogy a struktúra egymás után van elrendezve. Azt is érdemes explicit módon beállítani, hogy a struktúra csomagolási beállítása megegyezik a natív struktúra által használt beállítással. (Bár a Visual C++ alapértelmezés szerint 8 bájtos struktúrát használ mindkét felügyelt kódhoz.)

  1. Ezután olyan belépési pontokat deklarálhat, DllImportAttribute amelyek megfelelnek a struktúrát elfogadó nem felügyelt függvényeknek, de a struktúra felügyelt verzióját használják a függvény szignatúrákban, ami egy jelentéktelen szempont, ha ugyanazt a nevet használja a struktúra mindkét verziójához.

  2. A felügyelt kód mostantól úgy tudja átadni a struktúra felügyelt verzióját a nem felügyelt függvények számára, mintha ténylegesen felügyelt függvények lennének. Ezek a struktúrák átadhatók érték vagy hivatkozás alapján, ahogyan az az alábbi példában is látható.

Nem felügyelt modul és egy felügyelt modul

A következő kód egy nem felügyelt és egy felügyelt modulból áll. A nem felügyelt modul egy DLL, amely egy Hely nevű struktúrát és egy GetDistance nevű függvényt határoz meg, amely elfogadja a helystruktúra két példányát. A második modul egy felügyelt parancssori alkalmazás, amely importálja a GetDistance függvényt, de az MLocation helystruktúra felügyelt megfelelőjeként határozza meg. A gyakorlatban valószínűleg ugyanazt a nevet használnák a struktúra mindkét verziójához; Itt azonban egy másik nevet használunk annak igazolására, hogy a DllImport prototípus a felügyelt verzióban van definiálva.

Vegye figyelembe, hogy a DLL egyetlen része sem érhető el a felügyelt kódnak a hagyományos #include irányelv használatával. Valójában a DLL csak futásidőben érhető el, így a DllImporttal importált függvényekkel kapcsolatos problémák nem észlelhetők fordításkor.

Példa: Nem felügyelt DLL-modul

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

Példa: Felügyelt parancssori alkalmazásmodul

// 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

Lásd még

Explicit PInvoke használata c++ nyelven (DllImport attribútum)