Delen via


Handleiding: Marshal embedded pointers using P/Invoke

Functies die zijn geïmplementeerd in niet-beheerde DLL's, kunnen worden aangeroepen vanuit beheerde code met behulp van de functionaliteit Platform Invoke (P/Invoke). Als de broncode voor het DLL-bestand niet beschikbaar is, is P/Invoke de enige optie voor samenwerking. In tegenstelling tot andere .NET-talen biedt Visual C++ echter een alternatief voor P/Invoke. Zie C++ Interop gebruiken (impliciete P/Aanroepen) en Instructies: Marshal embedded pointers met C++ Interop voor meer informatie.

Voorbeeld

Het doorgeven van structuren aan systeemeigen code vereist dat een beheerde structuur die gelijk is aan de gegevensindeling voor de systeemeigen structuur wordt gemaakt. Structuren die aanwijzers bevatten, vereisen echter speciale verwerking. Voor elke ingesloten aanwijzer in de systeemeigen structuur moet de beheerde versie van de structuur een exemplaar van het IntPtr type bevatten. Daarnaast moet geheugen voor deze exemplaren expliciet worden toegewezen, geïnitialiseerd en vrijgegeven met behulp van de AllocCoTaskMemStructureToPtr, en FreeCoTaskMem methoden.

De volgende code bestaat uit een niet-beheerde en een beheerde module. De niet-beheerde module is een DLL die een functie definieert die een structuur accepteert die een aanwijzer ListString bevat en een functie die wordt aangeroepen TakesListStruct.

// TraditionalDll6.cpp
// compile with: /EHsc /LD
#include <stdio.h>
#include <iostream>
#define TRADITIONALDLL_EXPORTS
#ifdef TRADITIONALDLL_EXPORTS
#define TRADITIONALDLL_API __declspec(dllexport)
#else
#define TRADITIONALDLL_API __declspec(dllimport)
#endif

#pragma pack(push, 8)
struct ListStruct {
   int count;
   double* item;
};
#pragma pack(pop)

extern "C" {
   TRADITIONALDLL_API void TakesListStruct(ListStruct);
}

void TakesListStruct(ListStruct list) {
   printf_s("[unmanaged] count = %d\n", list.count);
   for (int i=0; i<list.count; i++)
      printf_s("array[%d] = %f\n", i, list.item[i]);
}

De beheerde module is een opdrachtregeltoepassing die de TakesListStruct functie importeert en een structuur MListStruct definieert die gelijk is aan de systeemeigen ListStruct , behalve dat de double* wordt weergegeven met een IntPtr exemplaar. Voordat TakesListStruct wordt aangeroepen, wijst de main-functie het geheugen toe en initialiseert dit voor het veld waarnaar de verwijzing verwijst.

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

[StructLayout(LayoutKind::Sequential, Pack=8)]
value struct MListStruct {
   int count;
   IntPtr item;
};

value struct TraditionalDLL {
    [DllImport("TraditionalDLL6.dll")]
   static public void TakesListStruct(MListStruct);
};

int main() {
   array<double>^ parray = gcnew array<double>(10);
   Console::WriteLine("[managed] count = {0}", parray->Length);

   Random^ r = gcnew Random();
   for (int i=0; i<parray->Length; i++) {
      parray[i] = r->NextDouble() * 100.0;
      Console::WriteLine("array[{0}] = {1}", i, parray[i]);
   }

   int size = Marshal::SizeOf(double::typeid);
   MListStruct list;
   list.count = parray->Length;
   list.item = Marshal::AllocCoTaskMem(size * parray->Length);

   for (int i=0; i<parray->Length; i++) {
      IntPtr t = IntPtr(list.item.ToInt32() + i * size);
      Marshal::StructureToPtr(parray[i], t, false);
   }

   TraditionalDLL::TakesListStruct( list );
   Marshal::FreeCoTaskMem(list.item);
}

Er wordt geen deel van het DLL-bestand blootgesteld aan de beheerde code met behulp van de traditionele #include instructie. In feite wordt het DLL-bestand alleen tijdens runtime geopend, dus problemen in functies die worden geïmporteerd met behulp DllImportAttribute van, kunnen niet worden gedetecteerd tijdens het compileren.

Zie ook

Expliciete P/Invoke gebruiken in C++ (DllImport kenmerk)