// 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 = null;
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
}
}