web-dev-qa-db-ja.com

C#:コントロールパネルのプログラムや機能とまったく同じようにプログラムをインストールする方法は?

プログラムの入手に関する情報をたくさん読みました。どのアルゴリズムも私が望むことをしませんでした。私はインストールされたプログラムを取得する必要があります正確にコントロールパネルのように。

だから私は使用しました:

  1. WMI Win32_Productクラス。 msiがインストールされているプログラムのみが表示されます。
  2. レジストリキー。 HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall。繰り返しますが、一部のプログラムはコントロールパネルに表示されません。一部のプログラムは、このレジストリノードにないコントロールパネルに表示されます。

では、この世界で、インストールされているプログラムを表示するためにコントロールパネルを使用するアルゴリズムを知っている人はいますか?

UPD1:はい、64ビットを使用しています。64ビットのインストール済みプログラム「HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall」に別のノードがあることはわかっていますが、次のコードはHKLM\SOFTWARE\Wow6432Node\Microsoft\Windows \を列挙していますCurrentVersion\Uninstallセクション、奇妙な...

var programs = new List(); 
 string Registry_key = @ "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"; 
 using(Microsoft.Win32.RegistryKey key = Registry.LocalMachine.OpenSubKey(registry_key ))
 {
 foreach(string subkey_name in key.GetSubKeyNames())
 {
 using(RegistryKey subkey = key.OpenSubKey(subkey_name))
 {
 var name =(string)subkey.GetValue( "DisplayName"); 
 if(!string.IsNullOrEmpty(name))
 {
プログラム.Add(name); 
} 
} 
} 
} 
 
 registry_key = @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall";
using (Microsoft.Win32.RegistryKey key = Registry.LocalMachine.OpenSubKey(registry_key))
{
    foreach (string subkey_name in key.GetSubKeyNames())
    {
        using (RegistryKey subkey = key.OpenSubKey(subkey_name))
        {
            var name = (string)subkey.GetValue("DisplayName");
            if (!string.IsNullOrEmpty(name))
            {
                programs.Add(name);
            }
        }
    }
}

foreach (var program in programs.OrderBy(x => x))
{
    Console.WriteLine(program);
}
17
MelnikovI

OK gyus、ホットフィックスやアップデートなしでレジストリからインストール済みプログラムを取得できるクラスを作成しました。それはまだ正確にはコントロールパネルのようですがほぼです。これが他の誰かに役立つことを願っています。

 public static class InstalledPrograms 
 {
 const string Registry_key = @ "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"; 
 
     public static List<string> GetInstalledPrograms()
    {
        var result = new List<string>();
        result.AddRange(GetInstalledProgramsFromRegistry(RegistryView.Registry32));
        result.AddRange(GetInstalledProgramsFromRegistry(RegistryView.Registry64));
        return result;
    } 

    private static IEnumerable<string> GetInstalledProgramsFromRegistry(RegistryView registryView)
    {
        var result = new List<string>();

        using (RegistryKey key = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, registryView).OpenSubKey(registry_key))
        {
            foreach (string subkey_name in key.GetSubKeyNames())
            {
                using (RegistryKey subkey = key.OpenSubKey(subkey_name))
                {
                    if(IsProgramVisible(subkey))
                    {
                        result.Add((string)subkey.GetValue("DisplayName"));
                    }
                }
            }
        }

        return result;
    }

    private static bool IsProgramVisible(RegistryKey subkey)
    {
        var name = (string)subkey.GetValue("DisplayName");
        var releaseType = (string)subkey.GetValue("ReleaseType");
        //var unistallString = (string)subkey.GetValue("UninstallString");
        var systemComponent = subkey.GetValue("SystemComponent");
        var parentName = (string)subkey.GetValue("ParentDisplayName");

        return
            !string.IsNullOrEmpty(name)
            && string.IsNullOrEmpty(releaseType)
            && string.IsNullOrEmpty(parentName)
            && (systemComponent == null);
    }
}
28
MelnikovI

MelnikovIの答えは、ほとんどの目的に十分です。リストには144個のアイテムがありましたが、プログラムと機能には143個ありました。 レビュー用、彼の解決策はこれらのレジストリの場所をヒットすることです:

  • HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall
  • HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall
  • HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall

資格を得るには、各サブキーに次のものが必要です。

  • DisplayNameREG_SZ値

そして持ってはいけません:

  • SystemComponent REG_DWORD(ゼロ以外)
  • ParentKeyNameまたはParentDisplayNameREG_SZ値
  • ReleaseTypeREG_SZ値

