Steam Run UU远程(Windows版本)

small parking
目录

在 Linux 下通过 Steam/Proton 运行 UU远程(Windows版)完整指南

在steam中安装uu远程

steam - 库 - 添加非steam游戏

然后右键属性-目标改成下载的exe安装程序。

兼容性-使用特定兼容工具-proton Experimental

ps: 这里是通用步骤,后面是特定于uu远程的修复方法

然后这里安装后会卡住,原因就是后面的IPC通讯问题,强制停止即可。然后后面使用脚本启动的时候这里的兼容性取消掉,因为是启动shell脚本,不需要兼容启动。

问题背景

UU远程(网易 GameViewer)只有 Windows 版本,在 Linux 下需要通过 Steam 的 Proton 兼容层运行。但在实际使用中会遇到一个核心问题:GameViewerService 无法启动子进程,导致整个远程串流功能不可用。

错误现象

启动 UU远程后,查看日志会发现以下循环报错:

GetWinlogonPid: 0
GetWinlogonPid OpenProcess failed: 87
GetWinlogonPid result: 0
[RollingCounter::recordCrash] backoff delay:1

延迟不断翻倍:1s → 2s → 4s → 8s → 16s → 32s → 64s → 128s → 256s…

同时客户端日志持续报:

[IpcSvrProxy::onIpcServerCheckTimeout] check ipc server timeout

根本原因

GameViewerService 使用 GetWinlogonPid 函数查找 Windows 的 winlogon.exe 进程 PID,然后通过 CreateProcessAsUser API 在用户会话中启动 GameViewerServer.exeGameViewerHealthd.exe

