Monday, February 23, 2009

Bootstrapper: scrap the bootstrapper

Although the "bootstrapper" solution worked fine, the decision was made to scrap it completely and do things in a different way.

There are a few valid reasons for that:
- The application comes together with a few other device driver packages
- Currently, these packages are bundled into the .msi package and installed on the client computer, and from there they have to be installed manually
- This brings the current .msi package size to over 100MB in size
- Not every client computer would use all of the device drivers
- If the application will need to support other hardware in the future, using the same approach will keep the .msi package bloating more and more.

So, the task was changed. The requirement now is to have an application in a separate package, and all the device drivers in separate packages, but the installation process will let users select which device drivers they want to install.

After some investigation I came to the conclusion that this can not be done using the Visual Studio Setup and Deployment project. The main limiting issue here is the fact that an .msi installer can not be started from withing another .msi installer. Therefore, I can not launch my application installer, show the dialog with options, and proceed to installing these optional drivers.

A simple solution I came up with was to write a small 'wrapper' Windows Forms application. The application would present the user with multiple checkboxes - one for each optional component.

After the user makes the choices and presses the 'Install' button, the application would first read the xml file which lists all available components






...


The name/path pairs would be added to the

Dictionary packages;

DriverPackage1, ..., MainAppPackage will be set up as tags for the checkboxes at design time to simplify the functionality.

The application will then loop through all checkboxes and, if the checkbox is checked, will add the setup file path to the list.


string startupPath = Application.StartupPath;

string path;
List components = new List();

foreach (Control control in this.Controls)
{
CheckBox checkBox = control as CheckBox;

if (checkBox != null && checkBox.Checked)
{
if (packages.TryGetValue(checkBox.Tag.ToString(), out path))
{
components.Add(path);
}
}
}

Finally, the application will loop through the list of setup files, executing the installation process for each file and waiting for it to finish before launching next one.


foreach (string componentPath in components)
{
InstallComponent(startupPath + componentPath);
}

// ..........

private void InstallComponent(string filePath)
{
System.Diagnostics.Process installerProcess;

installerProcess = System.Diagnostics.Process.Start(filePath);

while (installerProcess.HasExited == false)
{
//indicate progress to user
Application.DoEvents();
System.Threading.Thread.Sleep(250);
}
}

Other small details include a progress bar, success messages etc., but the main idea should be clear.

by . Also posted on my website

No comments: