Introduction
I am a struggling young software developer, and I often find myself surfing the web in search of various solutions for various problems, and CodeProject seems to be there for me most of the times. This time I encountered another problem: I wanted to create a setup and deployment project which passes arguments during installation time from the user to the configuration file of my application. It took me a while but I managed to find a way to make it work.
In this article, I will demonstrate how to create a Windows setup project which receives a string from the user and places that string in the configuration file of the application during the installation.
Background
In brief, the whole process is as follows:
- We create a project that we want to install.
- We create a Setup And Deployment project that will install the former project on the target computer.
- In the 'File System' window of the setup project, we add the primary output of our application and do all the usual routines.
- We add to the 'User Interface' window of the setup project a new dialog window that has a textbox in which the user will insert his string.
- We add a new class that derives from the class '
Installer
' and override the methods we want to use during the installation (Install
, Commit
, Rollback
, and Uninstall
).
- We "connect" the new '
Installer
'-derived-class to the setup project by adding our primary output to the Install Custom Action in the 'Custom Actions' window.
- We expose the textbox in the newly added dialog window so that it can be reached from the code.
- Finally, we write the code we want to perform during the installation (in my case, the code reads the string from the newly added dialog and updates the configuration file in the target computer).
Using the code
Let's get to work...
First of all, I created a simple Windows application that simply gets a path from the configuration file and sets the background image of the form to that path.
The app.config file looks like this:
="1.0" ="utf-8"
<configuration>
<appSettings>
<add key="FilePath" value="..\..\Images\penguin.png"/>
</appSettings>
</configuration>
And the constructor of the form gets that string and sets the BackgroundImage
property to the given string which, in fact, represents the image file.
The constructor looks like this:
public Form1()
{
InitializeComponent();
string filePath =
ConfigurationSettings.AppSettings["FilePath"];
Image backImage = Image.FromFile(filePath);
this.BackgroundImage = backImage.GetThumbnailImage(
this.Width,
this.Height,
null,
IntPtr.Zero);
this.Refresh();
}
Don't forget to add a reference to the System.Configuration
namespace in order to gain access to ConfigurationSettings.AppSettings
.
Now, what I want to do is create a setup and deployment project for my desktop application. In order to do that, what we need is to add a new project to our solution and select the setup and deployment project option as shown in the image below, and choose the "Setup Project" option in the Templates option.
Image 1: adding a setup and deployment project.
After adding the project, we can see the 'File System' window:
Image 2: file system window.
This window has three default folders:
By right clicking the root ('File System On Target Machine'), one can add more folders to the tree in the 'File System' window, were each folder installs the items placed with in it to a similar location on the target computer.
Up until now, all I did was simply install my application on the target computer and create its shortcut in the desktop.
When we run the installation wizard, we see only three screens: Welcome screen, Installation Folder screen (in which we specify were to install our application, and it is in that location that the installation wizard will install all the items we put in the 'Application Folder' node in the 'File System' eindow), and the Confirm screen which is the last screen before the installation finishes.
Now, let's play with the installation wizard and add some more screens. First of all, we need to right click the setup project in the Solution Explorer, and in the 'View' option, we choose 'User Interface' (as shown in the image below). In this screen, we see a tree that specifies the order of the screens of the installation wizard. Under the Install node, you can see the three default screens. I added a screen with a textbox for the user to enter a string, by right clicking the Install node and choose the 'Add Dialog' option (Image 5). You will see a number of dialogs you can add. I chose the TextBoxes (A) dialog.
Image 4: view the 'User Interface' window to add more dialogs to the installation wizard.
Image 5: add a dialog to the 'User Interface' window.
In the TextBoxes dialog that I add to my wizard, there are, by default, four textboxes, but I need only one, so I simply change the other three textboxes' 'Visible
' property to false
in the Properties window. In the Properties window, you can also play with the text in the banner and the body of the dialog.
After we add the dialog, we need to somehow perform during the installation an action that will take the string from the textbox in the newly added dialog, and update the configuration file.
Now, we write a method that will be called during the installation process. To do that, we need to create a class that will derive from the class Installer
, and add the attribute [RunInstaller(true)]
. The new class can override the four main methods: Install
, Uninstall
, Commit
, and Rollback
.
[RunInstaller(true)]
public class InstallHelper : Installer
{
*
*
*
In this class, I override the Install
method in which I will get the text from the new textbox, and update the configuration file.
However, in order that the installation wizard will turn to our method, we first need to add a Custom Action. By right clicking on the setup project in the Solution Explorer window and clicking View->Custom Actions, we see the 'Custom Actions' window which presents to us a tree with four nodes: Install, Commit, Rollback, and Uninstall.
What I need now is to "connect" the installation wizard to my 'Install
' method, so I added a new custom action by right clicking the Install node and clicking on 'Add Custom Action':
Image 6: Custom Actions window.
After doing so, a window pops up in which I select my application primary output (in my application, I have the 'InstallerHelper
' class):
Image 7: adding a Custom Action
Note that for each method we can override (in the class that derives from 'Installer
'), we have a node in the Custom Actions window.
Now when the install wizard will run, it will perform my overridden 'Install
' method.
Now what we need to do is:
- Expose the
Text
property of the TextBox
in the new dialog so that we can access its value from the code.
- Write the code in the
Install
method that will update the configuration file.
For exposing the Text
property, we go to the Properties window of the newly added custom action. Here, we can see a property named 'CustomActionData
', and here, I declare my Text
property in the following format: /<key>=[<property name>]
. My specific declaration was '/PathValue=[EDITA1]
' because PathValue
was the name I gave, and with this name, I will get the property value in the code later on, and the TextBox
name was 'EDITA1
':
Image 8: update the CustomActionData
property
Note that you can add as much declarations as you want.
Now, we can finally write some code.
To read the value in the TextBox
from the code, all we need to do is in the 'Install' method we override, read the value from Context.Parameters[key]
were the 'key
' is actually the key we write when we declare the property (when we expose the textbox). In my case, the key is, of course, 'PathValue
'.
Note that the property Context.Parameters
's default value does not contain the Text
property of our new textbox. We had to expose it in the Custom Action Properties window.
Another important fact is that after installing the application, the configuration file exists in the target computer under the name of the executable file plus the ending ".config". For instance, if after the installation, the executable file is "MyApp.exe", then in the same directory, you will find the configuration file "MyApp.exe.config" (assuming of course that the application has a configuration file).
Another important value in the 'Context.Parameters
' property is the path to the executable file that will be installed to the target computer. Since we know that the configuration file has exactly the same path plus the ending ".config", we have the path to the configuration file.
string assemblypath = Context.Parameters["assemblypath"];
string appConfigPath = assemblypath + ".config";
All that is left to be done is to use the 'XmlDocument
' class to update the configuration file which we have the path to. You can view my code in the files attached.
Hope this will help you like you always help me.
Points of Interest
Very important: note that the user can't enter a string with spaces in the textbox. For some reason unknown to me, whenever I enter a string with spaces, the installation fails to work.