Udostępnij za pośrednictwem


Jak: MARSZAŁEK struktur przy użyciu funkcji PInvoke

Dokument ten wyjaśnia jak native funkcje, których ciągi c styl może być wywołana z zarządzanych funkcje, które zapewniają wystąpienie String przy użyciu P/Invoke.Chociaż zaleca się, aby używać funkcji współdziałania z modelem C++ zamiast P/Invoke, ponieważ P/Invoke zawiera niewiele błąd kompilacji, zgłoszenie nie jest typu bezpiecznej i mogą być nużące wdrożenia, jeśli niezarządzanego API jest dostarczana jako biblioteki DLL, a kod źródłowy nie jest dostępny, P/Invoke jest jedyną opcją.W przeciwnym razie zobacz następujące dokumenty:

Domyślnie struktur macierzystych i zarządzanych są określonymi inaczej w pamięci, więc pomyślnie, przekazując struktur granice zarządzanych/niezarządzanych wymaga wykonania dodatkowych czynności, aby zachować integralność danych.

W tym dokumencie omówiono kroki wymagane do definiowania zarządzanych odpowiedniki macierzystym struktur i jak Struktura wynikowa mogą być przekazywane do niezarządzanego funkcje.Dokument ten zakłada, że proste struktur — tych, które nie zawierają ciągi lub wskaźniki — są używane.Informacje dotyczące interoperacyjności nie istnieć, zobacz Za pomocą Interop C++ (niejawna PInvoke).P/Invoke nie może być niekopiowalne typów wartości zwracanej.Typy istnieć mają taką samą reprezentację kod zarządzany i niezarządzany.Aby uzyskać więcej informacji, zobacz Istnieć i typy niekopiowalne.

Kierowanie proste, struktur istnieć granice zarządzanych/niezarządzanych najpierw wymaga zarządzanych wersje każdej struktury macierzystym zdefiniowania.Struktury te może mieć dowolną nazwę prawnych; nie ma żadnej zależności między macierzystych i zarządzanych wersję struktury dwóch innych niż ich układ danych.Dlatego jest istotne, że zarządzany wersja zawiera pola, które są w taki sam rozmiar i w kolejności macierzystej wersji.(Nie istnieje mechanizm dla zapewnienia, że zarządzane i macierzystej wersji struktury są równoważne, więc niezgodności nie staną się widoczne do czasu wykonywania.Jest programmer's obowiązek zapewnić, że dwie struktury mają ten sam układ danych).

Ponieważ członkowie struktury zarządzanych czasami są przestawiane do celów wykonania, jest konieczne użycie StructLayoutAttribute atrybutu, aby wskazać, że struktury są kolejno określonymi.To jest również jawnie ustawić strukturę pakowania ustawienie być takie same jak te stosowane przez macierzysty struktury.(Chociaż domyślnie Visual C++ korzysta strukturę 8-bajtowe, pakowania, zarówno kodu zarządzanego).

  1. Następnie należy użyć DllImportAttribute Aby zadeklarować punkty wejścia, które odpowiadają niezarządzanego funkcje, których struktura, ale użyć zarządzanych wersję struktury w podpisach funkcja, która jest punkt moot używać tej samej nazwie w obu wersjach struktury.

  2. Teraz kodu zarządzanego można przekazać zarządzanych wersję struktury do niezarządzanego funkcji jak, chociaż są one faktycznie zarządzanej funkcji.Struktury te mogą być przekazywane przez wartość lub przez odwołanie, jak pokazano w następującym przykładzie.

Przykład

Poniższy kod składa się z niezarządzanych i zarządzanych modułu.Moduł niezarządzanego to biblioteki DLL, która definiuje strukturę o nazwie lokalizacji i funkcji o nazwie GetDistance, która akceptuje dwa wystąpienia struktury lokalizacji.Drugi moduł jest zarządzanej aplikacji wiersza polecenia, przywóz funkcji GetDistance, ale definiuje ją z zarządzanych równoważnej konstrukcji lokalizacji MLocation.W praktyce tej samej nazwie prawdopodobnie będzie używany dla obu wersji struktury; Jednakże różnych nazwa jest używana w tym miejscu do wykazania, że prototyp DllImport jest definiowane w kategoriach zarządzanych wersji.

Moduł zarządzany jest kompilowana/CLR, ale/CLR: również czystego programu works.

Uwaga, że żadna jego część biblioteki DLL jest narażony na kod zarządzany, przy użyciu tradycyjnych # dołączona dyrektywa.W rzeczywistości Biblioteka DLL jest dostępny tylko w czasie wykonywania, problemy z funkcjami przywożone z elementu DllImport nie będą wykrywane w czasie kompilacji.

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

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

Zobacz też

Inne zasoby

Za pomocą jawnego PInvoke w C++ (atrybut DllImport)