1つの追加の機能強化私が見つけたのはWindowsインストーラーエントリ用で、次のように定義されています。

  • キー名は標準ですGUID string
  • WindowsInstaller REG_DWORDが存在します(ゼロ以外)

このようなエントリの場合、Win32関数MsiGetProductInfoW from msi.dllを使用し、GUID。

この関数が1605:ERROR_UNKNOWN_PRODUCTを返す場合は、エントリがWindowsインストーラに従ってインストールされていないため、表示から除外する必要があることを意味します。

このマイナーな調整を実装した後、私のリストはプログラムと機能と同じになりました。

3
Mike

MelnikovIが書いたコード(非常に役に立ちました)を取り、いくつか追加しました。まず、レジストリ内の4つの場所を検索します。

HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall

HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall

HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall

HKCU\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall

また、サブキーがあるかどうかを確認します。ない場合は、サブキーをスキップします。

最後に、特定の文字セット[^ a-zA-Z0-9。()+-]のみを許可する正規表現を実行します。

私はC#から始めているだけなので、4つのregの場所すべてをループする方法がわからなかったので、2つのループがあります(1つはHKLM用、もう1つはHKCU用)。

public static class InstalledPrograms
    {
      public static List<string> GetInstalledPrograms()
        {
            var result = new List<string>();
            result.AddRange(GetInstalledProgramsFromRegistry(RegistryView.Registry32));
            result.AddRange(GetInstalledProgramsFromRegistry(RegistryView.Registry64));
            result.Sort();
            return result;
        }
        private static string cleanText(string dirtyText)
        {
            Regex rgx = new Regex("[^a-zA-Z0-9 .()+-]");
            string result = rgx.Replace(dirtyText, "");
            return result;
        }
        private static IEnumerable<string> GetInstalledProgramsFromRegistry(RegistryView registryView)
        {
            var result = new List<string>();
            List<string> uninstall = new List<string>();
            uninstall.Add(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall");
            uninstall.Add(@"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall");
            foreach (string registry_key in uninstall)
            {
               using (RegistryKey key = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, registryView).OpenSubKey(registry_key))
               {
                    foreach (string subkey_name in key.GetSubKeyNames())
                    {
                        using (RegistryKey subkey = key.OpenSubKey(subkey_name))
                        {
                            if (IsProgramVisible(subkey))
                            {
                                result.Add(cleanText(subkey.GetValue("DisplayName").ToString()).ToString());
                            }
                        }
                    }
                }
                using (RegistryKey key = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, registryView).OpenSubKey(registry_key))
                {
                    if (key != null)
                    {
                        foreach (string subkey_name in key.GetSubKeyNames())
                        {
                            using (RegistryKey subkey = key.OpenSubKey(subkey_name))
                            {
                                if (IsProgramVisible(subkey))
                                {
                                    result.Add(cleanText(subkey.GetValue("DisplayName").ToString()).ToString());
                                }
                            }
                        }
                    }
                }
            }

            return result;
        }

誰かが興味を持っているなら、私は結果を私が使っていたPowerShellと比較しました、そしてそれらは同じです。

##Get list of Add/Remove programs
if (!([Diagnostics.Process]::GetCurrentProcess().Path -match '\\syswow64\\'))
{
$uninstallPath = "\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\"
$uninstallWow6432Path = "\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\"
@(
if (Test-Path "HKLM:$uninstallWow6432Path" ) { Get-ChildItem "HKLM:$uninstallWow6432Path"}
if (Test-Path "HKLM:$uninstallPath" ) { Get-ChildItem "HKLM:$uninstallPath" }
if (Test-Path "HKCU:$uninstallWow6432Path") { Get-ChildItem "HKCU:$uninstallWow6432Path"}
if (Test-Path "HKCU:$uninstallPath" ) { Get-ChildItem "HKCU:$uninstallPath" }
) |
ForEach-Object { Get-ItemProperty $_.PSPath } |
Where-Object {
$_.DisplayName -and !$_.SystemComponent -and !$_.ReleaseType -and !$_.ParentKeyName -and ($_.UninstallString -or $_.NoRemove)
} |
Sort-Object DisplayName |
Select-Object DisplayName
}
else
{
"You are running 32-bit Powershell on 64-bit system. Please run 64-bit Powershell instead." | Write-Host -ForegroundColor Red
}
2
John

ここで他のいくつかの回答で説明されているSystemComponentレジストリキーは通常 0または1の可能な値を持つREG_DWORDです。ただし、いくつかのインスタンス(Microsoft Visio2010やMicrosoftProject 2010など)を見てきました。 SystemComponentは、データのないREG_SZです。したがって、SystemComponentをintにキャストするソリューションは、これらの状況で例外をスローする傾向があります。

0
Vincent