Le API di Windows: differenze tra VB 6 e VB .Net
a cura di Alessandro Del Sole (requisiti: conoscenza intermedia di VB6)

Premessa
Lo scopo di questo articolo non è quello di essere una "guida". Più che altro il mio proposito è quello di illustrarvi ulteriori differenze tra VB 6 e VB .Net per quanto riguarda un argomento che è sempre stato croce e delizia del programmatore in genere.
Il mio intento è quello di illustrarvi una delle tante sfaccettature di un nuovo modo di pensare la programmazione, che va oltre un'evoluzione sintattica del linguaggio.
Questo articolo è diretto a chi sa cosa sono le API e le ha utilizzate in versioni di Visual Basic precedenti la 7.0. Vedremo insieme quali sono le differenze pratiche di utilizzo delle API (funzioni, costanti, tipi), e quali sono i concetti che stanno alla base del loro utilizzo in VB .Net. Cercherò di essere il più semplice possibile sebbene ci siano dei concetti nuovi e, forse, sconosciuti ai più.

Ritengo necessario ribadire un concetto che avrete già avuto modo diverse volte di sentir esprimere: VB .Net non va considerato come una semplice evoluzione del vecchio VB 6. Sarebbe bene mettersi a studiarlo come se fosse un linguaggio totalmente nuovo, partendo dalla base, in quanto è il modo migliore per capirne la struttura. Anche perché VB .Net (come gli altri linguaggi) è stato progettato per la piattaforma .Net, che è la vera rivoluzione di casa Microsoft(r), e che (ma per ora sono solo voci di corridoio...) sarà parte integrante delle prossime versioni di Windows. E, riprendendo una frase del Francesco Balena, imparare oggi a conoscere la piattaforma .Net quando è ancora neonata significherà fare qualche sacrificio di studio oggi per essere decisamente avanti rispetto ad altri tra un po' di tempo.

L'utilizzo delle API in VB 6
Chi ha utilizzato le Application Programming Interface in applicazioni VB 5 o 6 sa che spesso si devono digitare numerosissime righe di codice per dichiarare le funzioni, le costanti ed i tipi desiderati. Personalmente ho realizzato programmi che avevano dei moduli pieni zeppi solo di dichiarazioni delle funzioni, delle costanti e dei tipi della piattaforma Win32. Magari per realizzare una piccola Sub di poche righe, che interagisse col sistema operativo, erano necessarie decine di linee di codice per le dichiarazioni. Si pensi ad esempio a delle routine per realizzare effetti grafici sulle picturebox e per salvare le immagini realizzate su file, soprattutto in formati diversi dalle bitmap, o ancora la realizzazione di classi per la gestione del registro di configurazione di Windows.
Sicuramente l'utilizzo delle API permette spesso di evitare l'utilizzo di componenti ActiveX o librerie dei tipi esterne, riducendo le dimensioni dell'applicazione, e consentendo (cosa più importante) operazioni che la sintassi del linguaggio VB non consentirebbe se non con decine di righe di codice. Si consideri ad esempio la seguente funzione API:

 Declare Function SHGetFolderPath Lib "shfolder.dll" Alias "SHGetFolderPathA"      _
     (ByVal hwndOwner As Long, ByVal nFolder As Long, _
     ByVal hToken As Long, ByVal dwReserved As Long, _
     ByVal lpszPath As String) As Long

La funzione SHGetFolderPath permette di leggere le cartelle speciali di Windows sul PC in uso. Essa, tuttavia, necessita della dichiarazione di circa 40 costanti, a meno che non si ricordino a memoria i valori corrispondenti a tutte le varie cartelle.
Uno degli obiettivi perseguiti dalla piattaforma .NET è proprio quello di semplificare la vita del programmatore, e la cosa bella è che la potenza non è affatto diminuita, anzi.

