昨天地平线6终于发售,作为尊贵的尊享版用户,可以享受提前游玩的高贵待遇,于是我提前几天就预载好,在上班的时候还特意远程回去解压,就为了第一时间能游玩,殊不知这是恶心人的开始。在经历了十多个小时的挣扎后,我终于进入了游戏,下面发点历程,要看解决方案可以直接前往最后一节。
游戏启动后,弹出一个弹窗

最早我根据网上的指引去做了如下操作:
重启电脑。
Windows Update。
Microsoft Store 检查更新。
Xbox App 更新。
Xbox App 修复工具。
卸载并重装 Gaming Services。
设置里对 Gaming Services 点“修复 / 重置”。
Steam 验证游戏完整性。
开加速器、关代理、换代理规则。
可以说世界范围内网上所有能搜到的方法我全都搜到了(这里点名表扬B站,全是加速器广告),然而毛用没有,其实最早就有端倪——我的 Gaming Services 本来就是最新的。
首先我注意到游戏根目录有一个 xgameruntime.dll,版本是 10.0.26100.6247,而系统目录里是 10.0.26100.8071,虽然都是 10.0.26100,于是手动将这个DLL替换掉,发现没用。
然后就要上点技术手段了,最早我用ProcMon抓一下游戏的访问路径,发现游戏会去查HKLM\SOFTWARE\Microsoft\GamingServices\ForceUseLocalServices这个注册表项,于是我手动将这个表项写为1,进入游戏,这次绕过了版本检测,但是卡在了“正在加载”,在这里我,我又尝试了一系列绕过这个加载的方法,花了差不多一个多小时未果,于是我还是决定找问题根源。
最表面的问题无非就是我们被这个版本检测拦住了,已知我们本机的这个dll是好的,那要么就是他游戏加载的DLL版本不对,要么就是他比对的版本不对,要么就是他程序压根就没写好。
从易到难,我们先去看看加载的DLL版本,这里我写了个脚本轮询FH6的进程模块,发现它确实加载了系统目录里的新版xgameruntime.dll,所以版本不对的可能性就基本排除了。顺带又查了一下Xbox / Gaming相关组件也来自系统目录。
接下来我换用ETW抓游戏启动事件,还顺带自己写了个解码工具,去抓TraceLogging事件,发现有个很关键的条目:
Microsoft.Gaming.Install / GameCoreInitService::Initialize
GameConfigHelper::GetGameConfigForProcess(callingProcess.get(), gameConfig)
hr=-2147023728
Microsoft.Gaming.GRTS Initialize
hr=-2147023728
storeId=
msaAppId=
titleId=0
pfn=Microsoft.ForteBaseGame_1.0.0.0_x64__8wekyb3d8bbwe
UseLocalServices=False
这个-2147023728 转成十六进制是0x80070490,根据HRESULT的定义,这个值可以拆成:
0x80070000 | 0x490 其中高16位代表这是个Win32错误码,低16位0x490就是这个错误码的具体值,换算成十进制是1168,查询WinError.h找到了这个错误码的定义:
#define ERROR_NOT_FOUND 1168L 也就是说,在这里压根不是 Gaming Services 版本旧,而是 Gaming Services 没能找到 FH6 的 GameConfig。
然后我就去检查 FH6 目录下的 MicrosoftGame.config,发现里面确实有 FH6 的 StoreId / MSAAppId / TitleId 等信息:
Identity: Microsoft.ForteBaseGame
Version: 1.0.0.0
StoreId: 9NR1R1XWLCNB
MSAAppId: 000000004CE146F7
TitleId: 7bf69384 顺便我还发现 MicrosoftGame.config 里列的 executable 不是实际启动的 forzahorizon6.exe,而是一些占位名字,还倒腾了半天尝试手动把这些东西链接上,但无果。
最关键的问题其实是这个.config压根没注册成功,于是我换用 Microsoft GDK 里的wdapp.exe,尝试手动注册这个.config 一开始它失败过几种错误。
最早报了个 0x80070002,因为 MicrosoftGame.config 里引用了游戏目录里没有的东西,我又自己硬造了一堆占位符,于是报了这个错:
0x80070005 也就是:
ACCESS DENIED 很显然,在注册过程中,某个环节访问了某个资源,但被拒绝了。
于是我拿ProcMon去抓 wdapp register,抓到了:
GamingServices.exe CreateFile D:\SteamLibrary\steamapps\common\ForzaHorizon6\MicrosoftGame.config ACCESS DENIED
Desired Access: Generic Read 用人话来讲,这是在说GamingServices.exe想读取MicrosoftGame.config,但被拒绝了。
然后查进程身份,发现:
GamingServices.exe -> NT AUTHORITY\SYSTEM 再查游戏目录 ACL,发现当时权限大概只有当前用户:
D:\SteamLibrary\steamapps\common\ForzaHorizon6
JMC的PC\JMC:(I)(OI)(CI)(F) 但是没有:
NT AUTHORITY\SYSTEM 换言之,我的用户能读游戏目录、Steam 能启动游戏。但 Gaming Services 是 SYSTEM 身份,它反而读不到这个 Steam 游戏目录里的 MicrosoftGame.config。
于是它拿不到 GameConfig,ETW 里就变成:
GameConfigHelper::GetGameConfigForProcess -> ERROR_NOT_FOUND
游戏居然把这个错误翻译成了“检测到无效的 Gaming Services”,误导性满分。
搞清楚问题的根因也就知道怎么修复了,给 FH6 目录和子文件补 SYSTEM 读取权限:
icacls "D:\SteamLibrary\steamapps\common\ForzaHorizon6" /grant "*S-1-5-18:(OI)(CI)(RX)"
补完以后,再跑:
wdapp register D:\SteamLibrary\steamapps\common\ForzaHorizon6
成功。
之后再抓 ETW,之前失败的地方变成成功:
Microsoft.Gaming.GRTS Initialize
hr=0
storeId=9NR1R1XWLCNB
msaAppId=000000004ce146f7
titleId=2079757188
pfn=Microsoft.ForteBaseGame_1.0.0.0_x64__8wekyb3d8bbwe
GRTSVersion=36.113.14003.0
UseLocalServices=False
然后游戏终于能进入,出现正常的初始设置界面,感恩。
先看游戏目录权限:
icacls "D:\SteamLibrary\steamapps\common\ForzaHorizon6"
如果输出里没有类似:
NT AUTHORITY\SYSTEM:(OI)(CI)(RX)
或者没有 SYSTEM 权限,那么可以试:
icacls "D:\SteamLibrary\steamapps\common\ForzaHorizon6" /grant "*S-1-5-18:(OI)(CI)(RX)"
然后重启 Steam / 重启游戏。
如果要更精确验证,可以看这个文件 SYSTEM 能不能读:
D:\SteamLibrary\steamapps\common\ForzaHorizon6\MicrosoftGame.config
最直接的 ProcMon 证据会是:
GamingServices.exe
CreateFile
...\MicrosoftGame.config
ACCESS DENIED
要来摊锅,至少就我这个问题来说,微软的锅有这几条:
游戏错误提示说的是 Gaming Services 版本旧,但真实原因是 Gaming Services 读不到游戏配置文件。
Gaming Services 明明可以在 ETW 里知道自己 ACCESS DENIED 或 GameConfig not found,但前台只给了一个误导性的“版本旧”。你实在懒得处理,把错误码原封不动地返到前端,也省得用户搁那猜报错。自己大箩筐,还误导归因,呃呃。
FH6 Steam 版依赖 MicrosoftGame.config 和 Gaming Services,但安装 / 修复脚本没有保证 SYSTEM 对游戏目录有读取权限。
直接原因在于 SYSTEM 对我D盘的Steam库没有读取权限,导致FH6的文件夹也没继承到SYSTEM权限,导致注册失败,导致游戏以为是Gaming Services版本旧。