Not
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Det här dokumentet förklarar hur inbyggda funktioner som accepterar C-format kan anropas från hanterade funktioner med hjälp av P/Invoke. Även om vi rekommenderar att du använder C++ Interop-funktionerna i stället för P/Invoke eftersom P/Invoke ger lite kompileringstidsfelrapportering, inte är typsäker och kan vara omständlig att implementera, om det ohanterade API:et paketeras som en DLL och källkoden inte är tillgänglig, är P/Invoke det enda alternativet. I annat fall kan du läsa följande dokument:
Som standard läggs interna och hanterade strukturer ut på olika sätt i minnet, så för att kunna skicka strukturer över den hanterade/ohanterade gränsen krävs extra steg för att bevara dataintegriteten.
I det här dokumentet beskrivs de steg som krävs för att definiera hanterade motsvarigheter till interna strukturer och hur de resulterande strukturerna kan skickas till ohanterade funktioner. Det här dokumentet förutsätter att enkla strukturer – de som inte innehåller strängar eller pekare – används. Information om icke-blittbar interoperabilitet kan hittas i avsnittet Using C++ Interop (Implicit PInvoke). P/Invoke kan inte ha icke-blittbara typer som ett returvärde. Blittable-typer har samma representation i hanterad och ohanterad kod. Mer information finns i Blittable- och Icke-Blittable-typer.
För att ordna enkla, blittable strukturer över gränsen mellan hanterad och ohanterad kod krävs det först att hanterade versioner av varje inhemsk struktur definieras. Dessa strukturer kan ha valfritt juridiskt namn. Det finns ingen relation mellan den inbyggda och hanterade versionen av de två strukturerna, förutom deras datalayout. Därför är det viktigt att den hanterade versionen innehåller fält som har samma storlek och i samma ordning som den interna versionen. (Det finns ingen mekanism för att säkerställa att de hanterade och inbyggda versionerna av strukturen är likvärdiga, så inkompatibiliteter blir inte uppenbara förrän körningstiden. Det är programmerarens ansvar att se till att de två strukturerna har samma datalayout.)
Eftersom medlemmar i hanterade strukturer ibland ordnas om i prestandasyfte är det nödvändigt att använda StructLayoutAttribute attributet för att indikera att strukturen anges sekventiellt. Det är också en bra idé att uttryckligen ange att inställningen för strukturförpackning ska vara densamma som den som används av den interna strukturen. (Visual C++ använder som standard en 8-bytes strukturpackning för både hanterad kod.)
DllImportAttribute Använd sedan för att deklarera startpunkter som motsvarar alla ohanterade funktioner som accepterar strukturen, men som använder den hanterade versionen av strukturen i funktionssignaturerna, vilket är en diskussionspunkt om du använder samma namn för båda versionerna av strukturen.
Nu kan hanterad kod skicka den hanterade versionen av strukturen till ohanterade funktioner som om de faktiskt är hanterade funktioner. Dessa strukturer kan skickas antingen som värde eller som referens, vilket visas i följande exempel.
Ohanterade och hanterade moduler
Följande kod består av en ohanterad och en hanterad modul. Den ohanterade modulen är en DLL som definierar en struktur som kallas Plats och en funktion som kallas GetDistance som accepterar två instanser av platsstrukturen. Den andra modulen är ett hanterat kommandoradsprogram som importerar funktionen GetDistance, men definierar den i termer av en hanterad motsvarighet till platsstrukturen, MLocation. I praktiken skulle förmodligen samma namn användas för båda versionerna av strukturen. Ett annat namn används dock här för att visa att DllImport-prototypen definieras i termer av den hanterade versionen.
Observera att ingen del av DLL:n exponeras för den hanterade koden med hjälp av det traditionella #include-direktivet. I själva verket nås DLL endast vid körning, så problem med funktioner som importeras med DllImport identifieras inte vid kompileringstillfället.
Exempel: Ohanterad 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;
}
Exempel: Hanterad kommandoradsprogrammodul
// 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