Jak: Marshal polí pomocí PInvoke
Toto téma popisuje, jak mohou být nativní funkce, které přijímají řetězce ve stylu jazyka C, volány pomocí řetězce typu CLR použitím String podpory volání nespravovaného kódu rozhraní .NET Framework. Programátoři jazyka Visual C++ místo toho používají funkce Interop jazaky C++ (pokud je to možné) protože P/Invoke poskytuje malé vykazování chyb při rychlosti kompilace, což není typově bezpečné a může to být zdlouhavé pro implementaci.Pokud je nespravované rozhraní API zabaleno jako DLL knihovna a není k dispozici zdrojový kód, pak je P/Invoke jedinou možností (jinak, viz Použití interoperability C++ (implicitní PInvoke)).
Příklad
Vzhledem k tomu, že nativní a spravované pole jsou rozloženy odlišně v paměti, vyžaduje úspěšný přechod přes spravovanou/nespravovanou hranici převod nebo zařazení.Toto téma ukazuje, jak může být pole jednoduchých (blitable) položek předáno nativním funkcím ze spravovaného kódu.
V obecném zařazování spravovaných/nespravovaných dat slouží atribut DllImportAttribute k vytváření spravovaného vstupního bodu pro každou nativní funkci, která bude použita. V případě funkcí, které přijímají pole jako argumenty, musí být použit atribut MarshalAsAttribute také k určení kompilátoru, jak budou data zařazována. V následujícím příkladu se používá výčet LPArray k označení, že bude spravované pole zařazeno jako pole ve stylu jazyka C.
Následující kód se skládá z nespravovaného a spravovaného modulu.Nespravovaný modul je knihovna DLL, definující funkci, která přijímá pole celých čísel.Druhý modul je spravovaná aplikace příkazové řádky, která importuje tuto funkci, ale definuje ji z hlediska spravovaného pole a používá atribut MarshalAsAttribute k určení, že by mělo být pole převedeno při volání na nativní pole.
Spravovaný modul je kompilován se /clr, ale /clr:pure pracuje stejně dobře.
// 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]);
}
// 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]);
}
Všimněte si, že žádná část knihovny DLL není zpřístupněna spravovanému kódu přes tradiční direktivy #include.Je tomu tak, protože 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)