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

如何在Python中通过WinSDK/WinRT从source_app_user_model_id获取应用显示名称(含非UWP应用兼容方案)

如何在Python中通过WinSDK/WinRT从source_app_user_model_id获取应用显示名称(含非UWP应用兼容方案)

我完全理解你现在的困境:用WinRT拿到媒体会话的source_app_user_model_id后,UWP专属的AppInfo和PackageManager完全搞不定Chrome、Firefox这类传统桌面应用。下面给你一套覆盖UWP和非UWP场景的完整解决方案,每个步骤都给你讲清楚逻辑:

一、先理清楚核心问题

首先要明确:

  • AppInfo.get_from_app_user_model_id仅对UWP应用或用MSIX打包的桌面应用有效,传统exe安装的应用(Chrome、Firefox)没有对应的AppInfo记录,所以会报"Element not found"。
  • PackageManager只能枚举Windows部署模型下的包(UWP/MSIX),传统桌面应用不属于这个范畴,所以完全找不到。

因此我们需要做的是:优先用WinRT方法处理UWP应用,针对非UWP应用,通过Win32 API或注册表查询的方式 fallback。

二、分步实现解决方案

1. UWP应用:正确使用AppInfo的方法

先保留对UWP应用的支持,这部分你的代码本身是对的,我们把它封装成一个单独的函数,并且加入异常处理来触发后续的fallback:

from winsdk.windows.applicationmodel import AppInfo

def get_uwp_display_name(app_id):
    try:
        app_info = AppInfo.get_from_app_user_model_id(app_id)
        return app_info.display_name
    except OSError:
        # 非UWP应用,返回None让后续逻辑处理
        return None

2. 非UWP桌面应用:通过注册表+文件版本信息获取名称

传统桌面应用的source_app_user_model_id通常会在注册表中关联到其exe路径,我们可以通过这个路径再去获取应用的友好名称,具体分两步:

步骤1:从AppUserModelID找到对应exe路径

桌面应用的AppUserModelID会在注册表的HKCU\Software\Classes\AppUserModelId或HKLM\Software\Classes\AppUserModelId下有记录,我们可以从中解析出启动命令,进而提取exe路径。对于一些常见应用,还可以做硬编码的兜底。

步骤2:从exe路径获取友好名称

拿到exe路径后,我们有两种方式获取名称:

  • 查注册表HKCR\Applications\<exe_name>下的FriendlyAppName键
  • 读取exe文件本身的版本信息中的FileDescription

下面是完整的fallback实现(需要先安装pywin32:pip install pywin32):

import winreg
import shlex
import win32api
import win32con
import os

def get_desktop_app_display_name(app_id):
    exe_path = None

    # 尝试从注册表查找AppUserModelID对应的exe路径
    for hkey in [winreg.HKEY_CURRENT_USER, winreg.HKEY_LOCAL_MACHINE]:
        try:
            with winreg.OpenKey(hkey, f"Software\\Classes\\AppUserModelId\\{app_id}") as key:
                with winreg.OpenKey(key, r"Shell\Open\Command") as cmd_key:
                    cmd_value, _ = winreg.QueryValueEx(cmd_key, "")
                    # 解析带引号的启动命令,提取exe路径
                    exe_path = shlex.split(cmd_value)[0]
                    break
        except FileNotFoundError:
            continue

    # 注册表找不到的话,针对常见应用做硬编码兜底
    if not exe_path:
        app_id_lower = app_id.lower()
        if "chrome" in app_id_lower:
            exe_path = r"C:\Program Files\Google\Chrome\Application\chrome.exe"
            if not os.path.exists(exe_path):
                exe_path = r"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
        elif "firefox" in app_id_lower:
            exe_path = r"C:\Program Files\Mozilla Firefox\firefox.exe"
            if not os.path.exists(exe_path):
                exe_path = r"C:\Program Files (x86)\Mozilla Firefox\firefox.exe"

    if not exe_path or not os.path.exists(exe_path):
        return app_id  # 完全找不到的话,返回原始ID

    # 从exe路径获取友好名称
    try:
        # 先查注册表的FriendlyAppName
        exe_name = exe_path.split("\\")[-1]
        with winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, f"Applications\\{exe_name}") as app_key:
            friendly_name, _ = winreg.QueryValueEx(app_key, "FriendlyAppName")
            return friendly_name
    except FileNotFoundError:
        # 读取exe文件的版本信息
        try:
            file_version_info = win32api.GetFileVersionInfo(exe_path, "\\")
            # 获取语言和代码页
            lang, codepage = win32api.GetFileVersionInfo(exe_path, "\\VarFileInfo\\Translation")[0]
            str_info = f"\\StringFileInfo\\{lang:04x}{codepage:04x}\\FileDescription"
            return file_version_info[str_info]
        except Exception:
            # 终极兜底:返回不带扩展名的文件名
            return exe_path.split("\\")[-1].split(".")[0]

3. 整合通用函数

把UWP和非UWP的逻辑整合起来,形成一个可以直接调用的通用函数:

from winsdk.windows.applicationmodel import AppInfo
import winreg
import shlex
import win32api
import win32con
import os

def get_app_display_name(app_id):
    # 优先处理UWP应用
    uwp_name = get_uwp_display_name(app_id)
    if uwp_name:
        return uwp_name
    
    # 非UWP应用走fallback逻辑
    return get_desktop_app_display_name(app_id)

# 测试你的场景
if __name__ == "__main__":
    print(get_app_display_name("Chrome.AI6Y5TE6AH3DDYXV66D2XOWVLA"))  # 应该返回"Google Chrome"
    print(get_app_display_name("308046B0AF4A39CB"))  # 应该返回"Mozilla Firefox"

三、补充说明

  • 为什么PackageManager找不到Chrome/Firefox?因为PackageManager仅管理Windows部署模型下的包(UWP/MSIX),而Chrome、Firefox是传统exe安装的桌面应用,不属于这个体系,所以完全不会被枚举到。
  • 对于一些非常见的桌面应用,硬编码兜底可能不生效,但注册表查询的逻辑通常能覆盖大部分场景,因为正规的桌面应用都会注册AppUserModelID到注册表中。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 08:53:04