The Problem

The other day, I was working on update / patch / setup patterns and stuff, when I noticed in the Windows Registry that the InstallLocation of my installed application was empty. You can find info on installed applications in the Windows Registry by typing “regedit” in the Run command and browsing to: “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\”.

Apparently, it is a known bug. So, we’ll have to fix it ourselves!

The “quick” way

On the internet, you can find various posts about manipulating your generated msi. You can find an example here. But I don’t want to do the manipulation thingies.

Installer Custom Actions

If you are not familiar with Custom Actions in an Visual Studio Setup project, you can find some info on the MSDN website.

To use Custom Actions in a Setup project, we need to create a class library that contains our logic. So create a class library, delete the generated class1 file and add an installer class. Add the following methods to your installer class:

        public override void Install(IDictionary stateSaver)

            stateSaver.Add("TargetDir", Context.Parameters["DP_TargetDir"].ToString());
            stateSaver.Add("ProductID", Context.Parameters["DP_ProductID"].ToString());

        public override void Commit(IDictionary savedState)

            string productId = savedState["ProductID"].ToString();
            RegistryKey applicationRegistry = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\" + productId, true);

            if (applicationRegistry != null)
                applicationRegistry.SetValue("InstallLocation", savedState["TargetDir"].ToString());

That’s all you have to do in the class library.

Next, go to your setup project. We need to add the class library dll to our setup project. Right click on the project > Add > Project output. In the dialog select the class library as your “Project”, select “Primary Output” and Configuration: “Release any CPU”.

Now, we need to hook up our logic to the installer events. Right click on the setup project > View > Custom Actions. We only need two events. “Install” to save our parameters and “Commit” to write into the registry after a succesful installation. Right click on Install > Add Custom Action, go into the Application Folder and select your class library primary output. Do the same for Commit.

The final step is supplying variables to our logic. Select your primary output under the Install event and in your Properties window, you will find a CustomActionData property. Give it the following value:

/DP_TargetDir="[TARGETDIR]\" /DP_ProductID="[ProductCode]"

Rebuild your setup project and install it. If you check the registry again, the InstallLocation will be filled in.