Extending Visual Studio Setup Project






4.88/5 (66 votes)
Extending Visual Studio Setup Project for Building Reliable Windows Installer (MSI)

Introduction
One of the things I hear all the time when companies talk about building reliable Windows Installer (MSI) for their product is –> Visual Studio Setup Project is not enough and we need much much more, my first response is – Wait, VS Setup project is not like Advanced Installer, InstallShield but still can do a lot more outside the box.
Setup projects are used to create Windows Installer (.msi) files, which are used to distribute your application for installation on another computer or Web server. There are two types of setup projects:
- Standard setup projects create installers that install Windows applications on a target computer.
- Web setup projects create installers that install Web applications on a Web server.
In this article, I’ll show how to extend your VS Setup Project and help to understand how VS Setup makes it easy for developers to build reliable Windows Installer (MSI) in Visual Studio. (All my screenshots will take from Visual Studio 2010.)
- Getting Started With VS Setup Project
- Adding New User Dialog and Deployments Conditions
- Run External Application during Setup
Getting Started
Open Visual Studio and create new Setup Project called – "DemoSetup
", the Setup project item can be found under "Other Project Types"-> "Setup and Deployment" –> "Visual Studio Installer".
Also create a WPF application called – "DemoWpfApplication
", we need some project to work with.
Two things need to be done in order to get the MSI ready for deployment.
- On the
DemoSetup
project, Add Project Output fromDemoWPFApplication
– Setup will automatically find all related dependencies. - Modify Setup Project properties (See picture below)
The Version
Property is very important for various MSI, in order to identify old installation and overwrite existing files with a newer version.

Adding New User Dialog and Deployments Conditions
Now, this is one of most common improvement users always want – Add an additional Dialog during the setup and add your own questions or input.
In this step, I’ll show how to add conditions and add a new user Dialog, here are the requirements: Add the following file (Dummy Files):
- Blue.bmp,Red.bmp, Green.bmp
- License.rtf
- "Readme for 2000.txt", "Readme for Windows 7.txt"
1. First Let's Add Our Product License Agreement
Select the Setup Project and click "User Interface Editor" icon:

This will open a view showing all the dialogs the user will see during the Setup process.
Click "Add Dialog" and choose "License Agreement", after adding this dialog view dialog properties and select the License.rtf file.

2. Add Deployment by Condition
Add deployment condition for "Readme for 2000.txt", "Readme for Windows 7.txt", the propose is to copy each file only for specific operation system.
Select "Readme for 2000.txt" to see his properties, locate Condition
and add this command –
WindowsBuild = 2195 or VersionNT = 500
Now select "Readme for Windows 7.txt" and add this in the Condition property –
WindowsBuild >= 7100 or VersionNT = 601
(More information on Operating System Property Values)
The condition will allow you to copy specific file depending on the user OS.
3. Add your User Choose Condition
This step will show you how to add your own questions (using Radio Buttons) and allow the user to define a Favorite Color and use User choose as condition for deployment.
Add a new Dialog and choose "RadioButton
(3 buttons)" add fill the information as below:

To add the condition, you need to select each of the following files: Blue.bmp, Red.bmp, Green.bmp and add the proper value in the condition property as follow - FAVORITECOLOR="Blue"
, FAVORITECOLOR="Red" etc
.
Build the setup project and run it, select Green in "Favorite Color" and the result should look like:

Run External Application during Setup
In this step, I’ll show how to run an external application before the actual install process using "Installer Class".
Create new WPF Application project called – "SetupHelper
" and add additional Item of type "Installer Class" called – "MyInstallerHelper
".
The InstallerClass
will allow you to override the following events:
Rollback
Install
OnAfterInstall
Commit
OnAfterRollback
OnAfterUninstall
OnBeforeRollback
OnBeforeUninstall
OnCommitted
OnCommitting
Uninstall
OnBeforeInstall
First, add your code for "SetupHelper
" WPF application, I’ve added code to show current processes and process title, but you can add whatever you want.
Now we need to add "SetupHelper
" WPF app to our setup project, select the Setup Project and "Add Project Output" of SetupHelper
.
Select the Setup Project and click on the "Custom Actions Editor" icon:

