La presentazione è in caricamento. Aspetta per favore

La presentazione è in caricamento. Aspetta per favore

Mixed code: C++/CLI Raffaele Rialdi Visual Developer Security MVP MVP Profile:

Presentazioni simili


Presentazione sul tema: "Mixed code: C++/CLI Raffaele Rialdi Visual Developer Security MVP MVP Profile:"— Transcript della presentazione:

1 Mixed code: C++/CLI Raffaele Rialdi Visual Developer Security MVP MVP Profile:

2 Agenda Perché usare C++... perché C++/CLIPerché usare C++... perché C++/CLI Carrellata sul linguaggioCarrellata sul linguaggio –solo gli elementi del linguaggio utili per interop –gestione della memoria managed/unmanaged –pinning e marshalling –mixed types C++ future directionsC++ future directions

3 Perché usare C++ Rende semplice usare codice unmanagedRende semplice usare codice unmanaged –Le definizioni PInvoke non sono sempre semplici da scrivere –VC++ usa IJW (It Just Works) per usare codice nativo e codice managed allo stesso tempo –Ad esempio si semplifica l'accesso alle librerie DirectX –VC++ può creare dll/exe misti con codice C# / VB / C++ Rende semplice usare codice managedRende semplice usare codice managed –System.Xml semplifica la manipolazione di Xml –System.Net semplifica l'accesso ai socket e al web –System.Text.RegularExpressions semplifica le regex –Idem per altre namespace/classi del framework

4 Perché un nuovo linguaggio? Perché C++/CLI? Le managed extensions erano complesse per aderire alle regole dello standard ISO (doppio underscore, etc.)Le managed extensions erano complesse per aderire alle regole dello standard ISO (doppio underscore, etc.) –cl /clr:oldSyntax continua a compilare le managed extensions –un tool di Stan Lippman permette una migrazione quasi automatica C++/CLI è vicino alla standardizzazione ECMA (in questi giorni) ed ISO (probabilmente chiamata ISO C++09)C++/CLI è vicino alla standardizzazione ECMA (in questi giorni) ed ISO (probabilmente chiamata ISO C++09) C++/CLI ha una piacevole sintassi per lavorare sia con il mondo managed che unmanagedC++/CLI ha una piacevole sintassi per lavorare sia con il mondo managed che unmanaged C++ Features Finalizzazione deterministicaFinalizzazione deterministica Template e genericsTemplate e generics Uso dei tipi nativiUso dei tipi nativi Multiple inheritance (unmanaged)Multiple inheritance (unmanaged) STL, algoritmi genericiSTL, algoritmi generici Distinzione Puntatore/PuntatoDistinzione Puntatore/Puntato Copy construction, assignmentCopy construction, assignment CLR Features Garbage collector, finalizzatoriGarbage collector, finalizzatori GenericsGenerics Reference e Value typeReference e Value type InterfacceInterfacce VerificabilitàVerificabilità SecuritySecurity Proprietà, delegati, eventiProprietà, delegati, eventi

5 Novità in C++/CLI di cui non parleremo trivial properties: property String ^Name;trivial properties: property String ^Name; indexed propertiesindexed properties managed copy constructorsmanaged copy constructors delegate + eventdelegate + event managed operator overloadingmanaged operator overloading boxing/unboxingboxing/unboxing safe_cast<>safe_cast<> generics vs templatesgenerics vs templates method overridingmethod overriding lock(...)lock(...) jagged arraysjagged arrays STL.NETSTL.NET integrazione MFC / Winformintegrazione MFC / Winform integrazione Avalonintegrazione Avalon compilazione parallelacompilazione parallela profile guided optimizationprofile guided optimization OpenMP parallelismOpenMP parallelism CLR Delay LoadingCLR Delay Loading

6 Veloce carrellata su C++/CLI Supporto distinto per tipi managed e unmanagedSupporto distinto per tipi managed e unmanaged C++/CLIC# public ref class MyClass {... } ; public ref struct MyClass {... } ; MyClass ^c = gcnew MyClass(); public class MyClass {... } MyClass c = new MyClass(); public value class MyValueType {... } ; public value struct MyValueType {... } ; MyValueType v; public struct MyValueType {... } MyValueType v; public interface class MyInterface {... } ; public interface struct MyInterface {... } ; public interface MyInterface {... } public enum class MyEnum : char {... } ; public enum struct MyEnum : char {... } ; public enum MyEnum : char {... } array ^nums = {1,2,3} ; int[] nums = new int[] {1,2,3} Le specifiche si trovano qui:

