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


83

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

답변:


116

레지스트리 키 "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 구성 요소 및 업데이트를 무시합니다.


27
이 쿼리를 반복적으로 실행하려는 경우 WMI Win32_Product 클래스를 사용하는 것은 좋지 않습니다. 다음 Microsoft KB 문서를 참조하십시오. support.microsoft.com/kb/974524/EN-US 핵심 문제는 (a) Win32_Product가 매우 느리고 (b) "Windows Installer가 제품을 재구성했습니다."를 생성한다는 것입니다. 쿼리를 실행할 때마다 시스템에 설치된 모든 제품에 대한 이벤트 로그 메시지 . 도! 이 문서에서는 SMS를 설치하지 않은 경우 나타나지 않는 Win32reg_AddRemovePrograms 클래스를 사용할 것을 권장합니다. 도! 따라서 레지스트리 쿼리를 고수하는 것이 좋습니다.
Simon Gillbee 2010 년

Simon Gillbee의 의견은 받아 들여진 대답이어야합니다. 또는 Kirtans! WMI WIN32_Product는 여기로가는 길이 아닙니다. 저를 믿으세요!
bdd

13
Er, 그것이 레지스트리 예제가 내 대답의 첫 번째 이유입니다. WMI는 단순히 대체 솔루션으로 제시되었으며 거기에서도 "실행 속도가 다소 느립니다"및 기타 단점을 언급했습니다. 처음부터 답을 읽으십시오. ;)
Xiaofu

1
좀 이상하지만 프로그램을 제거하고 다시 설치 한 다음 레지스트리 키를 사용하여 찾아보십시오. 컴퓨터를 다시 시작하지 않으면 찾을 수 없습니다
Yar

3
내 질문에 답하려면 : stackoverflow.com/questions/27838798/… 비록 64 비트와 32 비트를 모두 쿼리해야한다는 것이 짜증 스럽지만.
Robert Koernke 2017-07-27

9

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

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)
                { }
            }
        }
    }
}

전체 목록을 원하지는 않습니다. 선택한 설치 프로그램이 필요하므로이를 위해 무엇을 할 수 있습니까? 감사합니다
Dhru 'soni

9

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

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

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


이거 확실하니? 내 Windows 10 Enterprise 64bit에서는 두 목록이 비슷하게 보이고 x86 응용 프로그램이 둘 다에 표시됩니다.
Florian Straub

고맙습니다, 이것은 저에게 효과적입니다. 제가 검색했던 프로그램을 찾았습니다.
Xtian11

에서는 regedit그렇게 보인다. 32 비트 프로그램 (64 비트 윈도우에서) 그러나 두리스트는 동일 WOW6432Node하나 regedit.
Meow Cat 2012

6

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

또한 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 라는 사실을 알고 싶을 수도 있습니다 .


정말 감사합니다.이를 달성하는 좋은 방법입니다. ShellObjectWatcher에서 직접 이름을 가져오고 이름을 구문 분석하는 방법이 있는지 알고 계셨습니까?
forlayo

다른 이벤트 유형은 따로있다 AllEventsItemCreated이나 ItemRenamed나는 그들이 설치 또는 제거로 응용 프로그램을 추적하기 위해 사용하는 시도한다. 이 이벤트의 이벤트 인수에는 Path속성이 포함되어 있지만이 속성은 적어도 내 테스트에서 항상 null입니다. 항상 null이기 때문에 구문 분석 이름을 얻는 방법을 알아 내려고 노력하지 않았습니다. 대신 폴더의 앱을 반복하여 항목이 발생할 때마다 동기화하는 앱 목록을 유지합니다. 이상적이지는 않지만 작업을 완료합니다.
user1969903

1
감사! 나는 실제로 똑같이하고있다. 또한 이것은 "방금 설치된 응용 프로그램의 주요 실행 파일을 찾는 방법"에 대한 다른 질문에 도움이되었습니다.-> stackoverflow.com/questions/60440044/… 그런 다음 감사합니다! :)
forlayo

4

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와 결합 할 수 있습니다.


3

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

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

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)
          { }
        }
      }
    }
  }
}

1

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


1

Windows Installer API를 사용하십시오!

모든 프로그램을 안정적으로 열거 할 수 있습니다. 레지스트리는 신뢰할 수 없지만 WMI는 무겁습니다.


확실히 무거운 무게입니다. 반복적으로 실행하면 무거운 무게처럼 성능이 저하됩니다. 내 앱의 기능이 다른 앱에 종속되어 있고 제대로 설치되었는지 알고있는 경우 앱이 64 비트로 제공되는 경우에만 32 또는 64에 대한 제거 레지스트리 키만 필요합니다) 반면에 wmi를 사용해야하는 경우 스마트 속성 트릭을 통해 애플리케이션 중 한 번만 사용하도록 제한됩니다.
gg89


1

목록의 개체 :

public class InstalledProgram
{
    public string DisplayName { get; set; }
    public string Version { get; set; }
    public string InstalledDate { get; set; }
    public string Publisher { get; set; }
    public string UnninstallCommand { get; set; }
    public string ModifyPath { get; set; }
}

