by sandro
5. January 2009 22:43
Intro
Molti di noi si saranno trovati spesso a decidere, al momento dell'analisi di un progetto, se sviluppare l'applicazione sul nostro dispositivo con codice unmanaged (nativo, solitamente sviluppato in C++) o tramite codice managed con .NET Compact Framework. Di solito la propensione per quest'ultima scelta (.NET) avviene per velocizzare lo sviluppo di interfacce utente (UI), l'integrazione in classi già preesistenti o l'utilizzo di controlli terze parti che aumentano vertiginosamente la produttività degli sviluppatori coinvolti nel progetto. Si propende invece per il codice unmanaged nel momento in cui vogliamo garantire migliori performance dell'applicazione o magari una certa portabilità su altre piattaforme. Una delle soluzioni che possono essere prese è quella di utilizzare il CF .NET per scrivere l'interfaccia utente, mentre si può lasciare la scrittura della logica di business (chiamiamola così) con codice unmanaged nativo. In questa serie di post, proverò ad analizzare una semplice soluzione che step by step guiderà sia nella scrittura del codice .NET che del codice nativo.
L'applicazione
L'applicazione consiste di una solution (CF_Native_Sample) con due progetti: il primo di tipo Device Mobile .NET chamato CF_Native_Sample, mentre il secondo contiene un progetto DLL C++ per Smart Device chiamato NativeLib. Tanto per far seguire passo passo la costruzione dell'applicazione, vediamo lo schema in figura:
Costruiremo una semplice interfaccia Windows Form con due textbox, un bottone ed una label. Al click del bottone il codice managed interagirà con quello nativo inserito nella DLL scritta in C++. Lo schema che vogliamo seguire, ricalca uno standard che ritroviamo in moltissime applicazioni. Innanzitutto la DLL unmanaged contiene una funzione che rimane in attesa di alcuni eventi che simula per esempio una socket, oppure un controllore PLC, o una seriale da cui arrivano dei segnali che alla fine vengono trasformati in una chiamata (call) che dovrà essere gestita dal codice .NET. Il codice gestito consiste in una form che al click del bottone scatena un meccanismo per cui in maniera asincrona ci si mette in ascolto delle chiamate provenienti dalla parte unmanaged. Apparentemente le cose sono abbastanza semplici e se vogliamo avere anche uno schema visuale dell'applicazione, possiamo osservare la seguente figura:
In questa immagine risulta chiaro che, se vogliamo ascoltare gli eventi in maniera asincrona, dobbiamo creare nella parte managed un thread apposito che ascolterà la parte unmanaged. Primo problema: sappiamo benissimo che la GUI appartenendo al thread della Main form, non potrà essere aggiornata dal listener thread, per cui dovranno essere implementati dei meccanismi di comunicazione tra i due thread. Secondo problema: abbiamo voluto pensare al fatto che dalla parte managed ci potevano essere più di un thread in ascolto e quindi più di un thread che aggiorna alcune variabili globali. Quali meccanismi possono essere utilizzati per sincronizzare questi thread?. Altro problema: il listener thread managed dovrà passare un delegate contenente il riferimento ad una callback. Quest'ultima sarà invocata dalla parte unmanaged per poter passare dei valori alla funzione managed: come è possibile effettuare un marshalling...indolore? Per esempio come faccio a passare delle stringhe dalla parte unmanaged alla parte managed?
Dal prossimo post cominceremo a costruire tutti i dettagli implementativi, descrivendo passo passo le scelte architetturali intraprese, partendo dalla form unmanaged che sarà la prima parte ad essere costruita. A prestissimo quindi