Služby vyvolání platformy - Platform Invocation Services
![]() | tento článek může být pro většinu čtenářů příliš technická na to, aby tomu rozuměli. Prosím pomozte to vylepšit na aby to bylo srozumitelné pro neodborníky, aniž by byly odstraněny technické podrobnosti. (Březen 2015) (Zjistěte, jak a kdy odstranit tuto zprávu šablony) |
Služby vyvolání platformy, běžně označované jako P / Vyvolání, je funkce Společná jazyková infrastruktura implementace, jako Microsoft je Common Language Runtime, který umožňuje spravovaný kód zavolat nativní kód.
Spravovaný kód, jako je C # nebo VB.NET, poskytuje nativní přístup ke třídám, metodám a typům definovaným v knihovnách, které tvoří .NET Framework. Zatímco .NET Framework poskytuje rozsáhlou sadu funkcí, může postrádat přístup k mnoha nižším knihovnám operačních systémů běžně psaných v nespravovaném kódu nebo knihovnám třetích stran, které jsou také psány v nespravovaném kódu. P / Invoke je technika, kterou může programátor použít pro přístup k funkcím v těchto knihovnách. Volání funkcí v rámci těchto knihoven probíhá deklarováním podpisu nespravované funkce ve spravovaném kódu, který slouží jako skutečná funkce, kterou lze volat jako jakoukoli jinou spravovanou metodu. Deklarace odkazuje na cestu k souboru v knihovně a definuje parametry funkce a návrat ve spravovaných typech, u nichž je nejpravděpodobnější, že budou implicitně zařazeny do az nespravovaných typů pomocí společného jazykového běhu (CLR). Když se nespravované datové typy stanou příliš složitými pro jednoduchý implicitní převod za na spravované typy, rozhraní umožňuje uživateli definovat atributy funkce, návratu a / nebo parametrů, aby explicitně upřesnil, jak by měla být data zařazena, aby nebyla vést k výjimkám, když se o to pokusíte implicitně. Ve srovnání s programováním v nespravovaných jazycích je programátorům spravovaného kódu k dispozici mnoho abstrakcí programovacích konceptů nižší úrovně. Ve výsledku bude muset programátor, který má pouze zkušenosti se spravovaným kódem, oprášit koncepty programování, jako jsou ukazatele, struktury a předávání odkazem, aby překonal některé ze základních, ale běžných překážek při používání P / Invoke.
Architektura
Přehled
V současné době se používají dvě varianty P / Invoke:
Výslovný
- Nativní kód se importuje prostřednictvím dynamicky propojené knihovny (DLL)
- Metadata vložený do sestavy volajícího definuje, jak se má nativní kód volat a jak se má přistupovat k datům (obvykle vyžaduje přidělený zdrojový specifikátor, který kompilátoru pomůže generovat maršálské lepidlo)
- Tato definice je součástí „Explicitní“
Implicitní
- Používáním C ++ / CLI, aplikace může současně používat spravovanou haldu (pomocí sledovacích ukazatelů) a libovolnou oblast nativní paměti bez výslovné deklarace. (Implicitní)
- Primární výhodou v tomto případě je, pokud se změní základní nativní datové struktury, pokud je pojmenování kompatibilní, a přelomová změna je zabráněno.
- tj. Přidávání / odebírání / nové uspořádání struktur v nativním záhlaví bude transparentně podporováno, pokud se nezmění také názvy členů struktury.
Detaily
Při použití P / Invoke se CLR rukojeti DLL načítání a konverze neřízený předchozí typy do CTS typy (označované také jako zařazování parametrů).[1][Citace je zapotřebí ]Chcete-li to provést, CLR:
- Vyhledá DLL obsahující funkci.
- Načte DLL do paměti.
- Vyhledá adresu funkce v paměti a posune její argumenty na zásobník, zařazování dat podle potřeby.
P / Invoke je užitečné pro použití standardních (nespravovaných) C nebo C ++ DLL. Může být použit, když programátor potřebuje mít přístup k rozsáhlému Windows API, tolik funkcí poskytuje Knihovny Windows nedostatek k dispozici obaly. Když Win32 API není vystaven .NET Framework obal na to API musí být napsáno ručně.
Úskalí
Psaní obálek P / Invoke může být obtížné a náchylné k chybám. Používání nativních knihoven DLL znamená, že programátor už z nich nebude mít prospěch bezpečnost typu a odvoz odpadu jak je obvykle poskytováno v prostředí .NET. Při nesprávném použití by to mohlo způsobit problémy, jako je poruchy segmentace nebo úniky paměti. Získání přesných podpisů starších funkcí pro použití v .SÍŤ prostředí může být tvrdé, což může mít za následek takové problémy. Za tímto účelem existují nástroje a webové stránky pro získání těchto podpisů, které pomáhají předcházet problémům s podpisy. [1]
Mezi další úskalí patří:
- Nesprávný zarovnání dat uživatelem definované typy ve spravovaném jazyce: existují různé způsoby, jak lze data zarovnat v závislosti na kompilátorech nebo směrnicích kompilátoru v jazyce C a je třeba věnovat pozornost výslovnému CLR jak sladit data pro non-blittable typy. Běžným příkladem toho je, když se pokoušíte definovat datový typ v .NET, který představuje unie v C. Dvě různé proměnné se překrývají v paměti a definování těchto dvou proměnných v typu v .NET by způsobilo, že budou na různých místech v paměti, takže k opravě problému je nutné použít speciální atributy.
- Interference s umístěním dat pomocí garbage collectoru spravovaného jazyka: pokud je odkaz lokální pro metodu v .NET a je předán nativní funkci, když se vrátí spravovaná metoda, může garbage collector tento odkaz znovu získat. Je třeba dbát na to, aby odkaz na objekt byl připnul, zabraňující jeho shromažďování nebo přesunutí garbage collectorem, což by mělo za následek neplatný přístup nativního modulu.
Při použití C ++ / CLI může emitovaná CIL volně komunikovat s objekty umístěnými na spravované haldě a současně s jakýmkoli adresovatelným umístěním nativní paměti. Objekt rezidenta spravované haldy lze volat, upravovat nebo zkonstruovat pomocí jednoduchého pole „object-> field;“ zápis pro přiřazení hodnot nebo určení volání metod. Významné zvýšení výkonu je výsledkem eliminace zbytečného přepínání kontextu, snižují se nároky na paměť (kratší hromádky).
Přichází s novými výzvami:
Tyto odkazy specifikují řešení pro každý z těchto problémů, pokud k nim dojde. Primární výhodou je odstranění deklarace struktury, pořadí deklarace pole a problémy se zarovnáním nejsou v kontextu C ++ Interop přítomny.
Příklady
Základní příklady
Tento první jednoduchý příklad ukazuje, jak získat verzi konkrétního DLL:
DllGetVersion podpis funkce v Windows API:
HRESULT DllGetVersion( DLLVERSIONINFO* pdvi)
P / Vyvolání C# kód pro vyvolání DllGetVersion funkce:
[DllImport ("shell32.dll")]statický externí int DllGetVersion(ref DLLVERSIONINFO pdvi);
Druhý příklad ukazuje, jak extrahovat ikonu v souboru:
ExtractIcon podpis funkce v rozhraní Windows API:
HICON ExtractIcon( ZÁSADA hInst, LPCTSTR lpszExeFileName, UINT nIconIndex);
P / Vyvolání C # kódu pro vyvolání ExtractIcon funkce:
[DllImport ("shell32.dll")]statický externí IntPtr ExtractIcon( IntPtr hInst, [MarshalAs (UnmanagedType.LPStr)] tětiva lpszExeFileName, uint nIconIndex);
Tento další komplexní příklad ukazuje, jak sdílet událost mezi dvěma procesy v Platforma Windows:
CreateEvent podpis funkce:
RUKOJEŤ CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCTSTR lpName );
P / Vyvolání C # kódu pro vyvolání CreateEvent funkce:
[DllImport ("kernel32.dll", SetLastError = true)]statický externí IntPtr CreateEvent( IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, [MarshalAs (UnmanagedType.LPStr)] tětiva lpName);
Složitější příklad
// nativní deklaracetypedef struktur _PÁR { DWORD Val1; DWORD Val2; } PÁR, *PPAIR;
// Zkompilováno s / clr; použití #pragma spravováno / nespravováno může vést ke zdvojnásobení;// vyhnout se použitím samostatného .cpp s .h zahrnuje.// To by bylo umístěno v souboru .h.šablona<>v souladu CLR_PAIR^ marshal_as<CLR_PAIR^, PÁR> (konst PÁR&Src) { // Všimněte si použití de / referencování. Musí odpovídat vašemu použití. CLR_PAIR^ Dest = gcnew CLR_PAIR; Dest->Val1 = Src.Val1; Dest->Val2 = Src.Val2; vrátit se Dest;};
CLR_PAIR^ mgd_pair1;CLR_PAIR^ mgd_pair2;PÁR nativní0,*nativní1=&nativní0;nativní0 = NativeCallGetRefToMemory();// Použití marshal_as. Má smysl pro velké nebo často používané typy.mgd_pair1 = marshal_as<CLR_PAIR^>(*nativní1);// Přímé použití polemgd_pair2->Val1 = nativní0.Val1;mgd_pair2->val2 = nativní0.val2;vrátit se(mgd_pair1); // Zpět na C #
Nástroje
![]() | Tato část je Použití externí odkazy nemusí dodržovat zásady nebo pokyny Wikipedie.listopad 2013) (Zjistěte, jak a kdy odstranit tuto zprávu šablony) ( |
Existuje řada nástrojů, které jsou navrženy tak, aby napomáhaly výrobě podpisů P / Invoke.
Zápis obslužné aplikace, která by importovala soubory záhlaví C ++ a nativní DLL soubory a vytvořit sestavu rozhraní se automaticky ukáže být docela obtížné. Hlavním problémem při výrobě takového dovozce / vývozce pro podpisy P / Invoke je nejednoznačnost některých typů parametrů volání funkcí C ++.
Brad Abrams k tomu říká: Problém P / Vyvolání.
Problém spočívá ve funkcích C ++, jako jsou následující:
__declspec(dllexport) prázdnota MyFunction(char *parametry);
Jaký typ bychom měli použít pro parametr parametry v našem podpisu P / Invoke? Může to být buď řetězec zakončený nulou C ++, nebo to může být char pole nebo může být výstupem char parametr. Měli bychom tedy použít tětiva, StringBuilder, char [] nebo ref char ?
Bez ohledu na tento problém existuje několik nástrojů, které usnadňují výrobu podpisů P / Invoke.
Jeden z níže uvedených nástrojů, xInterop C ++ .NET Bridge vyřešil tento problém implementací více přepsání stejné metody C ++ ve světě .NET, vývojáři pak mohou vybrat ten správný pro uskutečnění hovoru.
PInvoke.net
PInvoke.net je wiki obsahující podpisy P / Invoke pro velké množství standardních Windows API. Je ve vlastnictví Software Redgate a má přibližně 50 000 přístupů za měsíc.
Podpisy jsou ručně vytvářeny uživateli wiki. Lze je prohledávat pomocí a doplněk zdarma na Microsoft Visual Studio.
PInvoker
PInvoker je aplikace, která importuje nativní soubory DLL a soubory C ++ .h a exportuje plně vytvořené a kompilované P / Vyvolání interop DLL. Překonává problém nejednoznačnosti zabalením parametrů funkce nativního ukazatele do tříd rozhraní .NET specifických pro PInvoker. Místo použití standardních typů parametrů .NET v definicích metod P / Invoke (char [], tětivaatd.) používá tyto třídy rozhraní při volání funkce P / Invoke.
Například pokud vezmeme v úvahu výše uvedený ukázkový kód, PInvoker by vytvořil .NET P / Vyvolání funkce přijímající třídu rozhraní .NET, která obaluje nativní char * ukazatel. Konstrukce této třídy by mohla být z a tětiva nebo z a char [] pole. Skutečná struktura nativní paměti pro oba je stejná, ale příslušné konstruktory třídy rozhraní pro každý typ naplní paměť různými způsoby. Odpovědnost za rozhodování o tom, jaký typ .NET je třeba předat do funkce, je proto předána vývojáři.
Microsoft Interop Assistant
Microsoft Interop Assistant je bezplatný nástroj s binárními soubory a zdrojovým kódem ke stažení na webu CodePlex. Je licencován pod Omezená veřejná licence společnosti Microsoft (Ms-LPL).
Má dvě části:
- Převaděč, který bere malé sekce nativního kódu souboru záhlaví C ++ obsahujícího struktur a definice metod. Poté vytvoří kód C # P / Invoke, který můžete zkopírovat a vložit do svých aplikací.
- Prohledávatelná databáze převedených definic konstanty, metody a struktury rozhraní Windows API.
Protože tento nástroj produkuje C # zdrojový kód spíše než kompilovanou dll, uživatel může před použitím provést jakékoli změny nezbytné v kódu. Problém nejednoznačnosti je tedy vyřešen tím, že aplikace vybere jeden konkrétní typ .NET, který se použije v podpisu metody P / Invoke, a pokud to bude nutné, uživatel to může změnit na požadovaný typ.
P / Vyvolat průvodce
The P / Vyvolat průvodce používá podobnou metodu jako Microsoft Interop Assistant v tom, že přijímá nativní kód souboru C ++ .h a vytváří kód C # (nebo VB.NET), který můžete vložit do kódu aplikace .NET.
Má také možnosti, na které rozhraní chcete cílit: .NET Framework pro stolní počítače nebo .NET Compact Framework pro inteligentní zařízení Windows Mobile (a Windows CE).
xInterop C ++ .NET Bridge
xInterop C ++ .NET Bridge je aplikace systému Windows pro vytvoření obálky C # pro nativní knihovny C ++ DLL a most C ++ pro přístup k sestavením .NET, přichází s knihovnou C # /. NET, která obaluje standardní třídy C ++, jako jsou řetězce, iostream atd., C ++ třídy a objekty lze přistupovat z .NET.
Tento nástroj generuje obálky C # DLL se zdrojovým kódem z existujících nativních knihoven C ++ DLL a přidružených souborů záhlaví, které jsou nástrojem vyžadovány k vytvoření C # obálky DLL. Podpisy P / Invoke a zařazování dat jsou generovány aplikací. Výsledná obálka C # má podobné rozhraní protějšku C ++ s typem parametru převedeným na kód .NET.
Tento nástroj rozpoznává třídy šablon, které se neexportují z C ++ DLL, a vytváří instanci třídy šablon a exportuje je v doplňkové knihovně DLL a odpovídající rozhraní C ++ lze použít v .NET.
Viz také
- Bleskové typy
- Nativní rozhraní Java, standardní způsob přístupu programů Java k nativnímu kódu
- Nativní přístup Java, Java ekvivalent P / Invoke
- Soubory knihovny Windows
- J / Direct, již neudržované ekvivalentní API pro Virtuální stroj Microsoft Java
Reference
- ^ Zařazování parametrů nelze zaměňovat s obecným pojmem seřaďování, význam Serializace. Zařazené parametry jsou zkopírovány do souboru CLR stack po jejich převodu na CTS typy, ale nejsou serializovány.
- ^ https://docs.microsoft.com/en-us/cpp/dotnet/double-thunking-cpp
- ^ https://docs.microsoft.com/en-us/cpp/dotnet/initialization-of-mixed-assemblies
externí odkazy
- Web věnovaný P / Invoke
- J / Vyvolat Přístup Java ke sdíleným knihovnám API Win32 API nebo Linux / Mac OS X, podobně jako P / Invoke
- [2] Implicitní P / Invoke se zvláštním zaměřením na techniky pro rozšíření na zařazovací šablonu
- 3 články společnosti Microsoft kontrastující s těmito metodami, Používání Explicit PInvoke, Implicitní C ++ Interop a "Bližší pohled na Vyvolání platformy"
- Microsoft Interop Assistant Hlavní stránka Microsoft Interop Assistant.
- P / Vyvolat průvodce Domovská stránka průvodce P / Invoke Wizard.
- PInvoker Hlavní stránka PInvoker.
- xInterop C ++ .NET Bridge Hlavní stránka xInterop C ++ .NET Bridge