목록 생성 요청 :

    List<InstalledProgram> installedprograms = new List<InstalledProgram>();
    string registry_key = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
    using (RegistryKey key = Registry.LocalMachine.OpenSubKey(registry_key))
    {
        foreach (string subkey_name in key.GetSubKeyNames())
        {
            using (RegistryKey subkey = key.OpenSubKey(subkey_name))
            {
                if (subkey.GetValue("DisplayName") != null)
                {
                    installedprograms.Add(new InstalledProgram
                    {
                        DisplayName = (string)subkey.GetValue("DisplayName"),
                        Version = (string)subkey.GetValue("DisplayVersion"),
                        InstalledDate = (string)subkey.GetValue("InstallDate"),
                        Publisher = (string)subkey.GetValue("Publisher"),
                        UnninstallCommand = (string)subkey.GetValue("UninstallString"),
                        ModifyPath = (string)subkey.GetValue("ModifyPath")
                    });
                }
            }
        }
    }

1

다른 사람들이 지적했듯이 수락 된 대답은 x86 및 x64 설치를 모두 반환하지 않습니다. 아래는 이에 대한 나의 해결책입니다. 를 만들고 StringBuilder레지스트리 값을 서식과 함께 추가하고 출력을 텍스트 파일에 씁니다.

const string FORMAT = "{0,-100} {1,-20} {2,-30} {3,-8}\n";

private void LogInstalledSoftware()
{
    var line = string.Format(FORMAT, "DisplayName", "Version", "Publisher", "InstallDate");
    line += string.Format(FORMAT, "-----------", "-------", "---------", "-----------");
    var sb = new StringBuilder(line, 100000);
    ReadRegistryUninstall(ref sb, RegistryView.Registry32);
    sb.Append($"\n[64 bit section]\n\n{line}");
    ReadRegistryUninstall(ref sb, RegistryView.Registry64);
    File.WriteAllText(@"c:\temp\log.txt", sb.ToString());
}

   private static void ReadRegistryUninstall(ref StringBuilder sb, RegistryView view)
    {
        const string REGISTRY_KEY = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
        using var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, view);
        using var subKey = baseKey.OpenSubKey(REGISTRY_KEY);
        foreach (string subkey_name in subKey.GetSubKeyNames())
        {
            using RegistryKey key = subKey.OpenSubKey(subkey_name);
            if (!string.IsNullOrEmpty(key.GetValue("DisplayName") as string))
            {
                var line = string.Format(FORMAT,
                    key.GetValue("DisplayName"),
                    key.GetValue("DisplayVersion"),
                    key.GetValue("Publisher"),
                    key.GetValue("InstallDate"));
                sb.Append(line);
            }
            key.Close();
        }
        subKey.Close();
        baseKey.Close();
    }


0

WMI ( Windows Management Instrumentation )를 살펴 보시기 바랍니다 . System.Management 참조를 C # 프로젝트에 추가하면`ManagementObjectSearcher '클래스에 액세스 할 수 있으며 유용 할 것입니다.

설치된 응용 프로그램에 대한 다양한 WMI 클래스가 있지만 Windows Installer와 함께 설치된 경우 Win32_Product 클래스가 가장 적합 할 것입니다.

ManagementObjectSearcher s = new ManagementObjectSearcher("SELECT * FROM Win32_Product");

0

Nicks 접근 방식을 사용했습니다. Visual Studio 용 원격 도구가 설치되어 있는지 여부를 확인해야했습니다. 약간 느려 보이지만 별도의 스레드에서는 괜찮습니다. -여기 내 확장 코드 :

    private bool isRdInstalled() {
        ManagementObjectSearcher p = new ManagementObjectSearcher("SELECT * FROM Win32_Product");
        foreach (ManagementObject program in p.Get()) {
            if (program != null && program.GetPropertyValue("Name") != null && program.GetPropertyValue("Name").ToString().Contains("Microsoft Visual Studio 2012 Remote Debugger")) {
                return true;
            }
            if (program != null && program.GetPropertyValue("Name") != null) {
                Trace.WriteLine(program.GetPropertyValue("Name"));
            }
        }
        return false;
    }

0

내 요구 사항은 내 시스템에 특정 소프트웨어가 설치되어 있는지 확인하는 것입니다. 이 솔루션은 예상대로 작동합니다. 도움이 될 수 있습니다. Visual Studio 2015에서 C #의 Windows 응용 프로그램을 사용했습니다.

 private void Form1_Load(object sender, EventArgs e)
        {

            object line;
            string softwareinstallpath = string.Empty;
            string registry_key = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
            using (var baseKey = Microsoft.Win32.RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64))
            {
                using (var key = baseKey.OpenSubKey(registry_key))
                {
                    foreach (string subkey_name in key.GetSubKeyNames())
                    {
                        using (var subKey = key.OpenSubKey(subkey_name))
                        {
                            line = subKey.GetValue("DisplayName");
                            if (line != null && (line.ToString().ToUpper().Contains("SPARK")))
                            {

                                softwareinstallpath = subKey.GetValue("InstallLocation").ToString();
                                listBox1.Items.Add(subKey.GetValue("InstallLocation"));
                                break;
                            }
                        }
                    }
                }
            }

            if(softwareinstallpath.Equals(string.Empty))
            {
                MessageBox.Show("The Mirth connect software not installed in this system.")
            }



            string targetPath = softwareinstallpath + @"\custom-lib\";
            string[] files = System.IO.Directory.GetFiles(@"D:\BaseFiles");

            // Copy the files and overwrite destination files if they already exist. 
            foreach (var item in files)
            {
                string srcfilepath = item;
                string fileName = System.IO.Path.GetFileName(item);
                System.IO.File.Copy(srcfilepath, targetPath + fileName, true);
            }
            return;

        }

foreach (key.GetSubKeyNames ()의 문자열 subkey_name) <-null 인 경우 여기에서 확인하지 않습니다.
Burgo855

이 이유 때문에 반대표를받을 자격이 없습니다. 복제되었지만.
Meow Cat 2012
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.