Postupy: Zařazení vložených ukazatelů pomocí PInvoke
Funkce, které jsou implementovány v nespravovaných knihovnách DLL lze volat ze spravovaného kódu pomocí funkce volání nespravovaného kódu (P/Invoke). Pokud není k dispozici zdrojový kód pro knihovnu DLL, P/Invoke je jedinou možností pro spolupráci. Nicméně na rozdíl od jiných jazyků .NET, poskytuje jazyk Visual C++ alternativu k P/Invoke. Další informace naleznete v tématu Použití interoperability C++ (implicitně PInvoke) a Postupy: Zařazení vložených ukazatelů pomocí C++ Interop.
Příklad
Předání struktur k nativnímu kódu vyžaduje, že je vytvořena spravovaná struktura, která je ekvivalentní z hlediska rozložení dat k nativní struktuře. Nicméně, struktury, které obsahují ukazatele, vyžadují zvláštní zpracování. Pro každý vložený ukazatel v nativní struktuře, by měla spravovaná verze struktury obsahovat instance k typu IntPtr. Také paměť pro tyto instance musí být explicitně přidělena, inicializována a uvolněna pomocí metod AllocCoTaskMem, StructureToPtr a FreeCoTaskMem.
Následující kód se skládá z nespravovaného a spravovaného modulu. Nespravovaným modulem je knihovna DLL, definující funkci, která přijímá strukturu s názvem ListString, která obsahuje ukazatel a funkci nazvanou TakesListStruct. Spravovaným modulem je příkazový řádek aplikace, který importuje funkci TakesListStruct a definuje strukturu, nazvanou MListStruct, která je ekvivalentní k nativní ListStruct s tím rozdílem, že double* je vyjádřena instancí IntPtr. Před voláním TakesListStruct, hlavní funkce přidělí a inicializuje paměť, která odkazuje na toto pole.
Spravovaný modul je kompilován se /clr, ale /clr:pure pracuje stejně dobře.
// 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);
}
Všimněte si, že žádná část knihovny DLL není zpřístupněna spravovanému kódu použitím tradiční direktivy #include. Ve skutečnosti je knihovna DLL přístupná pouze za běhu, takže problémy s funkcemi, které jsou importovány s DllImportAttribute nejsou během kompilace odhaleny.
Viz také
Další zdroje
Použití explicitního PInvoke v jazyce C++ (atribut DllImport)