7 I nuovi operatori ^ e % Introdotto nel linguaggio l' "handle"Introdotto nel linguaggio l' "handle" –una sorta di puntatore managed ad un oggetto nel managed heap –Il CLR tiene aggiornato il suo valore quando esegue la GC –analogo del reference di C#, ma il reference in C++ esisteva già –il simbolo è "hat" ^ –su un handle si applicano gli operatori -> e * –L'analogo di void* è Object^ Nuovo allocatore di memoria managed gcnewNuovo allocatore di memoria managed gcnew –String ^s1 = gcnew String; –String s2; continua ad essere un espressione valida Introdotto nel linguaggio il "tracking reference"Introdotto nel linguaggio il "tracking reference" –Analogo del reference & di C++ classico, cioè un alias all'oggetto –il simbolo è "%"

8 Distruzione deterministica C++/CLI introduce la distruzione deterministica delle risorseC++/CLI introduce la distruzione deterministica delle risorse –Non deve e non può riguardare la memoria, ma solo le risorse unmanaged. Questo è lo scopo del pattern Dispose. –In pratica il Pattern Dispose viene implementato dal compilatore Implementazione completa di GC.SuppressFinalizeImplementazione completa di GC.SuppressFinalize Quando nella classe esiste il distruttore:Quando nella classe esiste il distruttore: –In sostanza il distruttore della classe viene mappato su Dispose –La classe implementa automaticamente IDisposable –L'uscita dallo scope o una delete esplicita provoca la chiamata a Dispose (analogo dello statement using di C#, ma più semplice) Introdotto anche la sintassi per il finalizzatoreIntrodotto anche la sintassi per il finalizzatore –La sintassi è analoga al distruttore !NomeClasse() {...} –Nel finalizzatore si mette la distruzione delle risorse –Nella Dispose si mette la chiamata al finalizzatore

9 Istruire il precompilatore Il compilatore VC++ accetta di mixare codice managed e unmanaged anche nello stesso listatoIl compilatore VC++ accetta di mixare codice managed e unmanaged anche nello stesso listato –Alcune volte potrebbe esserci ambiguità su come compilare il codice Si può informare il compilatore con due #pragmaSi può informare il compilatore con due #pragma –#pragma managed –#pragma unmanaged #pragma managed class Managed {...} ; #pragma unmanaged class Native {...} ; #pragma managed...

10 Memoria: Interior Pointers Al contrario dell'handle, permette l'aritmetica dei puntatoriAl contrario dell'handle, permette l'aritmetica dei puntatori Utile per la veloce manipolazione di array e bufferUtile per la veloce manipolazione di array e buffer Trasparente: è usabile anche per tipi unmanaged (restituisce un puntatore classico)Trasparente: è usabile anche per tipi unmanaged (restituisce un puntatore classico) interior_ptr name = &value; Esempio 1 array ^a = {1,2,3,4,5}; interior_ptr ip = &a[0]; for(int i = 0; i Length; i++) Console::WriteLine(++ip[i]); // output: 2, 3, 4, 5, 6 Esempio 2 String ^str1 = "Hello, world"; String ^str2 = str1; interior_ptr ip = &str1; *ip = "Ciao"; Console::WriteLine(str1 + " - " + str2); // output: Ciao – Hello, world

11 Memoria: Pinning Pointers Unmanaged Pointer T* Pinning Pointer pin_ptr Pinning Pointer pin_ptr Interior Pointer interior_ptr Interior Pointer interior_ptr pin_ptr name = &value; void F(int* p);// Func unmanaged array ^ arr = …; pin_ptr pi = &arr[0]; F(pi);// ptr unmanaged String ^str1 = "Hello, world"; // interior pointer al buffer della stringa (non è una copia) interior_ptr ip = PtrToStringChars(str1); // interior pointer senza 'const' interior_ptr ip2 = const_cast >(ip); // pinning pointer Il GC non può muovere il buffer pin_ptr pp = ip2; // modifico il buffer for(int i=0; i Length; i++) ++pp[i];// caratteri ascii incrementati Console::WriteLine(str1);// out Ifmmp-!xpsme

12 Stack locale Managed heap GC muove i blocchi di memoria GC aggiorna i valori quando muove la memoria GC aggiorna i valori quando muove la memoria Sguardo molto semplicistico in memoria Unmanaged heap memoria classica sempre ferma memoria classica sempre ferma MyClass1 &rc = *pc; // rc è un "reference" alias sizeof(MyClass1) // pc è un "puntatore" MyClass1 *pc = new MyClass1(0x30); gg.hh.jj.kkgg.hh.jj.kk gg.hh.jj.kkgg.hh.jj.kk MyClass1 *pc2 = pc; xx.yy.zz.ttxx.yy.zz.tt size unknown MyClass2 ^hc = gcnew MyClass2(); // hc è un handle. ^ si pronuncia hat MyRefType %tr = *hc; // tr è un "tracking reference" pinned pin_ptr pp = &hc; pin_ptr pp2 = pp; ll.mm.nn.ooll.mm.nn.oo // pp e pp2 sono "pinning pointers" pp.qq.rr.sspp.qq.rr.ss interior_ptr ip = &hc; // ip è un "interior pointer"