Wine/Proton 环境中没有真实的 winlogon.exe 进程,导致:

  1. EnumProcesses 找不到 winlogon → PID 返回 0
  2. OpenProcess(0, ...) 失败,错误码 87(ERROR_INVALID_PARAMETER
  3. 子进程无法启动 → IPC 服务器不存在 → 客户端无限超时

修复方案

核心思路:创建一个最小的 winlogon.exe 桩程序,让 GameViewerService 能找到一个有效的进程 PID。

第一步:创建 winlogon.exe 桩程序

源代码

创建文件 winlogon_stub.c

#include <windows.h>

int main(void) {
    while(1) {
        Sleep(60000);
    }
    return 0;
}

这是一个最简单的 Windows 程序,启动后进入无限循环,每 60 秒休眠一次。它的唯一作用就是作为一个持续运行的进程,让 GameViewerService 的 GetWinlogonPid 能找到一个有效的 PID。

编译

需要安装 mingw-w64 交叉编译器:

# Ubuntu/Debian
sudo apt install gcc-mingw-w64

# Arch Linux
sudo pacman -S mingw-w64-gcc

# Fedora
sudo dnf install mingw64-gcc

编译命令:

x86_64-w64-mingw32-gcc -mwindows -static -o winlogon.exe winlogon_stub.c

参数说明:

  • x86_64-w64-mingw32-gcc:64 位 Windows 交叉编译器
  • -o winlogon.exe:输出文件名
  • -static:静态链接,不依赖额外的 DLL
  • -mwindows:把生成的 Windows 可执行文件标记为 Windows GUI 子系统(GUI subsystem),而不是 Console 子系统(CUI subsystem)。默认是 创建控制台窗口(cmd黑框)
安装到 Wine 前缀
# 设置前缀路径(根据你的实际路径修改)
PFX="$HOME/.local/share/Steam/steamapps/compatdata/4065807528/pfx"

# 复制到 system32 目录
cp winlogon.exe "$PFX/drive_c/windows/system32/winlogon.exe"

第二步:创建设备配置文件(可选)

GameViewer 启动时会读取设备标识配置,如果缺失会产生一些警告日志。可以创建配置文件消除这些警告。

PFX="$HOME/.local/share/Steam/steamapps/compatdata/4065807528/pfx"

# 生成 UUID
DEVICE_UUID=$(python3 -c "import uuid; print(uuid.uuid4())")
USER_UUID=$(python3 -c "import uuid; print(uuid.uuid4())")

# 创建配置目录
mkdir -p "$PFX/drive_c/ProgramData/Netease/GameViewer/config"

# 创建配置文件
cat > "$PFX/drive_c/ProgramData/Netease/GameViewer/config/device.ini" << EOF
[Device]
deviceId=$DEVICE_UUID
userId=$USER_UUID
uuid=$DEVICE_UUID
EOF

第三步:创建启动脚本

创建文件 start_uuremote.sh

#!/bin/bash
# UU Remote (GameViewer) 启动脚本 - 适用于 Steam/Proton 环境
# 修复 Wine 中缺少 winlogon.exe 导致服务无法启动子进程的问题
set -x
PFX="$HOME/.local/share/Steam/steamapps/compatdata/4065807528/pfx"
PROTON_DIR="/mnt/nvme/steamapps/common/Proton - Experimental"
PROTON="$PROTON_DIR/proton"

# 设置环境变量
export WINEPREFIX="$PFX"
export STEAM_COMPAT_DATA_PATH="$HOME/.local/share/Steam/steamapps/compatdata/4065807528"
export STEAM_COMPAT_CLIENT_INSTALL_PATH="$HOME/.local/share/Steam"
export DXVK_ASYNC=1
export WINEDLLOVERRIDES="dxva2=n;mfplat=n"
export LIBVA_DRIVER_NAME=radeonsi

WINEPREFIX=$HOME/.local/share/Steam/steamapps/compatdata/4065807528/pfx '/mnt/nvme/steamapps/common/Proton - Experimental/files/bin/wineserver'  -k

# 清理所有残留的 Wine/GameViewer 进程
pkill  -f "GameViewerService" 2>/dev/null
pkill  -f "GameViewerServer" 2>/dev/null
pkill  -f "GameViewerHealthd" 2>/dev/null
pkill  -f "crashpad_handler" 2>/dev/null
pkill  -f "winedevice.exe" 2>/dev/null
pkill  -f "xalia.exe" 2>/dev/null
killall wineserver 2>/dev/null
killall winlogon.exe
sleep 2

echo "[UU Remote] Starting winlogon.exe stub..."
"$PROTON" run "$PFX/drive_c/windows/system32/winlogon.exe" &
WINLOGON_PID=$!
echo "[UU Remote] winlogon.exe started with PID: $WINLOGON_PID"
echo sleep 2
sleep 2

echo "[UU Remote] Starting GameViewer..."
"$PROTON" run "$PFX/drive_c/users/steamuser/Desktop/UU远程.lnk" "$@" &> /tmp/gameviewer.log
EXIT_CODE=$?

echo "[UU Remote] GameViewer exited with code: $EXIT_CODE"
sleep 20

exit $EXIT_CODE

设置执行权限:

chmod +x start_uuremote.sh

路径说明

变量 说明 如何查找
PFX Wine 前缀目录 ~/.local/share/Steam/steamapps/compatdata/<APPID>/pfx
PROTON_DIR Proton 安装目录 Steam 库文件夹下的 common/Proton - Experimental
APPID Steam 应用 ID 在 Steam 中右键游戏 → 属性 → 更新 → 查看

查找 Proton wine 路径的方法:

# 查找 compatdata 目录
ls ~/.local/share/Steam/steamapps/compatdata/

# 查找 proton 脚本
find ~/.local/share/Steam/steamapps/common -name "proton" -type f

# 或者查找 wine 二进制
find ~/.local/share/Steam/steamapps/common -name "wine" -type f

使用方式

方式一:直接运行脚本

./start_uuremote.sh

方式二:在 Steam 中设置启动选项

在 Steam 中右键 UU远程 → 属性启动选项,输入:

bash $HOME/start_uuremote.sh

注意:不要加 %command%,因为脚本内部已经自己调用 proton 启动了。

方式三:创建桌面快捷方式

cat > ~/Desktop/UU远程修复版.desktop << 'EOF'
[Desktop Entry]
Name=UU远程修复版
Exec=bash $HOME/start_uuremote.sh
Type=Application
Icon=applications-games
Terminal=false
Categories=Network;RemoteAccess;
EOF

chmod +x ~/Desktop/UU远程修复版.desktop

验证修复是否成功

检查进程

ps aux | grep -i gameviewer

应该能看到以下进程都在运行:

  • GameViewerService.exe --service
  • GameViewerServer.exe
  • GameViewerHealthd
  • winlogon.exe(桩程序)

检查日志

查看服务日志,确认 GetWinlogonPid 不再返回 0:

# 找到最新的服务日志
ls -lt ~/.local/share/Steam/steamapps/compatdata/4065807528/pfx/drive_c/Program\ Files/Netease/GameViewer/log/service/Log/ | head -3

# 查看日志内容
cat ~/.local/share/Steam/steamapps/compatdata/4065807528/pfx/drive_c/Program\ Files/Netease/GameViewer/log/service/Log/log_最新文件.txt | grep -i winlogon

成功标志:

GetWinlogonPid: 288        # PID 不再是 0
GetWinlogonPid result: 1   # 成功
CreateProcessAsUser id:xxx  # 子进程成功启动

检查 IPC 超时

客户端日志中应该不再出现 check ipc server timeout 的循环。

已知限制

1. 硬件视频解码不可用

在 Wine/Proton 下,DXVA2/D3D11VA 硬件视频解码通常不可用,串流会使用软件解码。可以通过设置环境变量尝试启用:

export WINEDLLOVERRIDES="dxva2=n;mfplat=n"
export LIBVA_DRIVER_NAME=radeonsi  # AMD 显卡

2. 手柄支持有限

VigEmBus 驱动在 Wine 下无法安装,手柄模拟功能不可用。

3. 虚拟显示器驱动

虚拟显示器驱动可能无法正常工作,取决于具体的 Wine 版本和内核模块支持。

文件清单

修复完成后,涉及的文件:

文件 位置 说明
winlogon_stub.c 用户主目录 桩程序源代码(可删除)
winlogon.exe ~/ 和 Wine 前缀 system32/ 编译后的桩程序
start_uuremote.sh ~/ 启动包装脚本
device.ini Wine 前缀 ProgramData/Netease/GameViewer/config/ 设备配置(可选)

环境变量说明

变量 说明
WINEPREFIX 前缀路径 指定 Wine 前缀
STEAM_COMPAT_DATA_PATH compatdata 路径 Proton 兼容数据路径
STEAM_COMPAT_CLIENT_INSTALL_PATH Steam 路径 Steam 客户端安装路径
DXVK_ASYNC 1 启用 DXVK 异步编译,减少卡顿
WINEDLLOVERRIDES dxva2=n;mfplat=n 覆盖 DLL 加载顺序
LIBVA_DRIVER_NAME radeonsi AMD 显卡的 VA-API 驱动

完整文件内容

winlogon_stub.c

#include <windows.h>

int main(void) {
    while(1) {
        Sleep(60000);
    }
    return 0;
}

编译和安装一条命令

x86_64-w64-mingw32-gcc -o winlogon.exe winlogon_stub.c  -mwindows -static && \
cp winlogon.exe "$HOME/.local/share/Steam/steamapps/compatdata/4065807528/pfx/drive_c/windows/system32/winlogon.exe" && \
echo "安装完成"

start_uuremote.sh

#!/bin/bash
# UU Remote (GameViewer) 启动脚本 - 适用于 Steam/Proton 环境
# 修复 Wine 中缺少 winlogon.exe 导致服务无法启动子进程的问题
set -x
PFX="$HOME/.local/share/Steam/steamapps/compatdata/4065807528/pfx"
PROTON_DIR="/mnt/nvme/steamapps/common/Proton - Experimental"
PROTON="$PROTON_DIR/proton"

# 设置环境变量
export WINEPREFIX="$PFX"
export STEAM_COMPAT_DATA_PATH="$HOME/.local/share/Steam/steamapps/compatdata/4065807528"
export STEAM_COMPAT_CLIENT_INSTALL_PATH="$HOME/.local/share/Steam"
export DXVK_ASYNC=1
export WINEDLLOVERRIDES="dxva2=n;mfplat=n"
export LIBVA_DRIVER_NAME=radeonsi

WINEPREFIX=$HOME/.local/share/Steam/steamapps/compatdata/4065807528/pfx '/mnt/nvme/steamapps/common/Proton - Experimental/files/bin/wineserver'  -k

# 清理所有残留的 Wine/GameViewer 进程
pkill  -f "GameViewerService" 2>/dev/null
pkill  -f "GameViewerServer" 2>/dev/null
pkill  -f "GameViewerHealthd" 2>/dev/null
pkill  -f "crashpad_handler" 2>/dev/null
pkill  -f "winedevice.exe" 2>/dev/null
pkill  -f "xalia.exe" 2>/dev/null
killall wineserver 2>/dev/null
killall winlogon.exe
sleep 2

echo "[UU Remote] Starting winlogon.exe stub..."
"$PROTON" run "$PFX/drive_c/windows/system32/winlogon.exe" &
WINLOGON_PID=$!
echo "[UU Remote] winlogon.exe started with PID: $WINLOGON_PID"
echo sleep 2
sleep 2

echo "[UU Remote] Starting GameViewer..."
"$PROTON" run "$PFX/drive_c/users/steamuser/Desktop/UU远程.lnk" "$@" &> /tmp/gameviewer.log
EXIT_CODE=$?

echo "[UU Remote] GameViewer exited with code: $EXIT_CODE"
sleep 20

exit $EXIT_CODE