ITALIANO
Nello sviluppo di applicazioni che si interfacciano con gli applicativi Office il programmatore si è sempre trovato davanti al classico dubbio: usare l'Early-Binding (associazione preventiva) oppure il Late-binding (associazione tardiva)?
Il problema, arci noto, è che se si usa il Late-Binding, ovvero usando la funzione CreateObject(), si perde la caratteristica dell'Intellisense (che non è poca cosa), ma si ha il vantaggio che il programma distribuito funzionerà su qualsiasi computer indipendentemente da quale versione di Office sia installata.
Al contrario, se si usa l'Early-Binding, si avrà a disposizione l'intellisense, ma il programma funzionerà solo quando la versione di Office installata è la stessa con cui è stato progettata l'applicazione.
Spesso (troppo spesso) si trovano nei forum le classiche (anche quelle) castronate in cui vengono mescolate entrambe le modalità di binding (che ovviamente non funzionano o funzionano male) e ciò tende ad confondere ancor più le idee di chi si approccia per la prima volta a queste problematiche.
In questo articolo spiegherò allora come sia possibile fare in modo di poter entrambe le modalità quando servono!
Cioè: usare l'Early-Binding quando si lavora nell'ambiente integrato di VB.NET (IDE), ma che una volta compilato, e senza alcuna modifica al progetto, il programma utilizzi il Late-Binding.
Tutto questo, in pratica, significa ottenere i due vantaggi ed eliminare gli svantaggi di entrambi i metodi.
Direi non male...
Passiamo al 'sodo'.
Il trucco (se vogliamo chiamarlo così) sta nello sfruttare una caratteristica di VB.NET che si trova nelle
Opzioni di compilazione avanzate accessibili dall'omonimo pulsante delle Proprietà del progetto e che si chiama
Costanti di compilazione:
Le costanti di compilazione sono davvero utili perchè consentono di compilare determinate istruzioni solo in base al valore di tali costanti. Ciò è reso possibile grazie alle direttive:
#If ... Then ... #Else
Osservando l'immagine sopra si nota che ho definito la costante condizionale:
EarlyBinding = 1
in questo modo posso decidere quali istruzioni saranno utilizzate a seconda del valore di EarlyBinding, e nel caso speciifico potrò utilizzare le direttive così:
Public Class Form1
#If EarlyBinding = 1 Then
Dim excelApp As Microsoft.Office.Interop.Excel.Application
Dim excelWorkbook As Microsoft.Office.Interop.Excel.Workbook
Dim excelWorksheet As Microsoft.Office.Interop.Excel.Worksheet
Dim excelRange As Microsoft.Office.Interop.Excel.Range
#Else
Dim excelApp As Object
Dim excelWorkbook As Object
Dim excelWorksheet As Object
Dim excelRange As Object
#End If
#If EarlyBinding = 1 Then
excelApp = New Microsoft.Office.Interop.Excel.Application
#Else
excelApp = CreateObject("Excel.Application")
#End If
Noterete che nell'IDE di VB.NET il codice di una delle due parti sarà visualizzato in grigio a seconda della modalità impostata, Debug o Release a dimostrazione di quali istruzioni saranno eseguite.
Osservando il codice, è lampante che EarlyBinding potrà contenere il valore 1 solo quando eseguirò il progetto nell'IDE di VB.NET oppure in modalità di Debug, mentre una volta compilato il progetto in modalità Release, dato che non c'è più l'IDE che la valorizza, conterrà sempre il valore 0.
Questo farà sì che eseguendo il progetto nell'IDE di VB.NET (o in Debug) saranno usate le dichiarazioni tipizzate, mentre una volta compilato l'eseguibile (Release) saranno usate le altre dichiarazioni 'As Object'.
A conferma di ciò, ho previsto nell'evento Load() del progetto di esempio un messaggio che visualizza la modalità di esecuzione:
#If EarlyBinding = 1 Then
MessageBox.Show("EarlyBinding=1 - Siamo in Debug")
#Else
MessageBox.Show("EarlyBinding=0 - Siamo in Release")
#End If
Alternando la modalità da Debug a Release (grazie al comodo combobox sulla toolbar di VS2010) si vedrà apparire un messaggio differente.
Come affermavo più sopra, oltre al vantaggio di poter continuare a sfruttare l'intellisense nell'IDE non vi sarà più il problema di versioning perchè proprio grazie alle dichiarazioni 'As Object' non esiste alcun controllo sulla versione di Office.
Questo però pone in evidenza due questioni che non bisogna assolutamente trascurare:
1) La prima riguarda il fatto che non usando dichiarazioni tipizzate il codice non può essere considerato completamente safe in quanto non esiste certezza che metodi e proprietà utilizzati siano presenti nella versione installata di Office.
Ciò costringe ad assicurarci di utilizzare metodi e proprietà che siano disponibili in tutte le versioni.
Ma, di solito, almeno nella stragrande maggioranza dei casi è così.
Comunque, volendo, è sempre possibile verificare quale versione dell'applicazione Office è in esecuzione sul computer e decidere il da farsi a seconda di questa informazione.
excelApp.Version
2) La seconda questione è inerente alle costanti intrinseche dell'applicazione specifica (Excel, Outlook, Word, e così via...) che ovviamente non saranno più disponibili nella versione compilata in modalità Release, quindi dovremo prestare attenzione a dichiarare esplicitamente tutte le costanti utilizzate nel nostro progetto, in caso contrario l'esecuzione in Release segnalerà un'errore ogni volta che non riesce a risolvere il valore.
Personalmente sconsiglio vivamente l'uso dei numeri al posto delle costanti.
Per concludere è utile sapere che il progetto di esempio fa un lavoro piuttosto semplice: tramite una OpenFileDialog consente all'utente di aprire un qualunque file Excel e di caricare il contenuto del primo foglio in un DataGridView e poi chiude l'istanza di Excel.
La particolarità è che nel progetto mostro come sia possibile aprire file Excel di qualunque versione inclusi quelli di Office 2007/2010.
Per chi non possiede Office 2007/2010 ma vuole aprire file Excel di questa versione dovrà installare il driver apposito:
Driver di Office System 2007: Data Connectivity Components
http://www.microsoft.com/downloads/details.aspx?displaylang=it&FamilyID=7554f536-8c28-4598-9b72-ef94e038c891