// SoftwarePackage.cs // // Copyright (C) 2003-2004 Ryan Seghers // // This software is provided AS IS. No warranty is granted, // neither expressed nor implied. USE THIS SOFTWARE AT YOUR OWN RISK. // NO REPRESENTATION OF MERCHANTABILITY or FITNESS FOR ANY // PURPOSE is given. // // License to use this software is limited by the following terms: // 1) This code may be used in any program, including programs developed // for commercial purposes, provided that this notice is included verbatim. // // Also, in return for using this code, please attempt to make your fixes and // updates available in some way, such as by sending your updates to the // author. // using System; using System.CodeDom.Compiler; using System.Collections; using System.Diagnostics; using Microsoft.Win32; namespace RTools_NTS.Util { /// /// This class represents an installed software package on a Windows /// system. This has some static utility methods that will get the /// list of installed software packages, letting you uninstall one. /// /// /// This is motivated by the desire to get the version of an installed /// package, and by the fact that I wasn't able to find an easier way to /// uninstall an Msi by product name (msiexec needs the product code). /// /// /// This looks for uninstallable packages in the registry in: /// HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall /// /// public class SoftwarePackage { #region main Instance Methods /// /// Uninstall this setup. /// /// Whether or not to use the interactive /// interface. /// bool - true for success, false for failure public bool Uninstall(bool interactive) { Process p; ProcessStartInfo psi = null; // build process start info string cmdLine; if (uninstallString == string.Empty) { // no specific uninstall string, use mine if (ProductCode == String.Empty) { return (false); } cmdLine = "/x" + ProductCode + (interactive ? " /qf" : " /qb"); psi = new ProcessStartInfo("msiexec.exe", cmdLine); } else if (uninstallString.ToLower().IndexOf("msiexec") >= 0) { // it's an msiexec command, try to enact the interactive spec if (ProductCode == String.Empty) { cmdLine = uninstallString; } else { cmdLine = "/x" + ProductCode + (interactive ? " /qf" : " /qb"); psi = new ProcessStartInfo("msiexec.exe", cmdLine); } } else { cmdLine = uninstallString; } // execute if (psi != null) { // Process endCapStyle p = new Process(); p.StartInfo = psi; p.Start(); int timeoutMs = 2*60*1000; if (interactive) { timeoutMs = Int32.MaxValue; } p.WaitForExit(timeoutMs); return (p.ExitCode == 0); //return(true); } else { // Executor endCapStyle for arbitrary command line TempFileCollection tmpFiles = new TempFileCollection(".", false); Executor.ExecWait(cmdLine, tmpFiles); return (true); } } #endregion #region Standard Methods /// /// ToString override. /// /// public override string ToString() { return (Name + ", " + DisplayVersion + ", uninstallable: " + IsUninstallable); } #endregion #region Fields private string uninstallString; #endregion #region Properties /// Product name. public string Name { get; set; } /// Product Code. public string ProductCode { get; set; } /// Uninstall string (a shell command to use to remove this SoftwarePackage). public string UninstallString { get { if (uninstallString != string.Empty) { return (uninstallString); } else if (ProductCode != string.Empty) { return ("msiexec.exe /I" + ProductCode); } else { return (string.Empty); } } set { uninstallString = value; } } /// The DisplayVersion for this SoftwarePackage. public string DisplayVersion { get; set; } /// Whether or not this SoftwarePackage is uninstallable (by this class). public bool IsUninstallable { get { if ((UninstallString != string.Empty) || (ProductCode != string.Empty)) { return (true); } else { return (false); } } } #endregion #region Constructors /// /// Default constructor. /// public SoftwarePackage() { Name = string.Empty; ProductCode = string.Empty; uninstallString = string.Empty; DisplayVersion = string.Empty; } /// /// Constructor which sets all values. /// /// The product name. /// The ProductCode. /// The uninstall string. /// The display version. public SoftwarePackage(string name, string productCode, string uninstallString, string displayVersion) { if (name != null) { Name = name; } else { Name = string.Empty; } if (productCode != null) { ProductCode = productCode; } else { ProductCode = string.Empty; } if (uninstallString != null) { this.uninstallString = uninstallString; } else { this.uninstallString = string.Empty; } if (displayVersion != null) { DisplayVersion = displayVersion; } else { DisplayVersion = string.Empty; } } #endregion #region Static Utility Methods /// /// This returns an array of potentially unstallable SoftwarePackages. /// See SoftwarePackage.IsUninstallable to see whether this class /// can uninstall a particular SoftwarePackage. /// /// The SoftwarePackage[], null for error. public static SoftwarePackage[] GetList() { // // registry access // string uninstallKey = @"Software\Microsoft\Windows\CurrentVersion\Uninstall"; RegistryKey key = Registry.LocalMachine.OpenSubKey(uninstallKey); if (key == null) { return null; } // list them ArrayList list = new ArrayList(); string[] subkeyNames = key.GetSubKeyNames(); foreach (string subkey in subkeyNames) { RegistryKey sk = key.OpenSubKey(subkey); string prodName; string uninstallString = (string) sk.GetValue("UninstallString"); string displayVersion = (string) sk.GetValue("DisplayVersion"); string productCode = string.Empty; if (subkey[0] == '{') { // product code entry productCode = subkey; prodName = (string) sk.GetValue("DisplayName"); if (prodName == null) { prodName = string.Empty; } } else { // entry by name prodName = subkey; } list.Add(new SoftwarePackage(prodName, productCode, uninstallString, displayVersion)); } return ((SoftwarePackage[]) list.ToArray(typeof(SoftwarePackage))); } /// /// Get a particular software package, by product name. This returns /// the first package found with the specified product name. /// /// The product name of the package to /// get. /// SoftwarePackage public static SoftwarePackage GetPackage(string productName) { SoftwarePackage[] setups = GetList(); foreach (SoftwarePackage s in setups) { if (s.Name.Equals(productName)) { return (s); } } return (null); } /// /// This returns the requested SoftwarePackage only if it only appears /// exactly once (as determined solely by name) in the input SoftwarePackage /// array. /// /// The product name to look for. /// The array of SoftwarePackages to search. /// The SoftwarePackage found, or null for none found or more /// than one found. public static SoftwarePackage FindOne(string name, SoftwarePackage[] list) { SoftwarePackage setup = null; foreach (SoftwarePackage s in list) { if (s.Name.Equals(name)) { if (setup != null) { return (null); } setup = s; } } return (setup); } /// /// Uninstall all uninstallable packages with the specified product name. /// /// The product name of the packages to /// uninstall. /// Whether to run Msiexec in interactive mode /// or not. /// bool - true for 1 or more found and uninstalled, false /// otherwise. public static bool UninstallMultiple(string productName, bool interactive) { SoftwarePackage[] setups = GetList(); foreach (SoftwarePackage s in setups) { if (s.Name.Equals(productName) && s.IsUninstallable) { if (!s.Uninstall(interactive)) { return (false); } } } return (true); } #endregion } }