You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用C#获取Windows系统已安装软件及对应许可证信息

解决方案:多源数据整合 + 针对性密钥提取

没有单一方案能覆盖所有场景,建议结合注册表、WMI、系统API及特定软件的密钥解析逻辑,互补短板。以下是具体实现思路和代码:

一、获取已安装软件列表:注册表为主,WMI补全

1. 注册表读取(快速覆盖多数软件)

Windows多数软件会在注册表的Uninstall项注册信息,需同时处理64位和32位路径:

using Microsoft.Win32;
using System.Collections.Generic;

public List<SoftwareInfo> GetSoftwareFromRegistry()
{
    var softwareList = new List<SoftwareInfo>();
    // 覆盖64位系统下的32/64位软件路径
    var paths = new[] { 
        @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
        @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
    };

    foreach (var path in paths)
    {
        using (var key = Registry.LocalMachine.OpenSubKey(path))
        {
            if (key == null) continue;
            foreach (var subKeyName in key.GetSubKeyNames())
            {
                using (var subKey = key.OpenSubKey(subKeyName))
                {
                    if (subKey == null) continue;
                    var name = subKey.GetValue("DisplayName")?.ToString();
                    var version = subKey.GetValue("DisplayVersion")?.ToString();
                    var publisher = subKey.GetValue("Publisher")?.ToString();
                    if (!string.IsNullOrEmpty(name))
                    {
                        softwareList.Add(new SoftwareInfo
                        {
                            Name = name,
                            Version = version,
                            Publisher = publisher,
                            Source = "Registry"
                        });
                    }
                }
            }
        }
    }
    return softwareList;
}

public class SoftwareInfo
{
    public string Name { get; set; }
    public string Version { get; set; }
    public string Publisher { get; set; }
    public string LicenseKey { get; set; }
    public string Source { get; set; }
}

2. WMI补全(针对MSI安装的软件)

Win32_Product确实慢,但可以通过只查询必要字段优化速度,避免全量属性查询:

using System.Management;

public List<SoftwareInfo> GetSoftwareFromWmi()
{
    var softwareList = new List<SoftwareInfo>();
    // 仅查询核心字段,减少数据传输
    var query = new SelectQuery("SELECT Name, Version, Vendor, IdentifyingNumber FROM Win32_Product");
    using (var searcher = new ManagementObjectSearcher(query))
    {
        foreach (var obj in searcher.Get())
        {
            softwareList.Add(new SoftwareInfo
            {
                Name = obj["Name"]?.ToString(),
                Version = obj["Version"]?.ToString(),
                Publisher = obj["Vendor"]?.ToString(),
                Source = "WMI"
            });
        }
    }
    return softwareList;
}

二、提取许可证密钥:分场景处理

1. Windows系统产品密钥

读取注册表的DigitalProductId并解密,无需依赖第三方工具:

using System;
using System.Text;

public string GetWindowsProductKey()
{
    using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion"))
    {
        if (key == null) return null;
        var digitalProductId = key.GetValue("DigitalProductId") as byte[];
        if (digitalProductId == null) return null;

        // Windows通用密钥解密算法
        const string chars = "BCDFGHJKMPQRTVWXY2346789";
        var keyParts = new int[15];
        Array.Copy(digitalProductId, 52, keyParts, 0, 15);

        var productKey = new StringBuilder();
        for (int i = 24; i >= 0; i--)
        {
            int remainder = 0;
            for (int j = 14; j >= 0; j--)
            {
                int temp = remainder * 256 + keyParts[j];
                keyParts[j] = temp / 24;
                remainder = temp % 24;
            }
            productKey.Insert(0, chars[remainder]);
            if ((i % 5 == 0) && (i != 0))
                productKey.Insert(0, "-");
        }
        return productKey.ToString();
    }
}

2. Office套件密钥

类似Windows密钥,读取对应版本的注册表项解密:

public string GetOfficeProductKey(string officeVersion = "16.0") // 16.0=Office 2019/365, 15.0=2013
{
    var path = $@"SOFTWARE\Microsoft\Office\{officeVersion}\Registration";
    using (var key = Registry.LocalMachine.OpenSubKey(path))
    {
        if (key == null) return null;
        foreach (var subKeyName in key.GetSubKeyNames())
        {
            using (var subKey = key.OpenSubKey(subKeyName))
            {
                if (subKey == null) continue;
                var digitalProductId = subKey.GetValue("DigitalProductID") as byte[];
                if (digitalProductId == null) continue;

                // Office密钥解密逻辑(偏移量与Windows不同)
                const string chars = "BCDFGHJKMPQRTVWXY2346789";
                var keyParts = new int[15];
                Array.Copy(digitalProductId, 56, keyParts, 0, 15);

                var productKey = new StringBuilder();
                for (int i = 24; i >= 0; i--)
                {
                    int remainder = 0;
                    for (int j = 14; j >= 0; j--)
                    {
                        int temp = remainder * 256 + keyParts[j];
                        keyParts[j] = temp / 24;
                        remainder = temp % 24;
                    }
                    productKey.Insert(0, chars[remainder]);
                    if ((i % 5 == 0) && (i != 0))
                        productKey.Insert(0, "-");
                }
                return productKey.ToString();
            }
        }
    }
    return null;
}

3. 第三方软件密钥

多数第三方软件会将密钥存在特定注册表路径(如HKLM\Software\[厂商]\[软件名]下的SerialNumber或LicenseKey字段),可针对性读取:

public string GetThirdPartyLicenseKey(string vendorPath, string keyName)
{
    using (var key = Registry.LocalMachine.OpenSubKey(vendorPath))
    {
        return key?.GetValue(keyName)?.ToString();
    }
}

// 示例:获取Adobe Photoshop密钥
// var photoshopKey = GetThirdPartyLicenseKey(@"SOFTWARE\Adobe\Adobe Photoshop\2024", "SerialNumber");

4. 系统许可证状态(替代Slmgr)

直接调用系统自带的slmgr.vbs解析输出,无需额外依赖:

using System.Diagnostics;

public string GetWindowsLicenseStatus()
{
    var process = new Process
    {
        StartInfo = new ProcessStartInfo
        {
            FileName = "cscript.exe",
            Arguments = @"//nologo %windir%\system32\slmgr.vbs /dli",
            RedirectStandardOutput = true,
            UseShellExecute = false,
            CreateNoWindow = true
        }
    };
    process.Start();
    var output = process.StandardOutput.ReadToEnd();
    process.WaitForExit();
    return output;
}

三、优化与注意事项

  • 权限:必须以管理员身份运行程序,否则无法读取部分注册表路径和WMI信息。
  • 去重:整合注册表和WMI的软件列表时,需按名称/IdentifyingNumber去重。
  • 异步并行:将注册表读取、WMI查询、密钥提取放在异步任务中并行执行,减少总耗时。
  • 局限性:部分软件的许可证密钥会被加密存储或不公开,无法通过通用方法提取,只能覆盖主流软件。

内容的提问来源于stack exchange,提问作者Majid Ebadiparsa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 03:48:19