Early-Late Binding con Outlook
Pubblicato il 23/06/2010
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)?
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) e ciò tende ad confondere ancor più le idee del neofita.
Per chi non ha ben presente l'argomento suggerisco la lettura di un breve ma conciso articolo sulle differenze tra le due modalità di associazione ad opera di @Alex: http://forum.masterdrive.it/vba-tutorials-and-how-to-37/latebinding-vs-earlybinding-46733/
Anche se lui si riferisce al solo VBA, il concetto è esattamente uguale. Solo che VB6, come vedremo, mette a disposizione un qualcosa in poù che consente di risolvere il problema in modo elegante.
In questo articolo, invece, spiegherò come sia possibile fare in modo di poter usare l'Early-Binding quando si lavora nell'ambiente integrato di VB6 (IDE), ma nello stesso tempo, senza alcuna modifica al progetto, venga poi eseguito a run-time utilizzando il Late-Binding.
Come esempio, prenderemo l'automazione con Outlook, ma il concetto vale per qualsiasi altra applicazione di Office che esponga il relativo modello ad oggetti.
Prima di tutto, assicuriamoci di aggiungere il riferimento alla libreria di Outlook al nostro progetto. Nel mio caso, avendo Office 2007, sarà la versione 12.0

Nota importante: non importa quale versione usiate voi, e non importa quale versione ha l'utente finale.
Non importa semplicemente perchè tale libreria sarà utilizzata solo all'interno dell'IDE di VB6. Quando il programma sarà eseguito sul computer dell'utente, userà quella presente.
Infatti, come vedremo tra poco, il programma utilizzerà l'Early-Binding quando è eseguito nell'IDE, mentre quando sarà eseguito nella versione compilata userà automaticamente il Late-Binding.
Il bello è che ciò sarà possibile senza che lo sviluppatore debba modificare il proprio progetto!
Ricordo infatti che di solito si usa(va) utilizzare l'Early-Binding in fase di sviluppo con il vantaggio di avere disponibile il modello ad oggetti esposto dall'applicativo Office, intellisense incluso, ma poi al momento della compilazione si dovevano commentare le righe delle dichiarazioni che si riferivano direttamente alla libreria referenziata, rimuovere il riferimento alla libreria stessa, ed utilizzare CreateObject(...); poi si doveva rimettere tutto a posto per eventuali sviluppi futuri del progetto.
Tutt'altro che piacevole...
Ora dobbiamo predisporre il progetto affinchè possa distinguere la modalità di esecuzione sfruttando un argomento di compilazione condizionale.
Apriamo le Proprietà del progetto e nella scheda Crea inseriamo l'assegnazione EarlyBinding = 1 come mostrato in figura:

Bene, adesso iniziamo a scrivere il codice in modo da sfruttare l'argomento di compilazione condizionale.
Apriamo la finestra del codice del nostro form, e nella sezione delle Dichiarazioni inseriamo il codice
Rem ------------------------------------------------------------
Rem Dichiarazione condizionale degli oggetti in funzione di come
Rem sarà eseguito il programma (dall'IDE di VB o dall'EXE)
Rem ------------------------------------------------------------
#If EarlyBinding = 1 Then
Rem VB IDE
Rem OUTLOOK
Dim myOlApp As Outlook.Application
Dim myNameSpace As Outlook.NameSpace
Rem CONTACT
Dim myContacts As Outlook.Items
Dim myItem As Outlook.ContactItem
Rem APPOINTMENT
Dim myAppointments As Outlook.Items
Dim myRestrictItems As Outlook.Items
Dim myAppItem As Outlook.AppointmentItem
Rem Used both for CONTACTS and APPOINTMENTS
Dim objItems As Outlook.ItemProperties
Dim objItem As Outlook.ItemProperty
#Else
Rem EXE stand alone
Rem OUTLOOK
Dim myOlApp As Object 'Outlook.Application
Dim myNameSpace As Object 'Outlook.NameSpace
Rem CONTACT
Dim myContacts As Object 'Outlook.Items
Dim myItem As Object 'Outlook.ContactItem
Rem APPOINTMENT
Dim myAppointments As Object 'Outlook.Items
Dim myRestrictItems As Object 'Outlook.Items
Dim myAppItem As Object 'Outlook.AppointmentItem
Rem Used both for CONTACTS and APPOINTMENTS
Dim objItems As Object 'Outlook.ItemProperties
Dim objItem As Object 'Outlook.ItemProperty
#End If
Come vedete abbiamo inserito delle doppie dichiarazioni che saranno utilizzate, le une o le altre, a seconda della valore indicato alla riga
#If EarlyBinding = 1 Then
Ora, dato che noi abbiamo impostato questo valore su 1 (figura 1) sarà utilizzata la modalità Early-Binding.
Ciò ci permetterà di sfruttare comodamente l'intellisense di VB6 quindi avere sotto mano tutti gli oggetti e metodi di Outlook e relativa sintassi digitando il punto dopo la nostra variabile oggetto myOlApp:
myOlApp.
Probabilmente avete già capito: quando il progetto sarà compilato ed eseguito stand-alone il valore di EarlyBinding sarà sempre 0 (perchè non c'è più l'IDE di VB6 a valorizzarla in automatico) per cui le variabili oggetto dichiarate saranno quelle As Object.
Addesso occorre un secondo passo: dopo averle dichiarate occorre istanziarle in modo corretto. per cui nell'evento Form_Load() faremo più o meno la stessa cosa, ma questa volta useremo una proprietà dell'oggetto Application: App.LogMode
Private Sub Form_Load()
If App.LogMode = 1 Then ' sta eseguendo l'EXE (compilato)
' uso il Late-Binding
Set myOlApp = CreateObject("Outlook.Application")
Else ' sta eseguendo il progetto nell'IDE
' uso l'Early-Binding
Set myOlApp = Outlook.Application
End If
' se sul computer non esiste Outlook avvio la chiusura del form
If myOlApp Is Nothing Then
GoTo OUTLOOK_NOT_FOUND
End If
' Outlook esiste, per cui posso istanziare anche gli altri oggetti.
Set myNameSpace = myOlApp.GetNamespace("MAPI")
Set myAppointments = myNameSpace.GetDefaultFolder(olFolderCalendar).Items
Set myContacts = myNameSpace.GetDefaultFolder(olFolderContacts).Items
Exit Sub
OUTLOOK_NOT_FOUND:
Timer1.Enabled = False ' Esce dall'applicazione
End Sub
Come vedete, non è poi così difficile.
Il vantaggio di non dover modificare niente per 'commutare' tra le due modalità (early e late) non è di poco conto per lo sviluppatore che in pratica non deve curarsi di nulla, se non quella di migliorare la propria applicazione.
A questo punto può essere spontaneo domandarsi se lasciare attivo il riferimento alla libreria di Outlook 2007 (v.12.0) non crei problemi nel caso si esegua il programma su un computer in cui è installata una versione diversa.
No, non crea alcun problema per il semplice fatto che nell'eseguibile l'oggetto Outlook.Application non sarà né dichiarato, né istanziato direttamente ma sempre e solo tramite la CreateObject().
Ultima nota importante: le costanti esposte da Outlook.
Quando il programma sarà compilato (EXE) le costanti di Outlook non sono più visibili perchè esse sono legate direttamente all'oggetto referenziato della libreria nel progetto.
Ovviamente, non essendoci più un riferimento esplicito a tale libreria il programma eseguibile non è in grado di accedervi, per cui è assolutamente necessario dichiarare nel progetto tutte le costanti utilizzate. Esempio:
Rem Outlook constants:
Public Const olMailItem = 0
Public Const olAppointmentItem = 1
Public Const olContactItem = 2
Public Const olTaskItem = 3
Public Const olJournalItem = 4
Public Const olNoteItem = 5
Public Const olPostItem = 6
Public Const olDistributionListItem = 7
Public Const olFolderDeletedItems = 3
Public Const olFolderOutbox = 4
Public Const olFolderSentMail = 5
Public Const olFolderInbox = 6
Public Const olFolderCalendar = 9
Public Const olFolderContacts = 10
Public Const olFolderJournal = 11
Public Const olFolderNotes = 12
Public Const olFolderTasks = 13
Public Const olFolderDrafts = 16
Sarebbe superfluo farlo, ma ricordo che le costanti devono essere sempre accessibili (scope) quindi consiglio di dichiararle Public in un modulo BAS, oppure impostare un enumerazione, oppure creare una classe, fate voi;
l'importante è che siano sempre accessibili altrimenti quando eseguite il programma compilato i risultati saranno inaspettati.
