[c#] 시스템에 설치된 애플리케이션 가져 오기

C # 코드를 사용하여 시스템에 애플리케이션을 설치하는 방법은 무엇입니까?



답변

레지스트리 키 “SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ Uninstall”을 반복하면 설치된 응용 프로그램의 전체 목록이 제공되는 것 같습니다.

아래 예제를 제외하고 여기에서 수행 한 것과 유사한 버전을 찾을 수 있습니다 .

이것은 대략적인 예입니다. 제공된 두 번째 링크에서와 같이 빈 행을 제거하기 위해 무언가를하고 싶을 것입니다.

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))
        {
            Console.WriteLine(subkey.GetValue("DisplayName"));
        }
    }
}

또는 앞서 언급 한대로 WMI를 사용할 수 있습니다.

ManagementObjectSearcher mos = new ManagementObjectSearcher("SELECT * FROM Win32_Product");
foreach(ManagementObject mo in mos.Get())
{
    Console.WriteLine(mo["Name"]);
}

그러나 이것은 실행 속도가 다소 느리고 “ALLUSERS”아래에 설치된 프로그램 만 나열 될 수 있다고 들었습니다. 비록 정확하지 않을 수 있습니다. 또한 편리 할 수있는 Windows 구성 요소 및 업데이트를 무시합니다.


답변

이 기사를 볼 수 있습니다 . 설치된 응용 프로그램 목록을 읽기 위해 레지스트리를 사용합니다.

public void GetInstalledApps()
{
    string uninstallKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
    using (RegistryKey rk = Registry.LocalMachine.OpenSubKey(uninstallKey))
    {
        foreach (string skName in rk.GetSubKeyNames())
        {
            using (RegistryKey sk = rk.OpenSubKey(skName))
            {
                try
                {
                    lstInstalled.Items.Add(sk.GetValue("DisplayName"));
                }
                catch (Exception ex)
                { }
            }
        }
    }
}


답변

레지스트리 키를 통해 열거하는 것이 가장 좋은 방법이라는 데 동의합니다.

참고 하지만, 키가 주어진 것을 @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", 윈도우 64 비트 설치의 모든 32 비트 Windows 설치에서 응용 프로그램 및 64 비트 응용 프로그램을 나열합니다.

Windows 64 비트 설치에 설치된 32 비트 애플리케이션도 보려면 키를 열거해야합니다 @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall".


답변

시작 메뉴에 나타나는대로 앱 목록을 추출 할 수 있기를 원했습니다. 레지스트리를 사용하여 시작 메뉴에 표시되지 않는 항목을 가져 왔습니다.

또한 exe 경로를 찾고 아이콘을 추출하여 멋진 런처를 만들고 싶었습니다. 불행히도 레지스트리 방법을 사용하면이 정보를 안정적으로 사용할 수 없다는 것이 관찰 되었기 때문에 이것은 일종의 히트 앤 미스입니다.

내 대안은 shell : AppsFolder를 기반으로하며 실행 explorer.exe shell:appsFolder하여 액세스 할 수 있으며 현재 설치되어 시작 메뉴를 통해 사용 가능한 스토어 앱을 포함한 모든 앱을 나열합니다. 문제는이 폴더가 .NET으로 액세스 할 수없는 가상 폴더라는 것입니다 System.IO.Directory. 대신 기본 shell32 명령을 사용해야합니다. 다행히 Microsoft 는 앞서 언급 한 명령의 래퍼 인 Nuget에 Microsoft.WindowsAPICodePack-Shell 을 게시했습니다 . 충분히 말하면 다음은 코드입니다.

// GUID taken from https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid
var FOLDERID_AppsFolder = new Guid("{1e87508d-89c2-42f0-8a7e-645a0f50ca58}");
ShellObject appsFolder = (ShellObject)KnownFolderHelper.FromKnownFolderId(FOLDERID_AppsFolder);

foreach (var app in (IKnownFolder)appsFolder)
{
    // The friendly app name
    string name = app.Name;
    // The ParsingName property is the AppUserModelID
    string appUserModelID = app.ParsingName; // or app.Properties.System.AppUserModel.ID
    // You can even get the Jumbo icon in one shot
    ImageSource icon =  app.Thumbnail.ExtraLargeBitmapSource;
}

