isual Studio setup projects provide a quick and easy way for end-users to deploy your application, whether it is a Web site, Windows NT service, smart client, or Web service. Even though the .NET framework introduced the idea of “xcopy deployment,” for many projects it is useful (or expected) that you automate all the tasks required by your installation procedure, thus ensuring the consistency and repeatability of the installation process. When you do that, system administrators and end users gain the ability to perform the installation process without technical assistance?and you avoid the need to provide detailed end-user documentation on the process.
A standard Visual Studio setup project can copy files and create directories on the target file system, create start menus, and create registry entries. If you need to do more, you may need to implement custom actions.
MSI Custom Installer Actions
Since the release of the Windows Installer component, most third-party (and Microsoft) setup-creation tools make use of it as a common base of functionality. Windows Installer setups allow developers to execute both standard actions and custom actions as part of a setup sequence.
You use custom actions when you need to perform special or application-specific tasks that standard actions cannot accomplish. The .NET framework exposes the custom actions capability via the Installer class, whose methods you override to perform tasks of your choice.
|Author’s Note: The techniques shown in this article work with the .NET framework 1.0 or 1.1 and Visual Studio. The code samples were written using Visual Studio 2003 and .NET 1.1|
Create Your Own Custom Action in .NET
To add a custom action to your setup project, you need to:
- Create an installer class.
- Override the Install and Uninstall methods.
- Test your installer class implementation using the .NET installer utility.
- Configure your setup project to use your custom installer.
Create the Installer Class
Create a class that inherits from the System.Configuration.Install.Installer class (you must first add a reference to the System.Configuration.Install.dll to your project). This class must be public, and it needs to be in one of the assemblies that are installed by your setup, so place it in one of your existing assemblies, or create a new assembly specifically for the custom installer class. Make sure you add its primary output to your setup. You must also add a RunInstallerAttribute(True) attribute to your installer class. For example:
_ Public Class MyInstaller Inherits System.Configuration.Install.Installer End Class
Override the Install and Uninstall Methods
You must override the Install and Uninstall methods to add the code to perform your custom installation steps. You can include user interaction when necessary; for example, your code can display forms to gather user input or display status and perform whatever custom steps are required for your application setup.
Make sure you call the base implementation of the Install and Uninstall methods within your overridden methods to ensure that your install executes automatic tasks such as logging to files and installing state recording. To do that call mybase.Install(stateSaver) and mybase.uninstall(savedState) respectively.
Be careful not to reference classes in your application assembles that are outside the assembly in which your installer class resides?they may not be installed yet!
Test Your Install Class
You run the installer utility installutil.exe (located in the .NET framework directory) from the command line to test your custom installer class. The utility accepts an assembly filename as an argument. You can also execute an uninstall using “/u” as the first command-line argument. The standard .NET framework 1.1 install places the installer utility on client machines, so you can also use installutil.exe to repeat setup tasks on client machines or to troubleshoot failed installations. For example, the following code fragment runs an install:
C:Source Codesamplesin>installutil installersample.dll
Or to run an uninstall, use:
C:Source Codesamplesin>installutil /u installersample.dll
Refer to the MSDN documentation for the installer utility for more information.
Custom Installer Class Example
Here’s a simple example custom installer class that shows how to inherit from the Installer class and override the Install and Uninstall methods. This sample creates an event log source during the install process and removes it during the uninstall.
_ Public Class SimpleInstaller Inherits System.Configuration.Install.Installer Const EVENTSOURCE_NAME = "DevX Sample" Public Overrides Sub Install(ByVal stateSaver As _ System.Collections.IDictionary) Dim strAssemblyPath As String Dim frmSelection As New Forms.Selection Try MyBase.Install(stateSaver) EventLog.CreateEventSource( _ EVENTSOURCE_NAME, "Application") Catch exc As Exception MsgBox("Error performing installer tasks-" & exc.ToString, Exclamation, "Example") End Try End Sub Public Overrides Sub Uninstall(ByVal savedState _ As System.Collections.IDictionary) Try MyBase.Uninstall(savedState) EventLog.DeleteEventSource(EVENTSOURCE_NAME) Catch exc As Exception MsgBox("Error performing un-installer tasks-" & exc.ToString,Exclamation, "Example") End Try End Sub End Class
Using Your Custom Installer
You need to configure your setup project to recognize your custom installer. First, make sure your installer class is in an assembly that will be deployed with your setup. Next, right-click your setup project, select the view menu, and then click Custom Actions (see Figure 1).
|Figure 1. Configuring a Custom Action: You can view or configure custom setup actions using the context menu available by right-clicking on your setup project item in the Solution Explorer.|
You’ll see the custom actions editor. Right-click the “Custom Actions” node, and click “Add Custom Action”, and then choose the assembly that contains your installer class implementation (see Figure 2).
|Figure 2. Adding Custom Actions: From the Custom Actions editor, right-click the “Custom Actions” node, select the “Add Custom Action” menu item, and then choose the assembly containing your installer class.|
Remember to select the assembly that contains your installer class, not the class you want to execute at setup time. The Windows Installer service uses the .NET framework to find all instances of the installer class in your assembly with the RunInstallerAttribute attribute set to true and executes each one. You can have multiple installer classes in your assembly.
You can also choose to execute your installer class in only some of the install, commit, rollback, and uninstall phases by adding your installer class to those nodes only (right-click the node you want, rather than the top “Custom actions” node.
Storing Install State Data
Use the stateSaver argument passed to the Install method to save information you will need later to perform custom uninstall actions. Having saved such information during the install, you retrieve it for the uninstall via the savedState argument passed to the Uninstall method. For example, if you were to prompt the user for the name of an IIS virtual directory that you want the install process to create automatically, you could then store the name of the virtual directory so that you could delete it on uninstall.
In your installer class install() method, save state like this:
stateSaver.Add( _ "VirtualDirectoryName", .CreateVirtualDirectory)
Having saved the virtual directory name during the install process, in your uninstall() method, you can retrieve it like this:
blnCreate = savedState("VirtualDirectoryName")
Use the LogMessage method to provide feedback from your installer. This is particularly useful when troubleshooting setup issues. Your output is stored in a log file and is also displayed in the command window when using installutil.exe. By default, the log file is stored in the same directory as your assembly with the same file name as your assembly and an .InstallLog file extension.
Avoid Unhandled Exceptions
If you allow exceptions to be thrown from your installer class, the calling application (your MSI setup) will fail. This is a particular problem if your installer class generates an exception during an uninstall, as it can make it impossible for users to uninstall your application. You should trap all exceptions, use LogMessage to record their details, and display on-screen messages as appropriate.
Setup Task Examples
The sample project includes a generic implementation of the installer class with a selection form and a status form. The sample displays the selection form to allow user selections and executes code to create a virtual directory, an event source for the application log, and a performance monitor category and counters.
Here are some other ideas you may want to implement:
- Present a settings dialog and write settings to a configuration (.config) file. This could include user preferences, database connection settings, or anything else you may need. You can use this method to avoid overwriting an existing configuration file when you re-run setup by checking for an existing file before writing out a set of default settings.
- Register your application online.
- Automatically check for upgrades (see the article Automatically Upgrade Your .NET Applications On-the-Fly)
- Perform custom uninstall clean-up actions like temporary file deletion to ensure your application uninstalls cleanly.
There are many application-specific tasks you need to execute at setup time. By using the installer class to write custom actions in .NET, you can code them in your chosen .NET language rather than in some vendor-specific third-party installer language. Doing it yourself lets you make the best use of your development skills and provides the means to reuse your code in your application. For example, it’s often desirable to use parts of your setup code from within your application for configuration or preferences forms.
Using an installer class in .NET is easy and gives you the essential flexibility you need to perform tasks at setup time.