本帖最后由 箭头_Row 于 2025-8-5 15:42 编辑

起因是源於此驚驚發的此貼:测试篇 c#获取所有已经安装的程序 - 惊惊 - 博客园

整理后實現的代碼如下:
  1. // https://www.cnblogs.com/JJBox/p/10439408.html
  2. public class Program
  3. {
  4.     private const string Reg32 = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
  5.     private const string Reg64 = @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall";

  6.     /// <summary>
  7.     /// 從32位和64位註冊表中獲取所有已安裝程式的資訊
  8.     /// </summary>
  9.     /// <returns>字典:程式名稱與安裝路徑</returns>
  10.     public static Dictionary<string, string> GetProgramInfo()
  11.     {
  12.         // 使用忽略大小寫的字典,避免名稱重複
  13.         var programs = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

  14.         // 從32位和64位註冊表檢視中獲取程式資訊
  15.         AddProgramsFromRegistry(programs, Reg32, RegistryView.Registry64); // 64位檢視
  16.         AddProgramsFromRegistry(programs, Reg64, RegistryView.Registry32); // 32位檢視

  17.         return programs;
  18.     }

  19.     /// <summary>
  20.     /// 從指定註冊表路徑和檢視中添加程式資訊
  21.     /// </summary>
  22.     /// <param name="programs">儲存程式資訊的字典</param>
  23.     /// <param name="regPath">註冊表路徑</param>
  24.     /// <param name="view">註冊表檢視(32位或64位)</param>
  25.     private static void AddProgramsFromRegistry(Dictionary<string, string> programs, string regPath, RegistryView view)
  26.     {
  27.         try
  28.         {
  29.             // 以指定檢視開啟本機註冊表
  30.             using var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, view);
  31.             using var regKey = baseKey.OpenSubKey(regPath, false);

  32.             if (regKey is null)
  33.             {
  34.                 Env.Print($"無法找到註冊表路徑:{regPath} (檢視:{view})");
  35.                 return;
  36.             }

  37.             // 遍歷所有子鍵,獲取程式資訊
  38.             foreach (var subKeyName in regKey.GetSubKeyNames())
  39.             {
  40.                 var programInfo = GetProgramInfoFromKey(regKey, subKeyName);
  41.                 if (programInfo.HasValue && !string.IsNullOrEmpty(programInfo.Value.DisplayName))
  42.                 {
  43.                     // 避免重複,優先選擇非空的安裝路徑
  44.                     if (
  45.                         !programs.ContainsKey(programInfo.Value.DisplayName)
  46.                         || (
  47.                             string.IsNullOrEmpty(programs[programInfo.Value.DisplayName])
  48.                             && !string.IsNullOrEmpty(programInfo.Value.InstallLocation)
  49.                         )
  50.                     )
  51.                         programs[programInfo.Value.DisplayName] = programInfo.Value.InstallLocation;
  52.                 }
  53.             }
  54.         }
  55.         catch (Exception ex)
  56.         {
  57.             Env.Print($"存取註冊表 {regPath} (檢視:{view}) 時發生錯誤:{ex.Message}");
  58.         }
  59.     }

  60.     /// <summary>
  61.     /// 從單個註冊表子鍵中提取程式資訊
  62.     /// </summary>
  63.     /// <param name="parentKey">父鍵</param>
  64.     /// <param name="subKeyName">子鍵名稱</param>
  65.     /// <returns>程式名稱與安裝路徑的元組,若無效則返回 null</returns>
  66.     private static (string DisplayName, string InstallLocation)? GetProgramInfoFromKey(
  67.         RegistryKey parentKey,
  68.         string subKeyName
  69.     )
  70.     {
  71.         try
  72.         {
  73.             using var key = parentKey.OpenSubKey(subKeyName);
  74.             if (key is null)
  75.                 return null;

  76.             var displayName = key.GetValue("DisplayName") as string ?? string.Empty;
  77.             var installLocation = key.GetValue("InstallLocation") as string ?? string.Empty;
  78.             var releaseType = key.GetValue("ReleaseType") as string;

  79.             // 僅包含具有有效顯示名稱且非更新類型的程式
  80.             if (string.IsNullOrEmpty(displayName) || releaseType is "Security Update" or "Update")
  81.                 return null;

  82.             return (displayName, installLocation);
  83.         }
  84.         catch (Exception ex)
  85.         {
  86.             Env.Print($"讀取子鍵 {subKeyName} 時發生錯誤:{ex.Message}");
  87.             return null;
  88.         }
  89.     }
  90. }


測試代碼如下:

var programs = Program.GetProgramInfo();
List<string> printLines = programs
    .Where(program => !string.IsNullOrWhiteSpace(program.Key) && program.Value.Contains("AutoCAD"))
    .Select(program => $"{program.Value}\n      {program.Key}")
    .OrderBy(item => item)
    .ToList();

string.Join("\n", printLines).Print();


問題來了:還有哪里可以優化的地方,總感覺不是完善呀,有木有?

最後鳴謝:驚驚(二開佈道者)中國的吉爾!




网友答: 那麼問題來了,可以獲取系統註冊過的所有軟件程序,那麼如何獲取當前CAD中所有加載註冊過的的fas、vlx、dll、arx等程序呢?

网友答: 本帖最后由 你有种再说一遍 于 2025-8-5 18:25 编辑
箭头_Row 发表于 2025-8-5 15:47
那麼問題來了,可以獲取系統註冊過的所有軟件程序,那麼如何獲取當前CAD中所有加載註冊過的的fas、vlx、dll ...

arx和dll这种插件叫加载模块.
c++非托管环境,靠GetModuleHandle或EnumProcessModules.
c#是托管环境,靠遍历程序集.
它们都可以相互读取,尤其是c#靠win32API读取arx模块.

fas,vlx这种我就不晓得载入到哪里了,
估计是藏在了lisp解释器中...

还有什么需要完善?
因为有些程序是免装版,
所以直接通过检索NTFS格式的USN Journal日志也就是Everything原理,
再者就是eFAT格式的直接扫盘然后构造索引.
然后维护磁盘写入事件.
构造倒序索引...
这样什么信息你都可以获取了.
  • 上一篇:中望.Net中PromptKeywordOptions对象的一个bug
  • 下一篇:没有了