更多 Python 文章见《有容乃大(Python集萃)》专栏
如何在 Windows 上自动发现 Epic Games 已安装游戏及其运行信息:
- 通过注册表定位 Launcher 安装路径
- 定位、解析 JSON manifest 文件
- 从元数据中获取所需信息
整体架构
架构图
输入层
- 注册表:提供 Launcher 安装入口
发现层
get_install_path():定位 Launcher_get_manifests_path():定位 manifest
处理层
- 文件过滤(hex 文件名)
- JSON 解析
- 数据合法性校验
输出层
- games dict(核心 API)
- 单游戏详情(扩展 API)
核心流程
流程图
核心处理流程-循环执行:
- 扫描
.item文件 - 过滤非 hex 文件
- 解析 JSON
- 校验关键字段
- 构建 game_info
关键决策点
| 决策点 | 作用 |
|---|---|
| 注册表是否存在 | 是否 fallback |
| 文件名是否 hex | 是否为合法 manifest |
| InstallLocation 是否存在 | 防止脏数据 |
| exe 是否存在 | 是否可直接运行 |
核心实现拆解
配置 / 输入
数据结构
{
"appid": str,
"name": str,
"namespace": str,
"install_location": str,
"version": str,
"executable": Optional[str]
}
设计点:
| 设计点 | 原因 |
|---|---|
| 使用 dict | 灵活扩展字段 |
| appid 作为 key | 唯一标识 |
| executable 可选 | 并非所有游戏都有 |
核心处理模块
核心机制
文件系统扫描 → 过滤 → JSON解析 → 数据验证 → 输出
设计点
| 设计 | 目的 |
|---|---|
| hex 校验 | 避免误解析非游戏文件 |
| JSON 标准解析 | 简化实现 |
| 路径存在校验 | 防止卸载残留 |
| 分阶段处理 | 提高可维护性 |
核心代码解析
路径发现核心
get_install_path()核心代码
def get_install_path():
try:
with winreg.OpenKey(HKEY_LOCAL_MACHINE, REGISTRY_PATH) as key:
exe_path, _ = winreg.QueryValueEx(key, REGISTRY_VALUE)
exe_path = os.path.normpath(exe_path)
parts = exe_path.split(os.sep)
for i, part in enumerate(parts):
if part.lower() == "launcher":
install_path = os.sep.join(parts[:i+1])
if os.path.exists(install_path):
return install_path
except Exception:
pass
# fallback
for path in COMMON_INSTALL_PATHS:
if os.path.exists(path):
return path
return ""
从注册表获取到路径后,必须 os.path.exists() 再返回
if os.path.exists(install_path):
防御点:
- 注册表可能残留(卸载未清理)
- 路径可能失效
数据源定位
_get_manifests_path()核心代码
def _get_manifests_path():
data_path = os.path.expandvars(DATA_PATH_TEMPLATE)
manifests_path = os.path.join(data_path, MANIFESTS_SUBDIR)
if os.path.exists(manifests_path):
return manifests_path
return ""
过滤器设计
_is_hex_filename()核心代码
def _is_hex_filename(filename):
name, _ = os.path.splitext(filename)
if not name:
return False
try:
int(name, 16)
return True
except ValueError:
return False
| 方案 | 优点 | 缺点 |
|---|---|---|
| int(...,16) | 快 + 语义强 | 不直观 |
| regex | 可读性高 | 性能略低 |
主处理管线
get_installed_games()核心代码骨架
games = {}
for item_file in Path(manifests_path).glob("*.item"):
if not _is_hex_filename(item_file.name):
continue
data = json.load(...)
appid = data.get("CatalogItemId")
if not appid:
continue
install_location = data.get("InstallLocation")
if not os.path.exists(install_location):
continue
game_info = {...}
launch_exe = data.get("LaunchExecutable")
if launch_exe:
exe_path = os.path.join(install_location, launch_exe)
if os.path.exists(exe_path):
game_info["executable"] = exe_path
games[appid] = game_info
核心机制:Pipeline(流水线)
逐字段校验,逐字段 fail-fast,避免:
- manifest 不完整
- 卸载残留
- 手动篡改
install_location 必须存在,否则会出现:
- UI 显示“已安装”
- 实际已删除
总结
整个核心代码可以抽象为:
Environment Discovery
↓
Data Source Location
↓
File Filtering
↓
Structured Parsing
↓
Validation Pipeline
↓
Normalized Output