Se le custom dialog preconfezionate non ci soddisfano,
se le launch conditions dovrebbero essere un po' più complesse, se abbiamo la
necessità di creare un qualcosa che non è possibile creare con le
caratteristiche base di Windows Installer, possiamo coprire questo gap
semplicemente sfruttando come si deve il nostro amico framework. Creando una nuova
Class Library e creando
una classe che eredita da System.Configuration.Install.Installer possiamo
piegare ai nostri scopi e fare tutto quello che vogliamo. La cosa magari non è
semplicissima, ma per me è stato talmente tanto divertente ed appagante che
voglio raccontare quello che ho fatto.
Creare una Class Library ed
ereditare da System.Configuration.Install.Installer
Dunque,
abbiamo già parlato l'altra volta di come è organizzata la mia solution. In
questo momento, il mio VS.NET ha aperto una solution con due progetti:
l'applicazione, e il setup dell'applicazione stessa.
Per comodità, ho
aggiunto un terzo progetto, di tipo Class Library e l'ho
chiamato ManageSetup. Vs.NET crea come al solito un classe
Class1 che ho immediatamente eliminato. Ho aggiunto invece un Item di tipo
Installer Class e l'ho chiamato ManageSetup.
Cosa abbiamo creato? Vediamolo.
Nel Solution Explorer ho aperto il file
ManageSetup.cs.
La classe contenuta in questo file è
definita come:
[RunInstaller(true)]
public class ManageSetup : System.Configuration.Install.Installer
Ovvero, eredita per l'appunto da
System.Configuration.Install.Installer, ed inoltre è "decorata" dall'attributo
[RunInstaller(true
)]. Abbiamo il solito
costruttore e il Dispose(). Notare che se facciamo
doppio-click su ManageSetup.cs VS.NET apre un bel designer, dove possiamo posizionare tutto
quello che eventualmente ci serve (SqlConnection, SqlDataAdapter e chi ne ha più
ne metta).
A questo punto dobbiamo decidere in quale momento vogliamo
intervenire durante il setup. Se vogliamo fare un qualcosa prima che
l'installazione cominci, dobbiamo fare l'overload del metodo
Install. Se vogliamo fare un qualcosa dopo che l'installazione
è terminata, overloadiamo Commit. Poi possiamo fare
l'overloading di Uninstall e di Rollback. Io ho fatto diverse prove, tutte
andate a buon fine:
- Tramite un custom dialog ho richiesto all'utente l'inserimento
di una directory da creare automaticamente al termine del setup
- Tramite un custom dialog con i CheckBoxes, ho
richiesto all'utente la volontà di aprire un sito Web al termine del
setup
- Prima che il setup cominci, mostro una Windows Form
per chiedere un activation code
- Al termine del setup, mando un'e-mail (su richiesta) all'autore del
programma (cioè a me! )
In cui casi, ho fatto l'overloading di Install, in altri di
Commit. Ecco un piccolo esempio di codice C#:
public override void Commit(IDictionary savedState)
{
base.Commit (savedState);
System.Diagnostics.Process.Start(@"C:\WINNT\notepad.exe");
}
Questo metodo Commit viene automaticamente chiamato dal motore di Windows
Installer durante la Commit, ovvero al termine del setup. In realtà, non basta creare questa Class Library
: dobbiamo in qualche modo notificare nel Setup Project il
fatto che vogliamo utilizzare questo assembly durante il setup. Ecco come fare!!!
Modifichiamo il setup
Torniamo
nel Setup Project, apriamo la finestra dedicata al File System. Posizioniamoci
nell'Application Folder, clicchiamo con il pulsante destro, poi su
Add ed infine su Project Output. Dalla
finestra di dialogo, selezioniamo Primary Output e confermiamo
con Ok: VS.NET inserisce automaticamente nel File System un oggetto chiamato
Primary output from ManageSetup (Active).
A questo punto, andiamo su View -->
Editor --> Custom Actions. Clicchiamo con
il pulsante destro sul nodo principale (Custom Actions), selezioniamo
Add Custom Action,
andiamo dentro Application Folder e selezioniamo Primary output from ManageSetup
(Active). Nei nodi Install, Commit,
Rollback e Uninstall apparirà il "legame" con
la Class Library che abbiamo creato. Se compiliamo il progetto e proviamo a
lanciarne l'installazione, vedremo che nel momento in cui il motore di Windows
Installer genererà la Commit, verrà aperto il Blocco Note (questo ovviamente a
patto di aver fatto l'overloading di Commit usando il codice C# che indicato più sopra).
Se volessimo creare una directory durante il
setup, non dovremmo fare altro che:
- aggiungere un custom dialog TextBoxes (A), per esempio. Personalizzarlo
come vogliamo. Definire la TextBox che contiene il nome della directory come
DIR_NAME
- andare nella custom action, selezionare l'evento Commit
(nel nostro caso). Compilare la property CustomActionData
indicando nome_parametro = [valore_parametro]. Nel nostro caso, /DIR_NAME =
[DIR_NAME]. Se avessimo più parametri, bisogna separarli con uno spazio. La
CustomActionData permette di passare i parametri all'interno
del contesto di esecuzione del CLR: in questo modo nel codice C# possiamo
"prelevare" le informazioni inputate dall'utente ed elaborarle come
vogliamo
- gestire l'evento Commit nella classe, prelevare i valori
immessi dall'utente ed elaborarli. Nel nostro caso, leggere il parametro
DIR_NAME (di tipo string) e usare la classe
Directory per controllare l'esistenza della directory ed
eventualmente crearla. Il codice può essere ad esempio questo:
public override void Commit(IDictionary savedState)
{
base.Commit (savedState);
string dir_name = this.Context.Parameters["DIR_NAME"];
MessageBox.Show("Sto per creare la directory : " + dir_name);
if (! Directory.Exists(dir_name))
Directory.CreateDirectory(dir_name);
}
Nella Class Library ho aggiunto le reference a System.Windows.Forms, così ho
potuto usare la classe MessageBox, ed eventualmente mostrare
Windows Forms a piacimento.
La logica è questa. Se avessimo avuto altre custom dialog, non cambierebbe
nulla. La CustomActionData conterrebbe più parametri, nel
codice C# avremmo più righe this.Context.Parameters["nome_parametro"]: tutto il
resto è normalissimo codice per fare assolutamente quello che vogliamo. Io, come
ho detto, ho usato le librarie Indy
Sockets (freeware) per far spedirmi un'e-mail, se l'utente ha attivato una
CheckBox.
Personalizzare un setup non è nient'altro che...usare il
framework
E' vero, già da tempo i tool per la creazione di setup
professionali permettono un'avanzata personalizzazione del processo di
deployment. Però il più delle volte si tratta di imparare linguaggi di scripting
dedicati, magari piuttosto ostici, e comunque con le loro limitazioni. Ed
ancora: non c'è la possibilità di fare debug.
Questa volta invece abbiamo tutta la potenza del framework anche dentro il
nostro setup.
Sia che usiate VB.NET o C#, basta che scriviate le vostre linee
di codice per fare letteralmente quello che volete...non credo di aver mai avuto
così tanto potere e così tanta flessibilità sotto le mani durante un setup
creato da me...
Francamente, non vedo cosa potrei avere di
meglio...