本帖最后由 箭头_Row 于 2025-8-5 15:42 编辑
起因是源於此驚驚發的此貼:测试篇 c#获取所有已经安装的程序 - 惊惊 - 博客园
整理后實現的代碼如下:

測試代碼如下:
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 编辑
arx和dll这种插件叫加载模块.
c++非托管环境,靠GetModuleHandle或EnumProcessModules.
c#是托管环境,靠遍历程序集.
它们都可以相互读取,尤其是c#靠win32API读取arx模块.
fas,vlx这种我就不晓得载入到哪里了,
估计是藏在了lisp解释器中...
还有什么需要完善?
因为有些程序是免装版,
所以直接通过检索NTFS格式的USN Journal日志也就是Everything原理,
再者就是eFAT格式的直接扫盘然后构造索引.
然后维护磁盘写入事件.
构造倒序索引...
这样什么信息你都可以获取了.
起因是源於此驚驚發的此貼:测试篇 c#获取所有已经安装的程序 - 惊惊 - 博客园
整理后實現的代碼如下:

- // https://www.cnblogs.com/JJBox/p/10439408.html
- public class Program
- {
- private const string Reg32 = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
- private const string Reg64 = @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall";
- /// <summary>
- /// 從32位和64位註冊表中獲取所有已安裝程式的資訊
- /// </summary>
- /// <returns>字典:程式名稱與安裝路徑</returns>
- public static Dictionary<string, string> GetProgramInfo()
- {
- // 使用忽略大小寫的字典,避免名稱重複
- var programs = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- // 從32位和64位註冊表檢視中獲取程式資訊
- AddProgramsFromRegistry(programs, Reg32, RegistryView.Registry64); // 64位檢視
- AddProgramsFromRegistry(programs, Reg64, RegistryView.Registry32); // 32位檢視
- return programs;
- }
- /// <summary>
- /// 從指定註冊表路徑和檢視中添加程式資訊
- /// </summary>
- /// <param name="programs">儲存程式資訊的字典</param>
- /// <param name="regPath">註冊表路徑</param>
- /// <param name="view">註冊表檢視(32位或64位)</param>
- private static void AddProgramsFromRegistry(Dictionary<string, string> programs, string regPath, RegistryView view)
- {
- try
- {
- // 以指定檢視開啟本機註冊表
- using var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, view);
- using var regKey = baseKey.OpenSubKey(regPath, false);
- if (regKey is null)
- {
- Env.Print($"無法找到註冊表路徑:{regPath} (檢視:{view})");
- return;
- }
- // 遍歷所有子鍵,獲取程式資訊
- foreach (var subKeyName in regKey.GetSubKeyNames())
- {
- var programInfo = GetProgramInfoFromKey(regKey, subKeyName);
- if (programInfo.HasValue && !string.IsNullOrEmpty(programInfo.Value.DisplayName))
- {
- // 避免重複,優先選擇非空的安裝路徑
- if (
- !programs.ContainsKey(programInfo.Value.DisplayName)
- || (
- string.IsNullOrEmpty(programs[programInfo.Value.DisplayName])
- && !string.IsNullOrEmpty(programInfo.Value.InstallLocation)
- )
- )
- programs[programInfo.Value.DisplayName] = programInfo.Value.InstallLocation;
- }
- }
- }
- catch (Exception ex)
- {
- Env.Print($"存取註冊表 {regPath} (檢視:{view}) 時發生錯誤:{ex.Message}");
- }
- }
- /// <summary>
- /// 從單個註冊表子鍵中提取程式資訊
- /// </summary>
- /// <param name="parentKey">父鍵</param>
- /// <param name="subKeyName">子鍵名稱</param>
- /// <returns>程式名稱與安裝路徑的元組,若無效則返回 null</returns>
- private static (string DisplayName, string InstallLocation)? GetProgramInfoFromKey(
- RegistryKey parentKey,
- string subKeyName
- )
- {
- try
- {
- using var key = parentKey.OpenSubKey(subKeyName);
- if (key is null)
- return null;
- var displayName = key.GetValue("DisplayName") as string ?? string.Empty;
- var installLocation = key.GetValue("InstallLocation") as string ?? string.Empty;
- var releaseType = key.GetValue("ReleaseType") as string;
- // 僅包含具有有效顯示名稱且非更新類型的程式
- if (string.IsNullOrEmpty(displayName) || releaseType is "Security Update" or "Update")
- return null;
- return (displayName, installLocation);
- }
- catch (Exception ex)
- {
- Env.Print($"讀取子鍵 {subKeyName} 時發生錯誤:{ex.Message}");
- return null;
- }
- }
- }
測試代碼如下:
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格式的直接扫盘然后构造索引.
然后维护磁盘写入事件.
构造倒序索引...
这样什么信息你都可以获取了.