그리고 그게 전부입니다. 다음을 사용하여 앱을 시작할 수도 있습니다.

System.Diagnostics.Process.Start("explorer.exe", @" shell:appsFolder\" + appModelUserID);

이는 일반 Win32 앱 및 UWP 스토어 앱에서 작동합니다. 사과는 어때요?

설치된 모든 앱을 나열하는 데 관심이 있으므로 다음을 사용하여 수행 할 수있는 새 앱 또는 제거 된 앱도 모니터링 할 수 있습니다 ShellObjectWatcher.

ShellObjectWatcher sow = new ShellObjectWatcher(appsFolder, false);
sow.AllEvents += (s, e) => DoWhatever();
sow.Start();

편집 : 위에 언급 된 AppUserMoedlID가 Windows가 작업 표시 줄에서 창을 그룹화하는 데 사용 하는 고유 ID 라는 사실을 알고 싶을 수도 있습니다 .


답변

Win32_Product WMI 클래스는 Windows Installer에 의해 설치되는 제품을 나타냅니다 . 모든 응용 프로그램이 Windows 설치 프로그램을 사용하는 것은 아닙니다.

그러나 “SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ Uninstall”은 32 비트 용 응용 프로그램을 나타냅니다. 64 비트의 경우 “HKEY_LOCAL_MACHINE \ SOFTWARE \ Wow6432Node \ Microsoft \ Windows \ CurrentVersion \ Uninstall”을 통과해야합니다. 모든 소프트웨어에 64 비트 버전이있는 것은 아니기 때문에 설치된 전체 응용 프로그램은 “UninstallString”이있는 두 위치에서 키의 합집합입니다. 그들과 함께 가치.

그러나 최상의 옵션은 동일한 .traverse 레지스트리 키로 유지되는 것이 좋습니다. 모든 응용 프로그램이 레지스트리에 항목 (Windows Installer의 항목 포함)이 있기 때문에 더 나은 방법입니다. 그러나 레지스트리 방법은 마치 누군가가 해당 키를 제거하는 것처럼 안전하지 않습니다. 반대로 HKEY_Classes_ROOT \ Installers를 변경하는 것은 Microsoft Office 또는 기타 제품과 같은 라이선스 문제와 관련되어 있기 때문에 더 까다 롭습니다. 보다 강력한 솔루션을 위해 언제든지 레지스트리 대안을 WMI와 결합 할 수 있습니다.


답변

허용되는 솔루션이 작동하지만 완전하지는 않습니다. 지금까지.

모든 키를 얻으려면 다음 두 가지를 더 고려해야합니다.

x86 및 x64 응용 프로그램은 동일한 레지스트리에 액세스 할 수 없습니다. 기본적으로 x86은 일반적으로 x64 레지스트리에 액세스 할 수 없습니다. 일부 응용 프로그램은 x64 레지스트리에만 등록됩니다.

일부 응용 프로그램은 실제로 LocalMachine 대신 CurrentUser 레지스트리에 설치됩니다.

염두에두고, 나는, ALL 다음 코드를 사용하여 응용 프로그램을 설치 얻을 수 있었다 없이 WMI를 사용하여

다음은 코드입니다.

List<string> installs = new List<string>();
List<string> keys = new List<string>() {
  @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
  @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
};

// The RegistryView.Registry64 forces the application to open the registry as x64 even if the application is compiled as x86 
FindInstalls(RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64), keys, installs);
FindInstalls(RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64), keys, installs);

installs = installs.Where(s => !string.IsNullOrWhiteSpace(s)).Distinct().ToList();
installs.Sort(); // The list of ALL installed applications



private void FindInstalls(RegistryKey regKey, List<string> keys, List<string> installed)
{
  foreach (string key in keys)
  {
    using (RegistryKey rk = regKey.OpenSubKey(key))
    {
      if (rk == null)
      {
        continue;
      }
      foreach (string skName in rk.GetSubKeyNames())
      {
        using (RegistryKey sk = rk.OpenSubKey(skName))
        {
          try
          {
            installed.Add(Convert.ToString(sk.GetValue("DisplayName")));
          }
          catch (Exception ex)
          { }
        }
      }
    }
  }
}


답변

“HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ Uninstall”키를 반복하고 “DisplayName”값을 확인합니다.