Vorgehensweise: Marshal-Arrays mit P/Invoke

Sie können systemeigene Funktionen aufrufen, die Zeichenfolgen im C-Stil akzeptieren, indem Sie den CLR-Zeichenfolgentyp String verwenden, wenn Sie die Unterstützung von .NET Framework Platform Invoke (P/Invoke) verwenden. Wir empfehlen Ihnen, die C++-Interopfeatures anstelle von P/Invoke zu verwenden, wenn möglich. P/Invoke bietet wenig Kompilierungszeitfehlerberichterstattung, ist nicht typsicher und kann nicht implementiert werden. Wenn die nicht verwaltete API als DLL verpackt ist und der Quellcode nicht verfügbar ist, ist P/Invoke die einzige Option. Andernfalls siehe Verwenden der C++-Interoperabilität (impliziter P/Aufruf)).

Beispiel

Da systemeigene und verwaltete Arrays im Arbeitsspeicher unterschiedlich angeordnet sind, müssen sie erfolgreich über die verwalteten/nicht verwalteten Grenzen hinweg konvertiert oder gemarstet werden. In diesem Artikel wird veranschaulicht, wie ein Array einfacher (durchlässiger) Elemente aus verwaltetem Code an systemeigene Funktionen übergeben werden kann.

Wie bei verwalteten/nicht verwalteten Datenmarsing im Allgemeinen gilt, wird das DllImportAttribute Attribut verwendet, um einen verwalteten Einstiegspunkt für jede systemeigene Funktion zu erstellen, die verwendet wird. In Funktionen, die Arrays als Argumente verwenden, muss das MarshalAsAttribute Attribut verwendet werden, um anzugeben, wie die Daten gemarsiert werden sollen. Im folgenden Beispiel wird die UnmanagedType Enumeration verwendet, um anzugeben, dass das verwaltete Array als C-Formatarray gemarstet wird.

Der folgende Code besteht aus einem nicht verwalteten und einem verwalteten Modul. Das nicht verwaltete Modul ist eine DLL, die eine Funktion definiert, die ein Array ganzzahliger Zahlen akzeptiert. Das zweite Modul ist eine verwaltete Befehlszeilenanwendung, die diese Funktion importiert, aber in Bezug auf ein verwaltetes Array definiert. Es verwendet das MarshalAsAttribute Attribut, um anzugeben, dass das Array bei Aufruf in ein systemeigenes Array konvertiert werden soll.

// TraditionalDll4.cpp
// compile with: /LD /EHsc
#include <iostream>

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

extern "C" {
   TRADITIONALDLL_API void TakesAnArray(int len, int[]);
}

void TakesAnArray(int len, int a[]) {
   printf_s("[unmanaged]\n");
   for (int i=0; i<len; i++)
      printf("%d = %d\n", i, a[i]);
}

Das verwaltete Modul wird mithilfe /clrvon .

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

value struct TraditionalDLL {
   [DllImport("TraditionalDLL4.dll")]
   static public void TakesAnArray(
   int len,[MarshalAs(UnmanagedType::LPArray)]array<int>^);
};

int main() {
   array<int>^ b = gcnew array<int>(3);
   b[0] = 11;
   b[1] = 33;
   b[2] = 55;
   TraditionalDLL::TakesAnArray(3, b);

   Console::WriteLine("[managed]");
   for (int i=0; i<3; i++)
      Console::WriteLine("{0} = {1}", i, b[i]);
}

Kein Teil der DLL wird über die herkömmliche #include Direktive für den verwalteten Code verfügbar gemacht. Da zur Laufzeit nur auf die DLL zugegriffen wird, können Probleme in funktionen, die mithilfe der Verwendung DllImportAttribute importiert werden, zur Kompilierungszeit nicht erkannt werden.

Siehe auch

Verwenden expliziter P/Invoke in C++ (DllImport Attribut)