13 Marshalling di stringhe Stringhe Ansi Managed Unmanaged Unmanaged Managed Marshal::StringToHGlobalAnsiMarshal::PtrToStringAnsi Stringhe Unicode Managed Unmanaged Unmanaged Managed PtrToStringChars (#include ) Marshal::PtrToStringUni Stringhe COM (BSTR) Managed Unmanaged Unmanaged Managed Marshal::StringToBSTRMarshal::PtrToStringBSTR

14 È tutto così semplice?... quasi Fin ad ora abbiamo visto che:Fin ad ora abbiamo visto che: –Creare immagini miste managed/unmanaged è semplice –Eseguire il marshalling dei parametri è semplice –Ci sono semplici strumenti per accedere alla memoria managed e unmanaged –L'interoperabilità è possibile in due modi: P/Invoke esplicito (come in C#)P/Invoke esplicito (come in C#) IJW (=It Just Works) eseguendo il marshalling dei parametriIJW (=It Just Works) eseguendo il marshalling dei parametri E allora dov'è il problema?E allora dov'è il problema?

15 Mixed types are not supported public ref class RefClass { public: POINT pt; // unmanaged struct }; public class Native { public: System::String ^str; }; error C4368: cannot define 'pt' as a member of managed 'ManagedClass': mixed types are not supported error C3265: cannot declare a managed 'str' in an unmanaged 'Native'

16 Tipi misti: tipi managed dentro tipi unmanaged GCHandleGCHandle gcroot<>gcroot<> –necessita #include –necessita #include –non chiama automaticamente Dispose! msclr::auto_gcroot<>msclr::auto_gcroot<> –necessita #include –necessita #include –chiama automaticamente la IDisposable::Dispose se esiste #include using namespace System; public class Native1 { gcroot str; }; #include using namespace System; public class Native1 { gcroot str; }; #include using namespace msclr; using namespace System; public class Native2 { auto_gcroot str; }; #include using namespace msclr; using namespace System; public class Native2 { auto_gcroot str; };

17 Tipi misti: tipi unmanaged dentro tipi managed Brutta notizia: fin'ora nessun supporto ufficiale ma la soluzione è molto semplice....Brutta notizia: fin'ora nessun supporto ufficiale ma la soluzione è molto semplice.... In una classe managed si può avere un puntatore unmanagedIn una classe managed si può avere un puntatore unmanaged –ma è poi necessario gestire la sua distruzione (ciclo di vita) Molto meglio scrivere una classe con template che gestisce il ciclo di vita del puntatoreMolto meglio scrivere una classe con template che gestisce il ciclo di vita del puntatore –Brandon Bray (uno degli ideatori della nuova sintassi) ne ha pubblicata una chiamata "Embedded" sul suo blog #include #include "Embedded.h" public ref class RefClass { Embedded np; }; #include #include "Embedded.h" public ref class RefClass { Embedded np; };

18 Cosa sono le calling convention? Una sorta di contratto alla compilazione che prevede:Una sorta di contratto alla compilazione che prevede: –come passare gli argomenti delle funzioni ed il valore di ritorno –quali registri della CPU devono essere salvati Le quattro convenzioni più usate oggi sono:Le quattro convenzioni più usate oggi sono: __cdeclusato dalle librerie C e numerose API__cdeclusato dalle librerie C e numerose API __stdcallconosciuta anche come "pascal", usata dalle Win32 API__stdcallconosciuta anche come "pascal", usata dalle Win32 API __fastcallusa i registri per passare gli argomenti__fastcallusa i registri per passare gli argomenti __thiscalldefault per le chiamate a funzioni membro in C++__thiscalldefault per le chiamate a funzioni membro in C++

19 Cos'è il "double thunking"? Quando si compila codice con metadati ogni funzione ha due entry-point:Quando si compila codice con metadati ogni funzione ha due entry-point: –uno con la calling-convention assegnata –uno con la calling-convention CLR Quale viene usato?Quale viene usato? –se il codice è compilato con /clr, l'entry-point di base è un thunk alla chiamata CLR –se il codice è compilato senza /clr, l'entry point CLR è un thunk alla chiamata x86 Come viene scelto l'entry-point da usarsi?Come viene scelto l'entry-point da usarsi? –il compilatore è normalmente in grado di scegliere ma... –non può scegliere se la chiamata è un puntatore a funzione –non può scegliere anche per le funzioni virtuali perché queste sono puntatori a funzioni

20 Cos'è il "double thunking"? Dove si presenta il problema?Dove si presenta il problema? –Le funzioni virtuali compilate in IL avranno sempre un thunk da unmanaged a managed. Questo è inevitabile. –Se poi la chiamata viene fatta da codice managed, c'è un thunk supplementare: managed unmanaged managed Questo doppio passaggio si chiama "double thunking" Esiste una soluzione?Esiste una soluzione? –La soluzione esiste solo se quella chiamata virtuale verrà solo chiamata dal mondo managed –In questo caso è sufficiente marcare la funzione con la convenzione __clrcall –forzando __clrcall si evita il double thunking virtual return-type __clrcall function-name(arguments);

21 Un assembly, mixed language Task complesso, nessun supporto di VS2005Task complesso, nessun supporto di VS2005 Più semplice se si disabilitano i precompiled headers in tutti i progetti VC++ (ma è comunque usarli)Più semplice se si disabilitano i precompiled headers in tutti i progetti VC++ (ma è comunque usarli) La novità consiste nei.netmoduleLa novità consiste nei.netmodule –Il.netmodule è identico ad un assembly ma senza metadati –per esempio non ha versione Il netmodule viene ri-compilato al link timeIl netmodule viene ri-compilato al link time Solo il linker di C++ ha questa capacità di ricompilazioneSolo il linker di C++ ha questa capacità di ricompilazione a.cpp c.cs C++Compiler D:\>cl /c /clr a.cpp D:\>csc /t:module c.cs EXE C++ Code C# Code a.obj c.netmoduleC#Compiler C++Linker

22 Un assembly, mixed language Esempio di una Winform C# che usa una business logic in C++/CLIEsempio di una Winform C# che usa una business logic in C++/CLI –Progetto 1: CppLogicClassLibrary Per semplicità precompiled headers disabilitatiPer semplicità precompiled headers disabilitati Si compila con VS.netSi compila con VS.net EXEEXE CppLogicClassLibrary CsFormClassLibrary CppStartWinform

23 Un assembly, mixed language Progetto 2: CsFormClassLibraryProgetto 2: CsFormClassLibrary –Eliminato Program.cs, l'entry point sarà in C++/CLI –Si referenzia CppLogicClassLibrary e si usano le classi –Si compila in VS.NET solo per il controllo sintattico –Necessario compilare a mano (ma si può lanciare make.bat come post-build action) csc /t:module /addmodule:..\CppLogicClassLibrary\debug\CppLogicClassLibrary.obj /resource:obj\Debug\CsFormClassLibrary.Form1.resources *.cs csc /t:module /addmodule:..\CppLogicClassLibrary\debug\CppLogicClassLibrary.obj /resource:obj\Debug\CsFormClassLibrary.Form1.resources *.cs vogliamo un.netmodule dipendenza dal progetto C++/CLI dipendenza dal progetto C++/CLI aggiungo le risorse (form) compilo tutti i sorgenti sorgenti Compilatore C#

24 Un assembly, mixed language Progetto 3: CppStartWinformProgetto 3: CppStartWinform –Progetto C++/CLI Winform a cui si toglie la form –Cambiare le opzioni da /clr:safe a /clr –Aggiungere nel Linker – Input – Additional il.netmodule di C# e l'obj di C++ –Aggiungere alla command line del linker l'opzione /LTCG –Funge solo da entry point per l'applicazione managed –Si può fare la build da VS.NET Risultato: 1 Assembly EXE con dentro tre immagini miste native/managedRisultato: 1 Assembly EXE con dentro tre immagini miste native/managed –Ovviamente la dipendenza dal framework rimane

25 Qual'è il futuro di ISO C++? Ci sono problemi da risolvere per il cambio nell'evoluzione della crescita hardwareCi sono problemi da risolvere per il cambio nell'evoluzione della crescita hardware –niente più grossi aumenti di velocità nelle CPU –aumento del numero di 'core' nelle CPU L'accesso diretto alla memoria impedisce una gestione efficiente nel determinare i problemi di concorrenzaL'accesso diretto alla memoria impedisce una gestione efficiente nel determinare i problemi di concorrenza Work in progress su:Work in progress su: –gestione automatica della concorrenza ("concurs") –gestione asincrona ("Futures") –type inference –lambda functions –Linq

26 Domande?


Scaricare ppt "Mixed code: C++/CLI Raffaele Rialdi Visual Developer Security MVP MVP Profile:"

Presentazioni simili


Annunci Google