cscript adsutil.vbs set w3svc/MaxConnections 40
October 22, 2009
September 15, 2009
- The safest way to use it is with the using clause.
- Always call Commit() before the end of the using.
- The optional TransactionScopeOptions enum parameter in the constructor defaults to TransactionScopeOption.Required meaning this new Transaction will join an existing one, the existing one is one that has already been created and is know as the "Ambiant Transaction".
September 03, 2009
August 27, 2009
The Custom Action is added to the Setup Project, select the Project node and hit the Custom Action button. This allows you add an Action to a particular phase in the Installation. But first you must create the Custom Action.
To Add a Custom Action you must first have a Custom Action created, this is usually in the form of a Installer Class, this should be created in a seperate project, the Installer Class is actually one of the File Templates in the C# Projects. So it's File->New Project and select Visual C# Projects. Then add a Class Library, this will prompt you for the Class Library Types , select "Installer Class".
Also here's a more comprehensive document on Setup/Installer implementations, it delves into the Registry etc
Getting Started with Setup Projects (SimpleTalk).
Create your Installer Class and then add it as a Custom Action to the Setup Project.
What happens now is that you can access the Installers data using what are called Installer Properties. How this is done is a bit messy, after you've added your Installer Class as a Custom Action to the Setup Project you must specify arguments to be passed to the Installer Class at runtime, apparantly this is the only way to references installer data after the installation has completed.
Here's an example of how to pass the name of the installation directory to the Custom Action assembly:
This is done in your Setup Project's Custom Action Tab.
Set the property of the Custom Action you have just added to
NOTE: the extra \" at the end is required to return a directory.
This tells the Custom Action dll that it can access the TARGETDIR (which is the installation location) with the InstallLoc arg, here's how it's done in the Custom Action class:
private void AfterInstallEventHandler(object sender, InstallEventArgs e)
//Copy the assemblies to the location _installationLoc
//From the command line (passed in by the Setup)
//_installationLoc is also used in the generated .targets file
_installationLoc = this.Context.Parameters["InstallLoc"];
For multiple Custom Action parameters use a single space between each parameter.
/appsetting1=[EDITA1] /appsetting2=[EDITA2] /installLoc="[TARGETDIR]\"
accessible in your Custom Action code with
_installLoc = Context.Parameters["installLoc"];
_appsetting1 = Context.Parameters["appsetting1"];//first edit
_appsetting2 = Context.Parameters["appsetting2"];//second edit
For Common Properties used in installer applications and other like TARGETDIR see
Debugging the CustomAction
Debugging the CustomAction can be tricky.
To attach the Visual Studio Debugger to the installation process, msiexec.exe is nigh on impossible. The best solution is to add a
The Debugger.Break() will force the runtime to prompt the installer to attach a Debugger this is your opportunity. Attach to a Visual Studio session that has the CustomAction project source code open and debug as normal once attached.
You may however find that the Debugger.Break() or other code you've just added to your CustomAction does not get picked up even though you've rebuilt, this has caught me out a few times, usually when I'm trying to debug the UnInstall. The usual reason is that the code the installer is using as the CustomAction is not the one you've just built. To resolve this drop the newly built assembly into the Target installation location, e.g. if your CustomAction is built to a dll named MyCustomAction.dll and you've just installed to C:\Program Files\MyCompany\MyApp then drop the newly built dll and it's pdb into here and then try to uninstall. The uninstall picks up the CustomAction from the target location (this is also why you see you CustomAction's assembly in the target installation directory after install).
InstallState, stateSaver and savedState IDictionary
In your CustomAction code you'll see an IDictionary being passed around the Install and UnInstall overrides. This IDictionary is a HashTable. Because the Install and UnInstall are 2 completely different instances the UnInstall knows nothing of member variables set in the Install, instead it relies on an IDictionary, this IDictionary uses a text file to store it's data, thsi is how the Install and the UnInstall can comunicate i.e. the actual have no communication but the Install writes to a file and later the Uninstall reads from that same file. The IDictionary contains paths to the components that the CustomAction has installed (these also get written to a file in the Target installation location which has an extension ".InstallState").
At install time the IDictionary, "stateSaver", records the component names and their paths that were installed, this gets serialized in the file "
public override void Uninstall(IDictionary savedState)
With the call to baseUninstall(stateSaved) it can uninstall all that was installed.
In the Install override you're free to add content yourself, the key can be any string really, remember the key must be unique, the value however should be a path to a file or the full path to a registry entry. The base.Uninstall(savedState) goes through each of these entries and attempts to remove them. The IDictionary can also be used to store values you'd like to explicitly uninstall yourself, remember you cannot depend on member variables you must have some persitant storage to store variables and that is this IDictionary.
Here's an example of a registry entry which was created by the CustomAction on Install and so must be deleted by the CustomAction on UnInstall
public override void Install(IDictionary stateSaver)
RegistryKey expressionEvaluatorPackageVersionKey = expressionEvaluatorInProcKey.CreateSubKey(packageVersion);
add the entry to the IDictionary with unique name for the Key and full registry path for the Value
stateSaver.Add("expressionEvaluatorPackageVersionKey" + guidString + packageVersion, expressionEvaluatorInProcKey.OpenSubKey(packageVersion).ToString());
At UnInstall pull the entry from the IDictionary and Explictly uninstall
It's unusual to have to explicitly do this, this should be done by the call to base.Uninstall(savedState).
public override void Uninstall(IDictionary savedState)
RegistryKey hKeyClassesRootCLSID = Registry.ClassesRoot.OpenSubKey("CLSID", true) as RegistryKey;
foreach (object key in savedState.Keys)
if (savedState[key] != null)
int index = savedState[key].ToString().IndexOf(@"\");
string keyStringWithoutHKEY_CLASSES_ROOT = savedState[key].ToString().Substring(index + 1);
RegistryKey expressionEvaluatorPackageVersionKey = Registry.ClassesRoot.OpenSubKey(keyStringWithoutHKEY_CLASSES_ROOT, true) as RegistryKey;
if(Registry.ClassesRoot.OpenSubKey(keyStringWithoutHKEY_CLASSES_ROOT, true) != null) Registry.ClassesRoot.DeleteSubKeyTree(keyStringWithoutHKEY_CLASSES_ROOT);
August 10, 2009
July 31, 2009
If you have problems with your installer itself and not the Custom Action then try this:You can also Log installer actions by activating the installer logging, this is done through a registry entry, http://support.microsoft.com/kb/223300. All your doing is adding a "String Value" named "Logging" and a value "voicewarmupx" to the registry entry HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\Installer
I've done this and found some useful info but it's not that easy to read, at least it tells you the command that was ran and where it got the installer from.
If you have problems with your Custom Action then try this:
In your Custom Action's code add a Debugger.Break() or a MessageBox.Show() , build your projet in Debug, launch your msi and when the messag appears you can then attach to msiexec.exe.
I've found that the Debugger.Break does not always work, the MessageBox.Show should always work, just gives you a chance to attach your debugger.
tryCommon problems with the Custom ActionCommon problems with the Custom Action are the use of the SavedState IDictionary, trying to use entries that do not exist. I recommend wrapping everthing in a try/catch and then rethrow everthing in a new InstallerException, I usually add one for each method in my Custom Action.