Search code examples
c#setup-projectcustom-actionuninstallation

Is it possible to access a variable in the Uninstall() proc that tells you the install directory?


I have a setup project that installs my service, gui, and a few other files. It installs them and creates the service and everything looks great! When the service runs, it creates a few text files and those text files stay in the install folder.

My question revolves around the uninstallation of the service/app. When I go to uninstall it does everything as expected but ends up leaving the program directory because the newly created text files that are still in there.

Is it possible to somehow get the original install path of the service and application when the Uninstall() proc gets fired up?

EX:

//Code to perform at the time of uninstalling application 
public override void Uninstall(System.Collections.IDictionary savedState)
{
    base.Uninstall(savedState);

    try
    {
        //This is the variable I want to NOT be a static set hardcoded path...
        string baseFolder = @"C:\Program Files (x86)\MyProgram\";

        string[] allFileNames = System.IO.Directory.GetFiles(baseFolder, "*.*", System.IO.SearchOption.AllDirectories);
        foreach (string filename in allFileNames)
        {
            FileAttributes attr = File.GetAttributes(filename);
            File.SetAttributes(filename, attr & ~FileAttributes.ReadOnly);
        }

        System.IO.Directory.Delete(baseFolder, true);
    }
    catch (Exception)
    {
        //throw;
    }
}

Solution

  • Answer: YES! Just use the SaveState property and pass it along in the chain of the install process thread...

    Solution: Add an "Installer Class" file to your project, in this example it's called "InstallerActions.cs".

    [RunInstaller(true)]
    public partial class InstallerActions : System.Configuration.Install.Installer
    {
        public InstallerActions()
        {
            InitializeComponent();
        }
    
        //Code to perform at the time of installing application
        public override void Install(System.Collections.IDictionary stateSaver)
        {
            //if (Debugger.IsAttached == false) Debugger.Launch();
    
            CustomParameters cParams = new CustomParameters();
            cParams.Add("InstallPath", this.Context.Parameters["targetdir"]);
            cParams.SaveState(stateSaver);
    
            //Continue with install process
            base.Install(stateSaver);
        }
    
        //Code to perform at the time of uninstalling application 
        public override void Uninstall(System.Collections.IDictionary savedState)
        {
            //if (Debugger.IsAttached == false) Debugger.Launch();
    
            CustomParameters cParams = new CustomParameters(savedState);
            string sBase = cParams.GetValue("InstallPath");
    
            //Continue with uninstall process
            base.Uninstall(savedState);
    
            try
            {
                //Delete all files in the base folder recursively except service or exe files
                string[] files = System.IO.Directory.GetFiles(sBase, "*.*", System.IO.SearchOption.AllDirectories);
                foreach (string f in files)
                {
                    //Check the extention of the filename first
                    string sExt = Path.GetExtension(f).ToLower();
                    if (sExt != ".installstate" && sExt != ".exe")
                    {
                        FileAttributes attr = File.GetAttributes(f);
                        File.SetAttributes(f, attr & ~FileAttributes.ReadOnly);
                        System.IO.File.Delete(f);
                    }
                }
    
                //This would delete the base install directory but
                //the installer will do this instead, I just need to
                //clean up everything I made other the the exe's and
                //service files
                //System.IO.Directory.Delete(sBase, true);
            }
            catch
            {
                //Error, just ignore it
            }
        }
    }
    

    Create another class called "CustomParameters.cs"

    public class CustomParameters
    {
        //Private variables
        private Dictionary<string, string> dParams;
    
        //Constructor
        public CustomParameters()
        {
            //Reset the dictionary
            dParams = new Dictionary<string, string>();
        }
        public CustomParameters(IDictionary savedState)
        {
            string sKey = "";
            string sValue = "";
    
            //Import saved state data
            if (dParams == null) dParams = new Dictionary<string, string>();
    
            foreach (var entry in (dynamic)savedState)
            {
                object dKey = entry.Key;
                object dValue = entry.Value;
    
                switch (dKey.GetType().ToString())
                {
                    case "System.String":
                        //Save the key
                        sKey = (string)dKey;
    
                        switch (dValue.GetType().ToString())
                        {
                            case "System.String":
                                //Save the string value
                                sValue = (string)dValue;
    
                                break;
                            case "System.Int32":
                                //Save the int value
                                sValue = ((int)dValue).ToString();
    
                                break;
                        }
    
                        break;
                }
    
                //Save the keypair to the global dictionary
                dParams.Add(sKey, sValue);
            }
        }
    
        //Public functions
        public void Add(string sParameterKey, string sParameterValue)
        {
            if (dParams == null) return;
    
            //Add or update the key
            dParams[sParameterKey] = sParameterValue;
        }
        public void Delete(string sParameterKey)
        {
            if (dParams == null) return;
    
            //Delete the key if it exists
            if (dParams.ContainsKey(sParameterKey))
            {
                dParams.Remove(sParameterKey);
            }
        }
        public void SaveState(IDictionary savedState)
        {
            if (dParams == null) return;
    
            foreach (KeyValuePair<string, string> param in dParams)
            {
                if (savedState.Contains(param.Key) == true)
                    savedState[param.Key] = param.Value;
                else
                    savedState.Add(param.Key, param.Value);
            }
        }
        public string GetValue(string sKey)
        {
            if (dParams.ContainsKey(sKey))
            {
                return dParams[sKey].ToString();
            }
            else
            {
                return "";
            }
        }
    }