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

Windows已安装应用图标缺失:如何优化代码或采用替代方案?

解决Windows已安装应用图标获取不全的问题

一、优化注册表查询逻辑

仅读取DisplayIcon键的局限性很大,多数应用不会在卸载项中直接配置该字段,你需要扩展查询范围并增加 fallback 逻辑:

  1. 覆盖更多注册表路径
    应用的卸载信息可能分布在多个位置,必须同时遍历:

    • HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall(系统级应用)
    • HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall(64位系统上的32位应用)
    • HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall(用户级安装的应用)
  2. 处理DisplayIcon的格式问题
    部分应用的DisplayIcon值会附带图标索引(比如"C:\xxx\app.exe,0"),需要先分割出实际文件路径:

    if "," in display_icon:
        display_icon = display_icon.split(",")[0].strip('"')
    
  3. 从InstallLocation fallback 找主程序
    当没有DisplayIcon时,读取InstallLocation字段,然后在该目录下查找主程序EXE:

    • 优先匹配常见主程序名(如chrome.exe、steam.exe)
    • 匹配失败时遍历目录查找EXE文件

二、基于PyQt6的完整实现代码

结合Qt原生的图标获取能力,无需额外调用复杂的Windows API:

import winreg
import os
from PyQt6.QtWidgets import QApplication, QComboBox, QWidget, QVBoxLayout
from PyQt6.QtGui import QIcon, QFileIconProvider
from PyQt6.QtCore import QFileInfo

def get_installed_apps():
    apps = []
    # 定义需要遍历的注册表路径
    reg_paths = [
        r"Software\Microsoft\Windows\CurrentVersion\Uninstall",
        r"Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
    ]
    root_keys = [winreg.HKEY_LOCAL_MACHINE, winreg.HKEY_CURRENT_USER]

    for root_key in root_keys:
        for reg_path in reg_paths:
            try:
                parent_key = winreg.OpenKey(root_key, reg_path)
                subkey_count = winreg.QueryInfoKey(parent_key)[0]
                
                for i in range(subkey_count):
                    subkey_name = winreg.EnumKey(parent_key, i)
                    try:
                        subkey = winreg.OpenKey(parent_key, subkey_name)
                        # 必须获取DisplayName,否则跳过该条目
                        display_name = winreg.QueryValueEx(subkey, "DisplayName")[0]
                        
                        # 尝试读取DisplayIcon
                        display_icon = None
                        try:
                            icon_val = winreg.QueryValueEx(subkey, "DisplayIcon")[0]
                            display_icon = icon_val.split(",")[0].strip('"') if "," in icon_val else icon_val.strip('"')
                        except FileNotFoundError:
                            pass

                        # 从InstallLocation查找主程序
                        if not display_icon:
                            try:
                                install_loc = winreg.QueryValueEx(subkey, "InstallLocation")[0]
                                if os.path.isdir(install_loc):
                                    # 优先匹配常见主程序名
                                    common_exes = ["chrome.exe", "steam.exe", "firefox.exe", "main.exe"]
                                    for exe in common_exes:
                                        exe_path = os.path.join(install_loc, exe)
                                        if os.path.exists(exe_path):
                                            display_icon = exe_path
                                            break
                                    # 找不到则遍历目录找第一个EXE
                                    if not display_icon:
                                        for root, _, files in os.walk(install_loc):
                                            for f in files:
                                                if f.lower().endswith(".exe"):
                                                    display_icon = os.path.join(root, f)
                                                    break
                                            if display_icon:
                                                break
                            except FileNotFoundError:
                                pass

                        apps.append((display_name, display_icon))
                    except FileNotFoundError:
                        continue
                    finally:
                        subkey.Close()
            except FileNotFoundError:
                continue
            finally:
                parent_key.Close()
    
    # 去重并按名称排序
    unique_apps = list({name: icon for name, icon in apps}.items())
    return sorted(unique_apps, key=lambda x: x[0])

def fill_combo_box(combo):
    apps = get_installed_apps()
    icon_provider = QFileIconProvider()
    for name, icon_path in apps:
        icon = QIcon()
        if icon_path and os.path.exists(icon_path):
            file_info = QFileInfo(icon_path)
            icon = icon_provider.icon(file_info)
        combo.addItem(icon, name)

if __name__ == "__main__":
    app = QApplication([])
    window = QWidget()
    layout = QVBoxLayout()
    combo = QComboBox()
    fill_combo_box(combo)
    layout.addWidget(combo)
    window.setLayout(layout)
    window.resize(400, 300)
    window.show()
    app.exec()

三、额外优化方案

  1. 处理UWP应用
    UWP应用的信息不在常规卸载路径中,需要读取HKLM\Software\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\Applications,从PackageFullName对应的InstallLocation中找到Assets目录下的图标文件(如Logo.png)。

  2. 使用Windows原生API获取图标
    如果需要更精准的系统原生图标,可以用pywin32调用SHGetFileInfo:

    import win32gui
    import win32con
    from PyQt6.QtGui import QPixmap
    
    def get_native_icon(file_path):
        shinfo = win32gui.SHGetFileInfo(file_path, 0, win32con.SHGFI_ICON | win32con.SHGFI_LARGEICON)
        hicon = shinfo[0]
        pixmap = QPixmap.fromWinHICON(hicon)
        win32gui.DestroyIcon(hicon)
        return QIcon(pixmap)
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 03:24:57