分類
    • 主機維護
    • 程式語言
    最新文章

    C# .Net 控制 Windows 的 Wifi 連線

    2024 年 8 月 28 日

    C# .Net 6 匯入至 Windows 憑證

    2024 年 8 月 28 日

    C# .Net 6 刪除 Windows 下的使用者

    2024 年 7 月 31 日

    C# .Net 6 取得 Windows 列印的紀錄 Log

    2024 年 7 月 31 日
    Facebook Instagram
    Facebook Instagram Telegram
    2kH – Technology Log
    • 首頁
    2kH – Technology Log
    Home»程式語言»C# .Net 6 取得 Windows 上安裝軟體的列表
    程式語言 2022 年 6 月 16 日

    C# .Net 6 取得 Windows 上安裝軟體的列表

    最近負責的案子是要在 Windows 的設備中定時回傳資料到伺服器,包含一些對 Windows 的操作,第一次製作類似這樣的程式,寫了很多沒有寫過的東西。

    記憶體、處理器、硬碟…等等基本的資訊可以透過 WMI 物件取得 Windows Management Instrumentation (WMI)

    Windows Management Instrumentation (WMI) 是 Microsoft 在 Web 架構企業管理 (WBEM) 方面的實作,這是一種開發標準技術的業界措施,用於存取企業環境中的管理資訊。 WMI 使用通用訊息模型 (CIM) 業界標準來代表系統、應用程式、網路、裝置和其他受管理元件。 CIM 是由分散式管理工作組 (DMTF) 所開發和維護。

    Microsoft docs

    簡單說就是 Windows 內建的一個東西,可以呼叫他做很多事情就對了!

    那可以透過 System.Management 去呼叫,但是在 .Net 6 的環境下需要另外安裝此套件(舊的 .Net 好像有內建,不確定,網路上寫的)

    可以透過 Nuget 安裝,確認有安裝後實作方式為以下

    using System.Management;
    
    ManagementClass mangnmt = new ManagementClass("Win32_PhysicalMemory");
    ManagementObjectCollection managementObjectCollection = mangnmt.GetInstances();
    foreach (ManagementObject managementObject in managementObjectCollection)
    {
        var data = managementObject.GetPropertyValue("Name");
        Console.WriteLine(data);
    }

    遇到的問題是,在取得安裝的軟體列表的時候可以用 Win32_Product 來取得

    但是透過 Win32_Product 取得的時候,速度非常慢,在舊電腦 Windows 10(四代 i7)上跑要將近一分鐘,新安裝的 Windows 11(十二代 i5)也要將近十秒的時間

    所以這邊就想說有沒有其他方式可以取得安裝列表

    另一方式是從註冊表,註冊表會記錄每一個軟體解除安裝的路徑,對應到的是控制台的應用程式,包含版本號以及解除安裝的執行檔案位置都是記錄在註冊表

    這邊用 RegistryKey 取得,程式如下

    string uninstallKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
    RegistryKey rk64 = Registry.LocalMachine.OpenSubKey(uninstallKey);
    foreach (string skName in rk64.GetSubKeyNames())
    {
        RegistryKey sk = rk64.OpenSubKey(skName);
        var name = sk.GetValue("DisplayName")?.ToString();
        if (!string.IsNullOrEmpty(name)) Console.WriteLine(name);
    }

    這邊要注意的是 x64 跟 x86 的軟體會在註冊表不同的位置

    如果是在 x64 的 Windows 環境下

    x64 軟體註冊表位置:SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall

    x86 軟體註冊表位置:SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall

    但是如果在 x86 的 Windows 環境下

    x86 軟體註冊表位置:SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall

    這個是比較需要注意的地方,不過 .Net 6 非常方便可以用 Environment.Is64BitOperatingSystem 來判斷是否是 x64 的環境(True/False)

    System.Environment.Is64BitOperatingSystem

    完整代碼如下:

    var result = new List<SoftwareView>();
    
    if (Environment.Is64BitOperatingSystem)
    {
        // x64 Registry
        string uninstallKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
        RegistryKey rk64 = Registry.LocalMachine.OpenSubKey(uninstallKey);
        foreach (string skName in rk64.GetSubKeyNames())
        {
            RegistryKey sk = rk64.OpenSubKey(skName);
            var name = sk.GetValue("DisplayName")?.ToString();
            if (!string.IsNullOrEmpty(name)) result.Add(SoftwareMap(name, sk, "x64"));
        }
    
        // x86 Registry
        uninstallKey = @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall";
        RegistryKey rk32 = Registry.LocalMachine.OpenSubKey(uninstallKey);
        foreach (string skName in rk32.GetSubKeyNames())
        {
            RegistryKey sk = rk32.OpenSubKey(skName);
            var name = sk.GetValue("DisplayName")?.ToString();
            if (!string.IsNullOrEmpty(name)) result.Add(SoftwareMap(name, sk, "x86"));
        }
    }
    else
    {
        // x86 Registry
        string uninstallKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
        RegistryKey rk64 = Registry.LocalMachine.OpenSubKey(uninstallKey);
        foreach (string skName in rk64.GetSubKeyNames())
        {
            RegistryKey sk = rk64.OpenSubKey(skName);
            var name = sk.GetValue("DisplayName")?.ToString();
            if (!string.IsNullOrEmpty(name)) result.Add(SoftwareMap(name, sk, "x86"));
        }
    }
    
    return result;
    
    SoftwareView SoftwareMap(string name, RegistryKey sk, string platform)
    {
        return new SoftwareView
        {
            DisplayName = name,
            DisplayVersion = sk.GetValue("DisplayVersion")?.ToString(),
            InstallDate = sk.GetValue("InstallDate")?.ToString(),
            InstallSource = sk.GetValue("InstallSource")?.ToString(),
            InstallLocation = sk.GetValue("InstallLocation")?.ToString(),
            InstallDir = sk.GetValue("InstallDir")?.ToString(),
            PSChildName = sk.GetValue("PSChildName")?.ToString(),
            Publisher = sk.GetValue("Publisher")?.ToString(),
            QuietUninstallString = sk.GetValue("QuietUninstallString")?.ToString(),
            UninstallString = sk.GetValue("UninstallString")?.ToString(),
            Platform = platform
        };
    }
    public class SoftwareView
    {
        public string DisplayName { get; set; }
    
        public string DisplayVersion { get; set; }
    
        public string InstallSource { get; set; }
    
        public string InstallLocation { get; set; }
    
        public string InstallDir { get; set; }
    
        public string Publisher { get; set; }
    
        public string InstallDate { get; set; }
    
        public string PSChildName { get; set; }
    
        public string Platform { get; set; }
    
        public string QuietUninstallString { get; set; }
    
        public string UninstallString { get; set; }
    
    }

    不曉得還有沒有更好的取得方式,這邊透過註冊表取得的列表和 Win32_Product 取得的資料是有不同的,但是目前沒有確認差異在哪裡。

    相關資源 :

    System.Management: https://www.nuget.org/packages/System.Management/

    .Net C# Software Windows

    Leave A Reply Cancel Reply

    關於作者
    關於作者
    我是軟體工程師 2kH
    這裡是用來記錄工作上遇到的事物
    如果有問題想詢問,或者有合作可能
    歡迎來信:2kh@bshade.net
    本部落格文章版權所有
    未經授權,不得進行任何營利行為
    • Home
    © 2025 idawn. All Rights Reserved by 2kH

    Type above and press Enter to search. Press Esc to cancel.