using Microsoft.VisualBasic; using System; using System.Collections; using System.Collections.Generic; using System.Data; using System.Diagnostics; using Microsoft.Win32; /// /// Represents a program that is installed on a PC /// public class InstalledProgram : IComparable, IEquatable { #region "Properties" private string _DisplayName = string.Empty; /// /// The name that would be displayed in Add/Remove Programs /// public string DisplayName { get { return _DisplayName; } set { _DisplayName = value; } } private string _Version = string.Empty; /// /// The version of the program /// public string Version { get { return _Version; } set { _Version = value; } } private string _ParentDisplayName = string.Empty; /// /// If this program is an update then this will contain the display name of the product that /// this is an update to /// public string ParentDisplayName { get { return _ParentDisplayName; } set { _ParentDisplayName = value; } } private bool _IsUpdate; /// /// Is this program classed as an update /// public bool IsUpdate { get { return _IsUpdate; } set { _IsUpdate = value; } } #endregion #region "Constructors" public InstalledProgram(string ProgramDisplayName) { this.DisplayName = ProgramDisplayName; } public InstalledProgram(string ProgramDisplayName, string ProgramParentDisplayName, bool IsProgramUpdate, string ProgramVersion) { this.DisplayName = ProgramDisplayName; this.ParentDisplayName = ProgramParentDisplayName; this.IsUpdate = IsProgramUpdate; this.Version = ProgramVersion; } #endregion #region "Public Methods" public override string ToString() { return DisplayName; } /// /// Retrieves a list of all installed programs on the local computer /// public static List GetInstalledPrograms(bool IncludeUpdates) { return InternalGetInstalledPrograms(IncludeUpdates, Registry.LocalMachine, Registry.Users); } /// /// Retrieves a list of all installed programs on the specified computer /// /// The name of the computer to get the list of installed programs from /// Determines whether or not updates for installed programs are included in the list public static List GetInstalledPrograms(string ComputerName, bool IncludeUpdates) { try { return InternalGetInstalledPrograms(IncludeUpdates, RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, ComputerName), RegistryKey.OpenRemoteBaseKey(RegistryHive.Users, ComputerName)); } catch (Exception ex) { Debug.WriteLine(ex.Message); return new List(); } } //Sorting function, required by IComparable interface public int CompareTo(InstalledProgram other) { return string.Compare(this.DisplayName, other.DisplayName); } //Equality function, required by IEquatable interface public bool Equals1(InstalledProgram other) { if (this.DisplayName == other.DisplayName && this.Version == other.Version) { return true; } else { return false; } } bool System.IEquatable.Equals(InstalledProgram other) { return Equals1(other); } #endregion #region "Private Methods" private static List InternalGetInstalledPrograms(bool IncludeUpdates, RegistryKey HklmPath, RegistryKey HkuPath) { List ProgramList = new List(); RegistryKey ClassesKey = HklmPath.OpenSubKey("Software\\Classes\\Installer\\Products"); //---Wow64 Uninstall key RegistryKey Wow64UninstallKey = HklmPath.OpenSubKey("Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall"); ProgramList = GetUninstallKeyPrograms(Wow64UninstallKey, ClassesKey, ProgramList, IncludeUpdates); //---Standard Uninstall key RegistryKey StdUninstallKey = HklmPath.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall"); ProgramList = GetUninstallKeyPrograms(StdUninstallKey, ClassesKey, ProgramList, IncludeUpdates); foreach (string UserSid in HkuPath.GetSubKeyNames()) { //---HKU Uninstall key RegistryKey CuUnInstallKey = HkuPath.OpenSubKey(UserSid + "\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall"); ProgramList = GetUninstallKeyPrograms(CuUnInstallKey, ClassesKey, ProgramList, IncludeUpdates); //---HKU Installer key RegistryKey CuInstallerKey = HkuPath.OpenSubKey(UserSid + "\\Software\\Microsoft\\Installer\\Products"); ProgramList = GetUserInstallerKeyPrograms(CuInstallerKey, HklmPath, ProgramList); } //Close the registry keys try { HklmPath.Close(); HkuPath.Close(); } catch (Exception ex) { Debug.WriteLine("Error closing registry key - " + ex.Message); } //Sort the list alphabetically and return it to the caller //ProgramList.Sort(); return ProgramList; } private static bool IsProgramInList(string ProgramName, List ListToCheck) { return ListToCheck.Contains(new InstalledProgram(ProgramName)); } private static List GetUserInstallerKeyPrograms(RegistryKey CuInstallerKey, RegistryKey HklmRootKey, List ExistingProgramList) { if ((CuInstallerKey != null)) { foreach (string CuProductGuid in CuInstallerKey.GetSubKeyNames()) { bool ProductFound = false; foreach (string UserDataKeyName in HklmRootKey.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData").GetSubKeyNames()) { //Ignore the LocalSystem account if (!(UserDataKeyName == "S-1-5-18")) { RegistryKey ProductsKey = HklmRootKey.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\" + UserDataKeyName + "\\Products"); if ((ProductsKey != null)) { string[] LmProductGuids = ProductsKey.GetSubKeyNames(); foreach (string LmProductGuid in LmProductGuids) { if (LmProductGuid == CuProductGuid) { RegistryKey UserDataProgramKey = HklmRootKey.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\" + UserDataKeyName + "\\Products\\" + LmProductGuid + "\\InstallProperties"); if (!(Convert.ToInt32(UserDataProgramKey.GetValue("SystemComponent", 0)) == 1)) { string Name = Convert.ToString(CuInstallerKey.OpenSubKey(CuProductGuid).GetValue("ProductName", string.Empty)); string ProgVersion = string.Empty; try { ProgVersion = Convert.ToString(UserDataProgramKey.GetValue("DisplayVersion", string.Empty)); } catch (Exception ex) { Debug.WriteLine(ex.Message); } if (!(Name == string.Empty) && !IsProgramInList(Name, ExistingProgramList)) { ExistingProgramList.Add(new InstalledProgram(Name)); ProductFound = true; } } break; // TODO: might not be correct. Was : Exit For } } if (ProductFound) { break; // TODO: might not be correct. Was : Exit For } try { ProductsKey.Close(); } catch (Exception ex) { Debug.WriteLine(ex.Message); } } } } } } return ExistingProgramList; } private static List GetUninstallKeyPrograms(RegistryKey UninstallKey, RegistryKey ClassesKey, List ExistingProgramList, bool IncludeUpdates) { //Make sure the key exists if ((UninstallKey != null)) { //Loop through all subkeys (each one represents an installed program) foreach (string SubKeyName in UninstallKey.GetSubKeyNames()) { try { RegistryKey CurrentSubKey = UninstallKey.OpenSubKey(SubKeyName); //Skip this program if the SystemComponent flag is set int IsSystemComponent = 0; bool ErrorCheckingSystemComponent = false; try { IsSystemComponent = Convert.ToInt32(CurrentSubKey.GetValue("SystemComponent", 0)); } catch (Exception ex) { Debug.WriteLine(SubKeyName + " - " + ex.Message); } if (!(IsSystemComponent == 1)) { //If the WindowsInstaller flag is set then add the key name to our list of Windows Installer GUIDs if (!(Convert.ToInt32(CurrentSubKey.GetValue("WindowsInstaller", 0)) == 1)) { System.Text.RegularExpressions.Regex WindowsUpdateRegEx = new System.Text.RegularExpressions.Regex("KB[0-9]{6}$"); string ProgramReleaseType = Convert.ToString(CurrentSubKey.GetValue("ReleaseType", string.Empty)); string ProgVersion = string.Empty; try { ProgVersion = Convert.ToString(CurrentSubKey.GetValue("DisplayVersion", string.Empty)); } catch (Exception ex) { Debug.WriteLine(SubKeyName + " - " + ex.Message); } //Check to see if this program is classed as an update if (WindowsUpdateRegEx.Match(SubKeyName).Success == true || !(Convert.ToString(CurrentSubKey.GetValue("ParentKeyName", string.Empty)) == string.Empty) || ProgramReleaseType == "Security Update" || ProgramReleaseType == "Update Rollup" || ProgramReleaseType == "Hotfix") { if (IncludeUpdates) { //Add the program to our list if we are including updates in this search string Name = Convert.ToString(CurrentSubKey.GetValue("DisplayName", string.Empty)); if (!(Name == string.Empty) && !IsProgramInList(Name, ExistingProgramList)) { ExistingProgramList.Add(new InstalledProgram(Name, Convert.ToString(CurrentSubKey.GetValue("ParentDisplayName", string.Empty)), true, ProgVersion)); } } //If not classed as an update } else { bool UninstallStringExists = false; foreach (string valuename in CurrentSubKey.GetValueNames()) { if (string.Compare("UninstallString", valuename, true) == 0) { UninstallStringExists = true; break; // TODO: might not be correct. Was : Exit For } } if (UninstallStringExists) { string Name = Convert.ToString(CurrentSubKey.GetValue("DisplayName", string.Empty)); if (!(Name == string.Empty) && !IsProgramInList(Name, ExistingProgramList)) { ExistingProgramList.Add(new InstalledProgram(Name, Convert.ToString(CurrentSubKey.GetValue("ParentDisplayName", string.Empty)), false, ProgVersion)); } } } //If WindowsInstaller } else { string ProgVersion = string.Empty; string Name = string.Empty; bool FoundName = false; try { string MsiKeyName = GetInstallerKeyNameFromGuid(SubKeyName); RegistryKey CrGuidKey = ClassesKey.OpenSubKey(MsiKeyName); if ((CrGuidKey != null)) { Name = Convert.ToString(CrGuidKey.GetValue("ProductName", string.Empty)); } } catch (Exception ex) { Debug.WriteLine(SubKeyName + " - " + ex.Message); } try { ProgVersion = Convert.ToString(CurrentSubKey.GetValue("DisplayVersion", string.Empty)); } catch (Exception ex) { Debug.WriteLine(ex.Message); } if (!(Name == string.Empty) && !IsProgramInList(Name, ExistingProgramList)) { ExistingProgramList.Add(new InstalledProgram(Name, Convert.ToString(CurrentSubKey.GetValue("ParentDisplayName", string.Empty)), false, ProgVersion)); } } } } catch (Exception ex) { Debug.WriteLine(SubKeyName + " - " + ex.Message); } } //Close the registry key try { UninstallKey.Close(); } catch (Exception ex) { Debug.WriteLine(ex.Message); } } return ExistingProgramList; } private static string GetInstallerKeyNameFromGuid(string GuidName) { string[] MsiNameParts = GuidName.Replace("{", "").Replace("}", "").Split('-'); System.Text.StringBuilder MsiName = new System.Text.StringBuilder(); //Just reverse the first 3 parts for (int i = 0; i <= 2; i++) { MsiName.Append(ReverseString(MsiNameParts[i])); } //For the last 2 parts, reverse each character pair for (int j = 3; j <= 4; j++) { for (int i = 0; i <= MsiNameParts[j].Length - 1; i++) { MsiName.Append(MsiNameParts[j][i + 1]); MsiName.Append(MsiNameParts[j][i]); i += 1; } } return MsiName.ToString(); } private static string ReverseString(string input) { char[] Chars = input.ToCharArray(); Array.Reverse(Chars); return new string(Chars); } #endregion }