Porady: kierowanie wskaźników osadzonych za pomocą funkcji PInvoke
Funkcje, które są implementowane w niezarządzanych bibliotek DLL może być wywołana z kod zarządzany przy użyciu funkcji wywołanie platformy (P i Invoke).Jeśli kod źródłowy dla biblioteki DLL nie jest dostępny, P/Invoke jest jedyną opcją dla współdziałania.Jednak w przeciwieństwie do innych języków .NET, Visual C++ stanowi alternatywę dla P i Invoke.Aby uzyskać więcej informacji, zobacz Korzystanie z międzyoperacyjności języka C++ (niejawna funkcja PInvoke) i Porady: kierowanie wskaźników osadzonych za pomocą międzyoperacyjności języka C++.
Przykład
Przekazywanie struktur do kodu macierzystego wymaga utworzenia struktury zarządzanej, pod względem układu danych odpowiada strukturze macierzystego.Jednakże struktury, które zawierają wskaźniki wymagają specjalnego traktowania.Dla każdego wskaźnika osadzone w strukturze macierzystego, zarządzane wersję struktury powinien zawierać wystąpienie IntPtr typu.Ponadto pamięci dla wystąpienia tych muszą zostać jawnie przypisane, zainicjowany i zwolniony przy użyciu AllocCoTaskMem, StructureToPtr, i FreeCoTaskMem metody.
Poniższy kod składa się z modułu zarządzane i niezarządzane.Moduł niezarządzanych to biblioteki DLL, która definiuje funkcję, która akceptuje strukturę o nazwie ListString, który zawiera wskaźnik i funkcji o nazwie TakesListStruct.Moduł zarządzany jest aplikacją wiersza polecenia, że przywóz funkcji TakesListStruct i definiuje strukturę o nazwie MListStruct, które jest równoważne z ListStruct macierzystego, chyba że podwójne * jest reprezentowany IntPtr wystąpienie.Przed wywołaniem TakesListStruct, którego główna funkcja przydziela i inicjalizuje pamięć, która odwołuje się do tego pola.
Moduł zarządzany jest skompilowany z/CLR, ale/CLR: pure działa jak również.
// 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]);
}
// 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);
}
Należy zauważyć, że żadna część biblioteki DLL jest narażony na kod zarządzany przy użyciu tradycyjnych # dyrektywy include.W rzeczywistości, biblioteka DLL jest dostępny tylko w czasie wykonywania, więc problemów z funkcjami importowane z DllImportAttribute nie zostaną wykryte w czasie kompilacji.
Zobacz też
Inne zasoby
Używanie jawnej funkcji PInvoke w języku C++ (atrybut DllImport)