Custom user interface for MSI packages using C# .Net
Introduction
Windows installer has its own way to display installer user interface which is far different from other technologies. MSI supports few controls compared to .Net or other platform. Though it is not very difficult, still it is hard job to develop sophisticated installation package with good user interface, even after using well known installer software..
Nvn Installer ships MsiDotNet API (NvnInstaller.MsiDotNet.dll) which is developed using .Net framework 2.0. So installation package author can use this API to create good looking installer UI using .Net framework, WPF and 3rd party libraries. This API is very useful when some other tasks need to be completed other than installation.
For example:
- license key validation using a web service
- installing your software only when payment is done
- displaying advertisements
- Installing multiple software
- accepting inputs from user and updating remote database
- any crazy things that you can accomplish using .Net
MsiInstaller Class
MsiInstaller is the basic class which initiates, controls, terminates installation process. Following are the useful functions which .Net application can use.
Install() – All features and components are installed.
Install(List
Remove() – All features and components are uninstalled.
Remove(List
Repair() – MsiInstaller class detects list of features already installed on local system and re-installs them.
Update(List
Install List – Feature is reinstalled if it is already installed or that feature is freshly installed.
Uninstall List – Feature which are already installed are removed or other features are ignored.
.Net application needs to subscribe InstallerMessageReceived event to handle Windows Installer messages. InstallerMessage object can be typecasted to specific InstallerMessage classes to obtain detailed information
For Example
Collapse
void msiInstaller_InstallerMessageReceived(object sender, InstallerMessageEventArgs e) {
if (e.InstallerMessage.Type == InstallerMessageType.ProgressReport) {
if (reset) {
ProgressReportMessage progressReportMessage = (ProgressReportMessage)e.InstallerMessage;
if (approximate && installPrograssBar.Maximum < (installPrograssBar.Value + progressReportMessage.TicksMoved)) return;
installPrograssBar.Value += (int)progressReportMessage.TicksMoved;
}
} else if (e.InstallerMessage.Type == InstallerMessageType.ResetMessage) {
reset = false;
// set progress bar properties
ResetMessage resetMessage = (ResetMessage)e.InstallerMessage;
installPrograssBar.Maximum = (int)resetMessage.Ticks;
installPrograssBar.Minimum = 0;
installPrograssBar.Step = 1;
installPrograssBar.Value = 0;
approximate = resetMessage.IsApproximate;
reset = true;
} else if (e.InstallerMessage.Type == InstallerMessageType.ActionData) {
SetLabel(((ActionDataMessage)e.InstallerMessage).Message);
} else if (e.InstallerMessage.Type == InstallerMessageType.ActionStart) {
ActionStartMessage actionStartMessage = (ActionStartMessage)e.InstallerMessage;
SetLabel(actionStartMessage.Action + ": " + actionStartMessage.Description);
} else if (e.InstallerMessage.Type == InstallerMessageType.FileInUse) {
MsiResponse userAction = (MsiResponse)MessageBox.Show("file in use:" + ((FileInUseMessage)e.InstallerMessage).FilePath, "File in use", MessageBoxButtons.AbortRetryIgnore);
msiInstaller.SetUserAction(userAction);
} else if (e.InstallerMessage.Type == InstallerMessageType.InstallationComplete) {
SetLabel("Installation Completed");
}
// Cancel installation
if (cancel && e.SetUserAction) {
msiInstaller.SetUserAction(MsiResponse.Cancel);
}
}
About features
MsiFeature is the basic class which contains all information about a feature. Installer user interface author can use the list of features to selectively install/uninstall. Use MsiInstaller.FeatureTree to get list of feature. This property gives only root features. Use ChildFeatures property recursively to get complete list of features.
For example
Collapse
public void LoadFeatures() {
MsiInterface msiInterface = new MsiInterface();
Listfeatures = msiInterface.FeatureTree;
foreach (MsiFeature feature in features) {
LoadFeatureTree(feature, null);
}
}
private void LoadFeatureTree(MsiFeature feature, TreeNode node) {
TreeNode newNode = null;
if (node == null) {
newNode = tvFeatures.Nodes.Add(feature.Title);
} else {
newNode = node.Nodes.Add(feature.Title);
}
newNode.Checked = feature.IsAlreadyInstalled;
if (feature.ChildFeatures != null) {
foreach (MsiFeature childFeature in feature.ChildFeatures) {
LoadFeatureTree(childFeature, newNode);
}
}
}
Use IsAlreadyInstalled property of MsiFeature to know whether feature is already installed on local system.
Configuring with Nvn Installer
- Create MSI package using Nvn Installer and save project file.
- Create windows application using NvnInstaller.MsiDotNet and MSI package created using Nvn Installer. Name of application should same as name of MSI file. For example Test.exe for Test.msi
- Setting parameters in Custom UI Application tab
- Open the project which is used for creating installation package.
- Open Custom UI Application tab
- Browse and select folder containing custom UI application and its supporting files
- Above action list all file in supporting files list. Now select only those file which you like to package.
- Click Build >> Build MSI file or Press F6