On the install, add new "Custom Action" and from the "Application Folder", pick "Primary output from SetupHelper
(Active).
Now select the new Custom Action and in the "CustomActionData
", add the following -
/Run=SetupHelper.exe /WaitForExit=true
Back to MyInstallerHelper
, override OnBeforeInstall
and paste the code below in order to get the CustomActionData
you wrote above:
protected override void OnBeforeInstall(IDictionary savedState)
{
try
{
base.OnBeforeInstall(savedState);
FileInfo fileInfo = new FileInfo
(System.Reflection.Assembly.GetExecutingAssembly().Location);
//Take custom action data values
string sProgram = Context.Parameters["Run"];
sProgram = Path.Combine(fileInfo.DirectoryName, sProgram);
Trace.WriteLine("Install sProgram= " + sProgram);
OpenWithStartInfo(sProgram);
}
catch (Exception exc)
{
Context.LogMessage(exc.ToString());
throw;
}
}
OpenWithStartInfo
will run SetupHelper
application and will pause the setup process while the SetupHelper
is open.
void OpenWithStartInfo(string sProgram)
{
ProcessStartInfo startInfo = new ProcessStartInfo(sProgram);
startInfo.WindowStyle = ProcessWindowStyle.Normal;
string[] ExcludeKeys = new string[] { "run", "WaitForExit" };
startInfo.Arguments = ContextParametersToCommandArguments(Context, ExcludeKeys);
Trace.WriteLine("run the program " + sProgram + startInfo.Arguments);
Process p = Process.Start(startInfo);
ShowWindow(p.MainWindowHandle, WindowShowStyle.Show); //otherwise it is
//not activated
SetForegroundWindow(p.MainWindowHandle);
BringWindowToTop(p.MainWindowHandle); // Make sure the user will see
// the new window above of the setup.
Trace.WriteLine("the program Responding= " + p.Responding);
if ((Context.IsParameterTrue("WaitForExit")))
{
p.WaitForExit();// Have to hold the setup until the application is closed.
}
}
ContextParametersToCommandArguments
gets the CustomActionData
arguments you added in the Custom Action.
public static String ContextParametersToCommandArguments
(InstallContext context, string[] ExcludeKeys)
{
ExcludeKeys = ToLower(ExcludeKeys);
StringBuilder sb = new StringBuilder();
foreach (DictionaryEntry de in context.Parameters)
{
string sKey = (string)de.Key;
bool bAdd = true;
if (ExcludeKeys != null)
{
bAdd = (Array.IndexOf(ExcludeKeys, sKey.ToLower()) < 0);
}
if (bAdd)
{
AppendArgument(sb, sKey, (string)de.Value);
}
}
return sb.ToString();
}
public static StringBuilder AppendArgument(StringBuilder sb, String Key, string value)
{
sb.Append(" /");
sb.Append(Key);
//Note that if value is empty string, = sign is expected, e.g."/PORT="
if (value != null)
{
sb.Append("=");
sb.Append(value);
}
return sb;
}
#region "FS library methods"
public static string[] ToLower(string[] Strings)
{
if (Strings != null)
{
for (int i = 0; i < Strings.Length; i++)
{
Strings[i] = Strings[i].ToLower();
}
}
return Strings;
}
#endregion //"FS library methods"
#region "showWindow"
// http://pinvoke.net/default.aspx/user32.BringWindowToTop
[DllImport("user32.dll")]
static extern bool BringWindowToTop(IntPtr hWnd);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetForegroundWindow(IntPtr hWnd);
//from http://pinvoke.net/default.aspx/user32.SwitchToThisWindow
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, WindowShowStyle nCmdShow);
/// <summary>Enumeration of the different ways of showing a window using
/// ShowWindow</summary>
private enum WindowShowStyle : uint
{
Hide = 0,
ShowNormal = 1,
ShowMinimized = 2,
ShowMaximized = 3,
Maximize = 3,
ShowNormalNoActivate = 4,
Show = 5,
Minimize = 6,
ShowMinNoActivate = 7,
ShowNoActivate = 8,
Restore = 9,
ShowDefault = 10,
ForceMinimized = 11
}
#endregion
Try It
Now Run the Setup project and you will notice that during the installation process, your Setup Helper will pop up and prevent the Setup from continuing until you will close the application.

After the setup is complete, you will see your setup output as below:

Summary
As you saw in this article, Visual Studio Setup Project can be extended a lot more and this can be good for many applications.
History
- 16th January, 2011: Initial post