Versione .NET della libreria INOUT32
a cura di Antonio Giuliana (requisiti: conoscenza generica di Windows NT/2000, .NET architecture,
programmazione ad oggetti, Device Development Kit)Introduzione
La necessità di interfacciare speciali apparecchiature al nostro PC tramite porta parallela o seriale e di realizzare programmi atti a pilotare tali strumentazioni, è sicuramente sentita da parte dei programmatori VB (e non solo), almeno a giudicare dal numero di download del progetto INOUT32 che avevo realizzato nel lontano 1999. Ancora oggi questa esigenza è avvertita ed il mutato assetto relativo a sistemi operativi e strumenti di sviluppo mi hanno spinto a ringiovanire questa libreria.Il progetto
Per la realizzazione della nuova versione della libreria - come per qualsiasi prodotto software - è stata necessaria una fase di analisi per identificare la migliore architettura. In particolare, nella seguente tabella ho riportato le considerazioni fatte e le soluzioni adottate
ALa libreria deve essere liberamente utilizzabile (con un'unica restrizione per l'uso commerciale) 1Il codice fornito può essere liberamente utilizzato per scopi di studio e test. Per scopi commerciali una libera donazione al sito VB-T&T è gradita e, in ogni caso, è necessario darne notizia all'autore. Verrà fornito il codice sorgente di ogni componente del progetto. BI sistemi operativi più diffusi saranno a tecnologia NT (2000/XP/.NET) 2I sistemi a tecnologia NT implementano un sistema di sicurezza per l'accesso alle porte di I/O È necessario utilizzare un device driver CIl device driver precedente (MapMemPlus) potrà non essere più disponibile 3Il device driver è di terze parti e soggetto a restrizioni per la distribuzione Verrà scritto un semplice device driver per 2000/XP e ne verranno distribuiti i sorgenti DAumenterà l'uso della versione .NET degli strumenti di sviluppo 4La libreria verrà scritta sfruttando l'architettura .NET La nuova libreria INOUT32 sarà scritta in VC++.NET e ne verranno distribuiti i sorgenti EL'architettura .NET non è attualmente molto usata 5È necessario garantire la compatibilità con VB6 La classe sarà compatibile con i client COM (VB6). Sarà scritto un programma di test in VB6 che utilizzi la libreria 6È necessario scrivere programmi d'esempio .NET per l'uso della libreria
Saranno scritti programmi di test in VB.NET e in C#.NET che utilizzino la libreria 7Il codice del driver, della libreria e dei programmi d'esempio deve essere documentato I sorgenti devono essere ampiamente commentati Potrà sembrare eccessivo scrivere un device driver ma, perché la nuova versione della libreria possa essere liberamente utilizzata e distribuita (punto A.1 del progetto), è necessario rendersi indipendenti dal device driver usato con la precedente versione della INOUT32. Vedremo, del resto, che la creazione del codice di questo device driver si rivelerà essere un'operazione più semplice del previsto, se seguiremo le semplici regole che indicherò nel seguito dell'articolo. Le funzionalità di questo device driver, dovranno essere limitate alla possibilità di eseguire le operazioni di input e output verso indirizzi di I/O del sistema superando le limitazioni imposte dai sistemi operativi di classe NT ai programmi utente che lavorano con l'I/O. Queste basteranno per implementare nella libreria i metodi più utili.
Bisogna chiarire il concetto che questo progetto non è il porting della INOUT32 su .NET ma una riscrittura della libreria con la nuova versione del linguaggio in modo che essa supporti i metodi fondamentali per un uso proficuo della stessa. La libreria sarà scritta in VC++.NET, sia perché questo è il linguaggio più adatto per lo scopo, sia perché è didatticamente molto utile capire come programmi scritti in altri linguaggi, possano facilmente interagire con essa. A tal fine, nel progetto saranno inclusi programmi di test per l'uso della nuova INOUT32 scritti in due linguaggi di Visual Studio .NET, ovvero VB e C#.
Tutto il codice è stato sviluppato su un sistema dotato dei seguenti programmi di sistema e di sviluppo
Sistema operativo Windows 2000 Pro - Build 2195 - SP2 - SRP1 .NET Framework - V. 1.0.3705 Visual Studio .NET Enterprise Architect ITA [Development Environment 2002 - V. 7.0.9500] Windows 2000 Device Development Kit (DDK) Visual C++ 6.0 Enterprise EditionL'ultimo strumento è necessario al DDK per compilare il device driver.
L'interazione dei componenti del progetto, viene evidenziato nella seguente figura
Mentre i client interagiranno con la DLL tramite i metodi esposti dalla classe INOUT32, questa lavorerà con il driver attraverso appositi comandi IOCTL. Il client VB6 opererà con la DLL tramite il CCW (COM Callable Wrapper).
Il device driver
È noto che per l'utilizzo su sistemi operativi di classe NT è necessario utilizzare un device driver in modo da eseguire le istruzioni macchina IN e OUT (soggette a restrizioni in user mode) in kernel mode (punti B.2 e C.3 del progetto). Sul funzionamento del device driver non scenderò molto in dettaglio - non è questa la sede per approfondire questo tipo di software - ma cercherò di essere esauriente. Per ulteriori informazioni, consiglio di leggere con attenzione la documentazione associata al DDK di Windows 2000.Il progetto del device driver (che chiameremo INOUT32D) è composto da 5 file sorgenti che sono posti all'interno della directory C:\WINNT\DDK\SRC\INOUT32D. La tabella seguente mostra quale sarà la funzione di tali file
INOUT32D.C Il sorgente principale del driver INOUT32D.H Il file include delle costanti INOUT32D.RC Le risorse associate al driver MAKEFILE Makefile (utilizzato dal DDK) SOURCES La descrizione dei sorgenti per il build Ignoriamo gli ultimi due (il cui contenuto è relativamente chiaro) e soffermiamoci sui primi tre.
In particolare, il file con estensione .RC è quello delle risorse che è utilizzato per includere informazioni sulla versione e descrizione del prodotto. Esso sarà incluso nel driver tramite il file SOURCES. Il file include (.H) contiene le costanti utilizzate dal codice e, in particolare, la stringa con il nome che il driver avrà per il sistema operativo (InOut32D, appunto) e la definizione dei comandi IOCTL per la lettura e la scrittura di porte di I/O. Il file sorgente (.C) contiene, ovviamente, il codice relativo al driver e verrà descritto in seguito.Dopo aver inserito questi file nella directory indicata, la creazione del driver avviene tramite una finestra comandi aperta tramite l'opzione apposita del Development Kit di Windows 2000, chiamata Free Build Environment. Non è possibile aprire ed usare una qualsiasi finestra (tramite il comando Cmd) ma bisogna usare quella aperta proprio tramite la voce di menu visibile in figura
perché solo così vengono impostate le variabili d'ambiente necessarie per la costruzione del driver.
Aperta la finestra, è sufficiente cambiare la directory corrente e arrivare all'interno della INOUT32D e lanciare il comando BUILD del DDK. Questo provvederà (servendosi del Visual C++ 6) a compilare i file del driver per ottenere il file .SYS. Al termine dell'operazione di build, verranno create alcune sottodirectory e, in particolare, la i386 al cui interno troveremo il file contenente il driver vero e proprio (INOUT32D.SYS) che dovrà essere, in seguito, installato.L'architettura del device driver
Nel file INOUT32D.C viene implementato il codice del driver che deve includere necessariamente la funzione DriverEntry la cui funzione è
- creare il device driver
- indicare al gestore dei driver gli indirizzi delle tre principali funzioni di controllo
In particolare - per l'ultimo punto - le funzioni inserite sono la InOut32DCreateDispatch, la InOut32DDeviceControl e la InOut32DUnload.
La prima viene richiamata nel momento in cui il gestore dei driver riceve una richiesta di apertura del driver da parte dei client che vogliono comunicare. In questo caso il driver non effettua alcuna operazione restituendo comunque un codice di successo per l'operazione richiesta, ma questa funzione è obbligatoria e deve essere inclusa.
L'ultima è utilizzata quando il driver viene scaricato eseguendo le normali operazioni di cleanup.
La funzione principale - e la più interessante - è la InOut32DDeviceControl che viene richiamata ogniqualvolta viene inviato un comando IOCTL al driver da parte di un client tramite la DeviceIoControl (dopo aver aperto un handle tramite la CreateFile).
A questa funzione viene passato il comando inviato dal client - che può essere uno tra IOCTL_READ_PORT_CHAR e IOCTL_WRITE_PORT_CHAR - e un buffer per il passaggio, nei due sensi, di informazioni tra il client e il driver (attenzione al fatto che, in questo contesto, il client è rappresentato dal codice della DLL INOUT32). In particolare vengono passati l'indirizzo della porta di I/O e il dato associato (da scrivere o letto) che sono utilizzati dalle macro READ_PORT_CHAR e WRITE_PORT_CHAR che effettuano il vero e proprio I/O in kernel mode. Qualsiasi altro comando viene ignorato e viene segnalato un errore.L'installazione del device driver
Prima di potere usare il device driver, questo deve essere installato.
Per fare ciò è sufficiente copiare il file INOUT32D.SYS nella cartella C:\WINNT\SYSTEM32\DRIVERS ed includere nel registro le informazioni necessarie nella chiave HKLM\SYSTEM\CurrentControlSet\Services\InOut32. A tale scopo ho preparato il file INOUT32D.REG che è possibile unire al registro.
L'attivazione del driver avviene dopo il riavvio del sistema.
Il driver può essere rilevato da Gestione Computer -> Gestione Periferiche. Dopo aver attivato la visualizzazione dei Driver non Plug and Play (tramite Visualizza -> Mostra periferiche nascoste), nell'elenco viene mostrato anche il driver appena installato, come in figura
Dalle proprietà del driver si può notare che esso è Avviato e che il tipo di avvio è settato su Automatico.
È possibile che venga evidenziato un errore 24; questo errore può essere ignorato (in quanto il driver non è Plug and Play) e, in genere, scompare dopo avere scelto l'opzione Rileva modifiche hardware.
In ogni caso, il driver è adesso attivo e funzionante.La nuova libreria INOUT32
La nuova libreria è stata scritta in VC++.NET perché è il linguaggio più adatto (nella piattaforma .NET) a questo tipo di progetti (punto D.4 del progetto).
La libreria, lo ricordo, deve dialogare con il driver e deve usare funzioni di sistema il cui uso con VB.NET sarebbe una forzatura.
È infatti vero che possono essere usate le API con VB.NET, ma questo modo di operare è sconsigliato; in più, sarà utile vedere come il codice scritto in più linguaggi possa interagire.Il tipo di progetto usato è quello della Libreria di classi C++ gestita che permette di costruire una classe riutilizzabile di tipo managed (public __gc, controllata dal Common Language Runtime e soggetta alla Garbage Collection).
La DLL ottenuta quindi, è un assembly con tutti i vantaggi connessi a tale tipo di entità.Sebbene il progetto sia costituito da diversi file, ci concentreremo sul sorgente (InOut32.cpp) e sull'include relativo (InOut32.h). In questi file, infatti, non solo è presente la dichiarazione della classe INOUT32 ma anche l'implementazione dei metodi (pubblici e privati) di tale entità.
I metodi pubblici messi a disposizione dei client, sono i seguenti
void Out ( SHORT Port, BYTE Data ) Effettua un'operazione di Out di un byte (Data) su una porta (Port) di I/O. Non restituisce valori. BYTE Inp ( SHORT Port ) Effettua un'operazione di Inp di un byte da una porta (Port) di I/O. Il valore restituito è il byte letto da tale porta. void BitSet ( SHORT Port, BYTE Bit ) Pone il bit (Bit) della porta (Port) a 1. Non restituisce valori. (Il valore degli altri bit è letto dalla stessa porta). void BitReset ( SHORT Port, BYTE Bit ) Pone il bit (Bit) della porta (Port) a 0. Non restituisce valori. (Il valore degli altri bit è letto dalla stessa porta).
BYTE InpBit ( SHORT Port, BYTE Bit ) Legge il valore del bit (Bit) dalla porta (Port). Restituisce il valore 0 o 1. BYTE InpBitWait ( SHORT Port, BYTE Bit, LONG msTimeout, PPolar pol ) Legge il valore del bit (Bit) dalla porta (Port), attendendo per il massimo tempo indicato (msTimeout), la transizione da Low ad High o viceversa. Restituisce il valore 0, 1 o 255 per avvenuto timeout. void Wait ( LONG ms ) Sospende l'esecuzione per il tempo (ms) indicato in ms. Non restituisce valori. void Cleanup ( void ) Effettua esplicitamente il cleanup dell'istanza (chiudendo l'handle di comunicazione verso il driver aperto dal costruttore della classe). Poco c'è da dire su tali metodi, che per lo più si basano sui primi due. I metodi Out e Inp effettuano l'I/O comunicando tramite la DeviceIoControl con il device driver. Ma per poter lavorare, la DeviceIoControl ha la necessità di ottenere un handle tramite una chiamata alla CreateDevice (alla quale si deve passare il nome del driver InOut32D). Questo handle, mantenuto a livello privato dalla classe, viene ottenuto dalla OpenINOUT32D (anch'essa privata) chiamata dal costruttore. Lo stesso handle può essere rilasciato, tramite la corrispondente CloseINOUT32D, in due modi diversi: tramite chiamata esplicita del metodo Cleanup, o dal distruttore della classe.
Questo in ragione del fatto che la classe INOUT32 è controllata dal Common Language Runtime di .NET il quale, a causa della complessa gestione del modulo di garbage collection, non garantisce la chiamata del distruttore una volta che l'oggetto relativo esce dallo scope.
L'utilizzo della classe all'interno di un programma client, prevede quindi i seguenti semplici passi:
- creazione di un'istanza della classe INOUT32
- uso dei metodi pubblici (Out, Inp e le altre)
- cleanup delle risorse
Solo per quest'ultima fase è possibile scegliere se effettuarla esplicitamente (metodo Cleanup) o tramite il distruttore. Quest'ultimo sarà chiamato quando l'oggetto uscirà dalla visibilità e il garbage collector lo riterrà necessario. Non serve settare esplicitamente a nothing (o a null) la variabile associata all'oggetto, a meno di non chiamare successivamente ed esplicitamente il garbage collector, come nelle seguenti righe (VB.NET)
Dim IO As New INOUT32_LIB.INOUT32( ) ... IO = Nothing GC.Collect( )È consigliabile però, per evidenti motivi di performance, chiamare il metodo Cleanup ed ignorare il fatto che il distruttore sarà chiamato in seguito, in questo modo
Dim IO As New INOUT32_LIB.INOUT32( ) ... IO.Cleanup( )Nel file delle risorse (INOUT32.RC) saranno poste soltanto le informazioni di versione e copyright.
Il file AssemblyInfo.cpp infine, assumerà importanza relativamente alla visibilità della libreria da parte dei programmi che la utilizzeranno, ma ciò sarà discusso in seguito.Installazione e visibilità della DLL
Gli assembly (come nel caso della nostra DLL) non devono essere registrati e possono essere distribuiti semplicemente copiandoli nella cartella del PC in cui devono essere utilizzati. Essi, normalmente, sono privati ovvero possono essere utilizzati dall'applicazione con cui vengono distribuiti a patto che una loro copia sia presente nella directory da cui parte l'applicazione (o in una sottostante). Questo vale anche per i client VB6 che utilizzano l'assembly (la nuova DLL).
Ma per componenti come la nostra DLL, è più ragionevole che l'assembly possa essere condiviso tra tutte le applicazioni che vorranno utilizzarlo (siano esse altri assembly o client COM, magari scritti in VB6 o VC6); per tale motivo esiste un'altra categoria di assembly - shared - che possono essere utilizzati da tutte le applicazioni liberamente, a prescindere dalla loro collocazione fisica. Per fare questo, l'assembly può essere posto nella cartella \WINNT\SYSTEM32 (ma non necessariamente) e trascinata in uno speciale contenitore detto GAC (Global Assembly Cache) che è visibile nella (speciale) cartella \WINNT\Assembly (mostrata accanto).
Queste operazioni consentono a tutte le applicazioni di referenziare l'assembly liberamente (anche se non comparirà nella dialog dei riferimenti, la relazione potrà essere creata raggiungendo la DLL tramite il pulsante Sfoglia).
Ma non è tutto. Mentre una DLL privata può essere creata ed utilizzata senza problemi dall'applicazione per cui è nata, quelle shared, per essere univocamente identificate, devono essere strongly named. Il meccanismo scelto da Microsoft prevede l'uso dello standard tecnico della crittografia a chiave pubblica/privata (nel quale non ci addentreremo) che, insieme al nome dell'assembly, alla versione e alla lingua, lo identificano univocamente. Questo garantisce anche che possano esistere componenti nella GAC che differiscono per la versione o, a parità di nome, versione e lingua, per la chiave pubblica/privata in quanto proveniente da altro fornitore. Il tentativo di inserire nella GAC un assembly che non ha le caratteristiche sopraindicate, non va a buon fine evidenziando con un messaggio la situazione d'errore.
Per creare un assembly strongly named, bisogna aprire il file AssemblyInfo.cpp (di cui s'è detto in precedenza) e fornire le quattro informazioni. Nella nostra DLL, ad esempio, è stato indicato
[assembly:AssemblyVersionAttribute("2.0.1.0")];per definire la versione in maniera statica, ed è stata inserita la linea
[assembly:AssemblyKeyFileAttribute("INOUT32.snk")];per fornire l'indicazione su dove reperire la coppia di chiavi pubblica/privata (ovvero nel file indicato con estensione snk posto nella cartella del progetto). Il file delle chiavi può essere semplicemente creato tramite l'utility SN, con il comando
SN -k INOUT32.SNKNaturalmente la DLL che ho creato è stata da me firmata con una coppia di chiavi da me creata (che distribuisco), ma, avendo a disposizione i sorgenti, ognuno può firmare la DLL con una propria coppia di chiavi.
La compatibilità con VB6
Naturalmente è auspicabile che questa nuova versione della libreria possa essere utilizzata con il VB6 e per questo motivo (punto E.5 del progetto) sono state adottate alcune misure per garantire la compatibilità. È infatti prevista l'interoperabilità tra COM e .NET ma bisogna tenere presente che la DLL è comunque un assembly e che, quindi, è sempre necessario installare il Framework .NET per farla funzionare. Si può d'altra parte tener conto del fatto che tra poco tempo sarà indispensabile installare il framework (anzi, in Windows .NET Server sarà integrato...) per sfruttare la nuova architettura e che questo non è molto pesante in termini di risorse.Per permettere che l'assembly possa interagire con client COM, la CLR di .NET provvede a creare a runtime una classe wrapper che, da un lato, espone i metodi a COM e dall'altro esegue le chiamate all'assembly. Ma per default l'interfaccia non viene creata di tipo duale, come serve per lavorare correttamente con il VB6. È questo il compito dell'attributo
[ClassInterface(ClassInterfaceType::AutoDual)]associato alla classe INOUT32.
Ma questo non basta, perché per poter utilizzare un componente COM è necessario che sia registrato e che esista una Type Library per ottenere il riferimento all'interno del VB6.
Queste operazioni sono realizzate in un solo colpo con l'utility REGASM, utilizzata nel seguente modoREGASM INOUT32.DLL /TLBIl comando provvede ad inserire nel registry le informazioni per i client COM e a creare il file INOUT32.TLB (la type library) da usare per referenziare la classe in VB6.
I client di test per la INOUT32
Per mostrare come utilizzare la DLL (supponendola presente in \WINNT\SYSTEM32, con la relativa Type Library, ed installata nella GAC), ho scritto e distribuito anche dei sorgenti di test scritti nei principali linguaggi di Visual Studio .NET e in VB6 (punti E.5 ed E.6 del progetto).
La scelta di scrivere i programmi di test utilizzando due linguaggi .NET, è stata fatta non solo per mostrare come si possa facilmente interagire con la nuova DLL INOUT32, ma anche per sottolineare che l'utilizzo del Framework .NET tende a minimizzare le differenze d'uso dei compilatori.
La scelta di un linguaggio piuttosto di un altro, non si basa su questioni di efficienza, velocità o usabilità ma semplicemente su preferenze soggettive legate all'esperienza propria di ogni programmatore. Questa considerazione porta, addirittura, a valutare l'opportunità che un programmatore VB6 possa pensare di passare ad utilizzare C#.NET piuttosto che VB.NET. Le caratteristiche della sintassi di questo nuovo linguaggio infatti, includono le migliori proprietà di VB.NET e di VC++.NET. Ma questa è un'altra storia ...Ogni client di test è denominato ParTest in quanto, per default, permette di effettuare prove con l'indirizzo 888 assegnato ad una porta parallela. Nonostante ciò, i programmi di test sono generici in quanto permettono di modificare l'indirizzo della porta usata.
Attenzione! L'uso di altre porte, se non si sa esattamente a cosa servono, è potenzialmente dannoso e quindi suggerisco di effettuare le prove con gli indirizzi delle porte parallele (632, 888 e 956).
A lato è mostrata l'interfaccia dell'applicazione di test (versione VB.NET, sebbene questa sia comune a tutte le versioni).
Per effettuare una Out è necessario inserire l'indirizzo della porta ed il dato mentre per la Inp è sufficiente solamente il primo valore.
Non viene effettuata alcuna validazione dei dati. Per questo motivo è possibile ottenere degli errori di conversione, se i dati inseriti non sono coerenti (lascio al lettore il compito di inserire tali controlli).
Le operazioni di Set e Reset si riferiscono alla porta indicata e al bit (da 0 a 7) inserito nell'apposito textbox. Il risultato dell'operazione viene subito evidenziato nella label posta sopra il pulsante Inp.
La InpBit restituisce il valore del bit indicato (0 o 1), mentre la InpBitWait effettua un'operazione un po' più complessa, legata all'indicazione mostrata dal pulsante "( H to L )".Nelle figure seguenti è mostrato come opera la InpBitWait secondo il valore dell'ultimo parametro.
Infatti, se questo è H to L, la funzione attende che il bit indicato transiti dal valore 1 a 0 entro il tempo indicato (in mS) come Timeout
Se ciò avviene, viene restituito il valore 0, altrimenti il valore 255 indica la condizione di timeout.
Nell'esempio di test, il timeout è settato ad 1 S.
Se l'ultimo parametro è L to H, la InpBitWait si comporta in modo opposto, come mostrato in figura che segue, ritornando 1 se la transizione avviene entro il tempo impostato, 255 altrimenti. La distribuzione del pacchetto
Dato che ho deciso, come in altre occasioni, di distribuire i file binari e i sorgenti di tutti i componenti, ritengo necessario impiegare qualche riga per illustrare il contenuto del file .ZIP disponibile per il download (circa 92 K).I sorgenti del driver (inout32d.c, inout32d.h, inout32d.rc, Makefile, Source) sono inseriti in NTDDK\src\INOUT32D per un'eventuale ricompilazione. Il driver vero e proprio (inout32d.sys, di circa 3 K) e il file registro per l'installazione (inout32d.reg) sono inclusi in NTDDK\src\INOUT32D\i386.
I sorgenti della DLL (INOUT32.cpp e INOUT32.h sono i principali) sono inseriti in DotNETApps\INOUT32. Ho inserito anche il file delle chiavi usato (INOUT32.snk) anche se ognuno di voi potrà generarne uno per ricompilare la DLL una volta aggiunte altre funzionalità.
La DLL (strongly named) è inclusa in DotNETApps\INOUT32\Release ed è di circa 72 K.
Tutti i sorgenti di test sono inseriti all'interno della cartella DotNETApps\INOUT32\Test. In particolare, i sorgenti delle diverse versioni sono all'interno di DotNETApps\INOUT32\Test\VB6, DotNETApps\INOUT32\Test\C#.NET e DotNETApps\INOUT32\Test\VB.NET e gli eseguibili in cartelle sottostanti. Insieme ai sorgenti della versione VB6 è incluso il file inout32.tlb (la type library ottenuta con il comando REGASM a partire dalla inout32.dll) per poterli ricompilare se necessario.
Una volta estratti i file, le seguenti operazioni sono sufficienti per potere utilizzare i programmi di test
- copiare il driver inout32d.sys in SYSTEM32\DRIVERS
- unire il file inout32d.reg al registro
- riavviare il computer
- copiare la DLL inout32.dll in SYSTEM32
- tramite la finestra comandi di .NET, usare il comando REGASM con la dll appena copiata (la registrazione è necessaria solo se si vuole utilizzare il client VB6)
- trascinare la dll appena copiata nella GAC (cartella ASSEMBLY)
Naturalmente, nel caso di Windows XP bisogna usare la directory WINDOWS al posto di WINNT.
Conclusioni
Questo progetto, oltre a permettere l'uso della INOUT32 con .NET svincolandosi anche dal driver di terze parti presente nella vecchia versione, consente di fare esperienza con il mondo .NET che è sicuramente, per la maggioranza, ancora da scoprire.Basta pensare alla moltitudine di classi che affollano il framework (tutte molto potenti e che mettono a disposizione un gran numero di metodi), al supporto del multithreading e, soprattutto, alla programmazione orientata agli oggetti.
Tutte queste caratteristiche possono - indubbiamente - spaventare coloro che hanno intenzione (o necessità) di sviluppare con i nuovi strumenti dato che il passaggio da VB6 a VB7 (o VB.NET) è di una portata veramente maggiore rispetto a tutti i precedenti.
Come ho già accennato, dato lo strato comune del framework, scegliere di programmare con .NET tramite VB o C# sarà irrilevante e dipenderà soltanto da preferenze personali di sintassi. Ma tramite tutti i seminari, techlab, workshop e demo su .NET a cui ho partecipato, ho capito che il linguaggio C# offre tutte le caratteristiche di uno strumento RAD come VB e la potenza indiscussa di C++.
I programmatori VB sono avvisati ...FeedBack
Per ogni chiarimento, critica, suggerimento, potete fare riferimento all'autore, Antonio Giuliana, anche attraverso la Mailing List.