Title: Mixed code: C++/CLI
1Mixed code C/CLI
Raffaele RialdiVisual Developer Security
MVP malta_at_vevy.comMVP Profile
http//snipurl.com/f0cv
http//mvp.support.microsoft.com
2Agenda
- Perché usare C ... perché C/CLI
- Carrellata sul linguaggio
- solo gli elementi del linguaggio utili per
interop - gestione della memoria managed/unmanaged
- pinning e marshalling
- mixed types
- C future directions
3Perché usare C
- Rende 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 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
4Perché un nuovo linguaggio? Perché C/CLI?
- Le managed extensions erano complesse per aderire
alle regole dello standard ISO (doppio
underscore, etc.) - cl /clroldSyntax 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
C09) - C/CLI ha una piacevole sintassi per lavorare
sia con il mondo managed che unmanaged
- C Features
- Finalizzazione deterministica
- Template e generics
- Uso dei tipi nativi
- Multiple inheritance (unmanaged)
- STL, algoritmi generici
- Distinzione Puntatore/Puntato
- Copy construction, assignment
- CLR Features
- Garbage collector, finalizzatori
- Generics
- Reference e Value type
- Interfacce
- Verificabilità
- Security
- Proprietà, delegati, eventi
5Novità in C/CLIdi cui non parleremo
- trivial properties property String Name
- indexed properties
- managed copy constructors
- delegate event
- managed operator overloading
- boxing/unboxing
- safe_castltgt
- generics vs templates
- method overriding
- lock(...)
- jagged arrays
- STL.NET
- integrazione MFC / Winform
- integrazione Avalon
- compilazione parallela
- profile guided optimization
- OpenMP parallelism
- CLR Delay Loading
6Veloce carrellata su C/CLI
- Supporto distinto per tipi managed e unmanaged
Le specifiche si trovano qui http//msdn.microsof
t.com/visualc/homepageheadlines/ecma/default.aspx
7I nuovi operatori e
- 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 -gt e
- L'analogo di void è Object
- Nuovo allocatore di memoria managed gcnew
- String s1 gcnew String
- String s2 continua ad essere un espressione
valida - Introdotto nel linguaggio il "tracking reference"
- Analogo del reference di C classico, cioè un
alias all'oggetto - il simbolo è ""
8Distruzione deterministica
- C/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.SuppressFinalize
- 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 finalizzatore
- La sintassi è analoga al distruttore ?
!NomeClasse() ... - Nel finalizzatore si mette la distruzione delle
risorse - Nella Dispose si mette la chiamata al
finalizzatore
9Istruire il precompilatore
- Il 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 pragma
- pragma managed
- pragma unmanaged
pragma managed class Managed ... pragma
unmanaged class Native ... pragma
managed ...
10Memoria Interior Pointers
- Al contrario dell'handle, permette l'aritmetica
dei puntatori - Utile per la veloce manipolazione di array e
buffer - Trasparente è usabile anche per tipi unmanaged
(restituisce un puntatore classico)
interior_ptrlttypegt name value
Esempio 1 arrayltintgta 1,2,3,4,5 interior_pt
rltintgt ip a0 for(int i 0 ilta-gtLength
i) ConsoleWriteLine(ipi) // output 2,
3, 4, 5, 6
Esempio 2 String str1 "Hello, world" String
str2 str1 interior_ptrltStringgt ip
str1 ip "Ciao" ConsoleWriteLine(str1 "
- " str2) // output Ciao Hello, world
11Memoria Pinning Pointers
pin_ptrlttypegt name value
void F(int p) // Func unmanaged arrayltintgt
arr pin_ptrltintgt pi arr0F(pi) // ptr
unmanaged
Interior Pointerinterior_ptrltTgt
String str1 "Hello, world" // interior
pointer al buffer della stringa (non è una
copia) interior_ptrltconst wchar_tgt ip
PtrToStringChars(str1) // interior pointer
senza 'const' interior_ptrltwchar_tgt ip2
const_castltinterior_ptrltwchar_tgt gt(ip) //
pinning pointer ? Il GC non può muovere il
buffer pin_ptrltwchar_tgt pp ip2 // modifico il
buffer for(int i0 iltstr1-gtLength
i) ppi // caratteri ascii
incrementati ConsoleWriteLine(str1) // out?
Ifmmp-!xpsme
Pinning Pointerpin_ptrltTgt
Unmanaged PointerT
12Sguardo molto semplicistico in memoria
13Marshalling di stringhe
14È tutto così semplice?... quasi
- 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
memoriamanaged e unmanaged - L'interoperabilità è possibile in due modi
- P/Invoke esplicito (come in C)
- IJW (It Just Works) eseguendo il marshalling dei
parametri - E allora dov'è il problema?
15Mixed types are not supported
public ref class RefClass public POINT pt //
unmanaged struct
public class Native public SystemString
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'
16Tipi misti tipi managed dentro tipi unmanaged
- GCHandle
- gcrootltgt
- necessita includeltvcclr.hgt
- non chiama automaticamente Dispose!
- msclrauto_gcrootltgt
- necessita include ltmsclr\auto_gcroot.hgt
- chiama automaticamente la IDisposableDispose se
esiste
include ltvcclr.hgt using namespace
System public class Native1 gcrootltString
gt str
include ltmsclr\auto_gcroot.hgt using namespace
msclr using namespace System public class
Native2 auto_gcrootltString gt str
17Tipi misti tipi unmanaged dentro tipi managed
- Brutta notizia fin'ora nessun supporto ufficiale
ma la soluzione è molto semplice .... - In 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 puntatore - Brandon Bray (uno degli ideatori della nuova
sintassi) ne ha pubblicata una chiamata
"Embedded" sul suo blog
include ltwindows.hgt include "Embedded.h" public
ref class RefClass EmbeddedltPOINTgt np
18Cosa sono le calling convention?
- Una sorta di contratto alla compilazione che
prevede - come passare gli argomenti delle funzionied il
valore di ritorno - quali registri della CPU devono essere salvati
- Le quattro convenzioni più usate oggi sono
- __cdecl usato dalle librerie C e numerose API
- __stdcall conosciuta anche come "pascal", usata
dalle Win32 API - __fastcall usa i registri per passare gli
argomenti - __thiscall default per le chiamate a funzioni
membro in C
19Cos'è il "double thunking"?
- 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?
- 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?
- 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
20Cos'è il "double thunking"?
- 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 supplementaremanaged ?
unmanaged ? managedQuesto doppio passaggio si
chiama "double thunking" - 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 laconvenzione __clrcall - forzando __clrcall si evita il double thunking
virtual return-type __clrcall function-name(argume
nts)
21Un assembly, mixed language
- Task complesso, nessun supporto di VS2005
- Più semplice se si disabilitano i precompiled
headers in tutti i progetti VC (ma è comunque
usarli) - La 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 time
- Solo il linker di C ha questa capacità di
ricompilazione
a.cpp
C Compiler
a.obj
EXE
C Code
C Linker
D\gtcl /c /clr a.cpp
C Code
D\gtcsc /tmodule c.cs
c.cs
c.netmodule
C Compiler
22Un assembly, mixed language
- Esempio di una Winform C che usa una business
logic in C/CLI - Progetto 1 CppLogicClassLibrary
- Per semplicità precompiled headers disabilitati
- Si compila con VS.net
EXE
CppLogicClassLibrary
CsFormClassLibrary
CppStartWinform
23Un assembly, mixed language
- Progetto 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)
vogliamo un .netmodule
dipendenza dal progetto C/CLI
Compilatore C
csc /tmodule /addmodule..\CppLogicClassLibrary
\debug\CppLogicClassLibrary.obj
/resourceobj\Debug\CsFormClassLibrary.Form1.resou
rces .cs
aggiungole risorse (form)
compilo tutti i sorgenti
24Un assembly, mixed language
- Progetto 3 CppStartWinform
- Progetto C/CLI Winform a cui si toglie la form
- Cambiare le opzioni da /clrsafe 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/managed - Ovviamente la dipendenza dal framework rimane
25Qual'è il futuro di ISO C?
- Ci 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
concorrenza - Work in progress su
- gestione automatica della concorrenza ("concurs")
- gestione asincrona ("Futures")
- type inference
- lambda functions
- Linq
26Domande?