Cosa cambia in VB .Net
Sappiamo che VB 6 ha le sue librerie di run-time e che le API dichiarate nell'applicazione accedono direttamente alle librerie di sistema di Windows.
In Visual Basic .NET questo funzionamento si ha solo in parte. In effetti il linguaggio utilizza le librerie di run-time della piattaforma .NET Framework. Queste librerie di run-time sono comuni a tutti i linguaggi della famiglia Visual Studio .NET, ed a loro volta interagiscono col sistema operativo, accedendo, ove necessario, alle librerie di sistema, contenenti le API.

Il vantaggio del programmatore sta nell'avere tutto ciò di cui ha bisogno proprio nel run-time dello strumento di sviluppo prescelto, sia esso VB .Net o altro linguaggio. Questo comporta, ed è cosa non da poco, che i diversi linguaggi della famiglia .Net possano utilizzare le stesse librerie di classi. Ciò significa che, se un domani vorremo imparare, ad esempio, il C#, avremo bisogno solo di conoscere la sintassi del linguaggio, perché conosceremo già le classi e le librerie disponibili.
In un linguaggio orientato agli oggetti significa un bel risparmio di tempo nel capire come questi vengano gestiti dai diversi ambienti di sviluppo.

Diciamo poi che in .NET l'utente ha a disposizione un enorme numero di classi che coprono praticamente tutti gli aspetti della programmazione. Poiché per ogni problematica possono esserci più classi (ad es. la grafica), queste ultime vengono raggruppate in "famiglie". Una famiglia di classi in Vb .Net è chiamata Namespace.

In Vb .Net, probabilmente per rendere la "migrazione" da una vecchia versione meno indolore, è stata lasciata inalterata la possibilità di dichiarare le funzioni (e badate: le funzioni sì, ma i tipi no) alla vecchia maniera, per capirci come la funzione d'esempio sopra riportata.
Il mio consiglio è di abbandonare questo vecchio sistema. Questo perché è bene calarsi nell'ottica dei Namespaces e, cosa non da poco, perché alcuni tipi di dato presenti in VB 6 in .Net non sono supportati, come il tipo Any, o hanno un compito diverso, come Object. Vi accorgerete che numerose funzioni API utilizzano il tipo di dato Any e se tenterete di utilizzarlo riceverete un messaggio di errore che vi avviserà che il tipo non è più supportato e che bisogna essere precisi nel tipo di dato da utilizzare; il problema è che spesso non si sa quale possa essere il tipo di dato più idoneo. Con la pratica vi accorgerete che è più semplice a farsi che a dirsi, e scoprirete che operazioni che prima richiedevano un bel po' di lavoro ora saranno possibili semplicemente invocando un metodo di una classe.

Ovviamente quelle librerie contenenti funzioni riutilizzabili ma che non fanno parte delle librerie di sistema, come ad esempio la libreria EZTW32.DLL che permette di interfacciarsi a periferiche Twain, potranno essere utilizzate nel modo classico di Vb 6, stando attenti a sostituire i vecchi tipi di dato con dei tipi "precisi".
Il che significa semplicemente dichiarazioni 'specifiche' della stessa API con 'tipi' diversi, compatibili con i tipi .net.

Altro consiglio: evitate di utilizzare la conversione guidata di progetti VB. Questa funzione si limita a tradurre le parole chiave da una versione all'altra, evidenziando (ove presenti) i problemi di compatibilità riscontrati con dei commenti di warning, lasciando però allo sviluppatore l'arduo compito di risolverli.
Poiché nella maggior parte dei casi siamo tutti neofiti di Vb .Net la cosa migliore è quella di risolvere il problema a monte, scrivendo il codice già in "formato" VB .Net, evitando le traduzioni ed i relativi problemi.

Generalmente i Namespaces messi a disposizione da .NET e le classi in essi contenute, sono più che sufficienti per svolgere le operazioni che ci servono.
A conti fatti in .Net non avremo più bisogno di dichiarare funzioni API. Ci basterà utilizzare i Namespaces e le classi della piattaforma.

Un'applicazione .Net non ingloba tutte le classi della piattaforma. Sarebbe impensabile. E' necessario "importare" le classi che occorrono. E' un po' quello che succede nel linguaggio C, nel quale si includono le librerie contenenti le funzioni necessarie. Ed è, in fondo, quel che fa VB quando aggiungiamo riferimenti ad un progetto.

