注册表Uninstall
Microsoft\Windows\CurrentVersion\Uninstall 是 Windows 注册表中的一个键(key),它包含了用户通过“控制面板”中的“程序和功能”(以前称为“添加或删除程序”)安装的所有应用程序的列表。这个注册表键位于 HKEY_LOCAL_MACHINE 分支下。
当你通过“程序和功能”卸载应用程序时,Windows 会在这个注册表键下为每个应用程序创建一个子键(subkey)。每个子键都包含了与该应用程序相关的卸载信息,包括:
- 应用程序的显示名称
 
- 发行者
 
- 卸载字符串(Uninstall String),指向卸载程序的路径
 
- 版本号
 
- 安装源(安装介质的路径,如果是从网络或CD安装)
 
- 估计大小
 
- 安装日期
 
- 状态(是否已安装、正在安装等)
 
- 系统组件(是否是系统必需的应用程序)
 
- 其他与卸载相关的信息
 
代码实现
初始化列表和集合:
这部分代码初始化了两个列表:key_list 用于存储打开的注册表键,t 用于存储已处理数据的MD5哈希值,用于去重。
尝试打开注册表键:
1 2 3 4 5 6 7
   | try:     sub_key = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"     setting.log.info("正在打开: HKEY_LOCAL_MACHINE\\%s" % sub_key)     key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, sub_key)     key_list.append(key) except Exception as e:     setting.log.error("打开失败, 原因: %s" % str(e))
   | 
 
这部分代码尝试打开注册表中的 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall 键,并将打开的键添加到 key_list 中。如果打开失败,会记录错误日志。
重复上述步骤,尝试打开其他注册表键:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
   | try:     sub_key = r"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"     setting.log.info("正在打开: HKEY_LOCAL_MACHINE\\%s" % sub_key)     key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, sub_key)     key_list.append(key) except Exception as e:     setting.log.error("打开失败, 原因: %s" % str(e))
  try:     sub_key = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"     setting.log.info("正在打开: HKEY_CURRENT_USER\\%s" % sub_key)     key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, sub_key)     key_list.append(key) except Exception as e:     setting.log.error("打开失败, 原因: %s" % str(e))
   | 
 
这部分代码重复上述步骤,尝试打开 HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall 和 HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall 键,并将打开的键添加到 key_list 中。如果打开失败,会记录错误日志。
遍历每个打开的注册表键:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
   | for key in key_list:     sub_num, _, _ = winreg.QueryInfoKey(key)
      for i in range(sub_num):         name = winreg.EnumKey(key, i)
          try:             setting.log.info("正在打开: %s" % name)             key_1 = winreg.OpenKey(key, name)         except Exception as e:             setting.log.error("打开失败, 原因: %s" % str(e))             continue
          try:             display_name = winreg.QueryValueEx(key_1, "DisplayName")         except:             display_name = ""         try:             display_version = winreg.QueryValueEx(                 key_1, "DisplayVersion")         except:             display_version = ""         try:             _, _, timestamp = winreg.QueryInfoKey(key_1)         except:             timestamp = 0
   | 
 
这部分代码遍历每个打开的注册表键,获取每个子键的名称,并尝试打开这些子键。然后,它尝试获取每个子键中的 DisplayName、DisplayVersion 和 timestamp 值。如果获取失败,会将相应的值设置为空字符串或0。
处理获取到的软件信息:
1 2 3 4 5 6 7 8 9 10 11 12 13
   | if display_name:     source_data = {         "DisplayName": display_name,         "InstallTime": timestamp,         "DisplayVersion": display_version     }
      clean_data = get_line(self, source_data, self.display)     data = json.dumps(clean_data, ensure_ascii=False)     md5 = get_md5(data)     if md5 not in t:         write_file(self.file, data)         t.append(md5)
   | 
 
这部分代码检查 display_name 是否存在,如果存在,则将获取到的软件信息封装成一个字典 source_data。然后,它调用 get_line 方法处理 source_data,并将处理后的数据转换为 JSON 格式。接着,它计算 JSON 数据的 MD5 哈希值,并检查该哈希值是否已存在于 t 中。如果不存在,它将 JSON 数据写入到输出文件中,并将 MD5 哈希值添加到 t 中。