I Namespaces e le classi di .Net risiedono in delle librerie DLL. L'importazione dei Namespaces avviene con una nuova istruzione, Imports. Questa nuova istruzione, come facilmente potete intuire, rende disponibili nell'applicazione i Namespaces indicati, e le classi in essi contenute. Ad esempio, la seguente istruzione:

 Imports System.Drawing.Imaging

include nell'applicazione delle funzionalità per l'elaborazione delle immagini, consentendo, ad esempio, il supporto dei formati Tiff e Png, oppure metodi per la rotazione e l'inclinazione di immagini.

Esempi pratici
Facciamo qualche esempio:
in Visual Basic 6 potevamo utilizzare l'API ShellExecute per effettuare delle operazioni sui files. Essa viene dichiarata in questo modo:

 Public Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
    (ByVal hWnd As Long, ByVal lpOperation As String, ByVal lpFile As String, _
    ByVal lpParameters As String, ByVal lpDirectory as String, ByVal ShowCmd As Long) As Long

Con questa dichiarazione si può, ad esempio, lanciare il browser predefinito per aprire una pagina web:

  Dim lRet As Long
  lRet = ShellExecute(Me.hWnd, "open", "www.visual-basic.it", "", "", 1)

In VB .Net questo non sarà più necessario, in quanto la ShellExecute è inglobata in un NameSpace che si occupa della diagnostica di sistema, ovviamente con un nome diverso. Ecco il codice:

Imports System.Diagnostics

Public Module Modulo1

  Sub ApriSito()

    Dim Processo As Process = New Process
    Processo.Start("www.visual-basic.it")

  End Sub

End Module

Come vedete l'importazione del NameSpace viene inserita all'inizio del file di codice. All'interno di un modulo abbiamo creato una sub chiamata ApriSito(). In questa funzione viene creata un'istanza della classe Process, la quale mette a disposizione il metodo Start, che consente l'operazione di apertura del file specificato.

Potete facilmente intuire che, prima, per avere una sola funzione, dovevamo inserire una dichiarazione. Ora, in .Net, inserendo una sola dichiarazione avremo a disposizione un'intera libreria di classi.

Un altro esempio: l'API CopyFile. Questa funzione permette di copiare un file da una posizione in un'altra. In VB 6 il codice era il seguente:

 Declare Function CopyFile Lib "kernel32" Alias "CopyFileA" _
(ByVal lpExistingFileName As String, ByVal lpNewFileName As String, _ ByVal bFailIfExists As Long) As Long Dim A As Long A = CopyFile("C:\Prova.Txt","A:\Doc.Txt",0)

Invece in VB .Net dovremo utilizzare il seguente codice:

 Imports System.IO

 Public Module Modulo1

   Sub CopiaFile()

     File.Copy("c:\prova.txt","a:\doc.txt")

   End Sub

 End Module

Come prima, l'importazione del NameSpace IO (membro del NameSpace System) permette una elevata quantità di operazioni sui files con una sola dichiarazione all'inizio del modulo. In questo caso è stato utilizzato il metodo Copy della classe predefinita File.

Conclusioni
Il succo del discorso fatto finora è questo: se avete la possibilità di passare a VB .Net, consideratelo come un linguaggio da studiare da zero e pensate alla sintassi di VB 6 come un qualcosa di obsoleto che prima o poi farà parte della storia passata.
Munitevi di un buon libro e approfondite gli aspetti che più vi interessano. Vi renderete conto che ben poco del caro VB 6 è rimasto inalterato in .Net.
Se invece avrete necessità di utilizzare entrambe le versioni, il mio consiglio è quello di viaggiare su due binari paralleli, cercando di tenere separate due modalità di programmazione, in modo da non confondervi le idee, ma soprattutto per tener conto della presenza della piattaforma .NET Framework, la base delle applicazioni future.(segue)

Per eventuali quesiti, critiche o suggerimenti, vi ricordo comunque che potete contattarmi al mio indirizzo e-mail.