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

Unity容器窗口改为重叠窗口后行为异常,如何修复?

问题

我用Unity开发游戏,程序包含主窗口和可停靠窗口。有多块屏幕的情况下,把部分子窗口拖到其他屏幕后,切换回Unity主窗口时,这些子窗口总会跑到其他应用窗口的前面,这不是我想要的效果。

通过Spy++查到这些子窗口带有WS_POPUP和WS_EX_TOOLWINDOW样式,于是写了以下代码尝试修改:

EnumWindows(FindUnityWindows, NULL);

以及回调函数:

BOOL CALLBACK FindUnityWindows(HWND hwnd, LPARAM lParam)
{
    char class_name[80];

    GetClassName(hwnd, class_name, sizeof(class_name));
    int processid = GetWindowThreadProcessId(hwnd, NULL);


    if (!strcmp(class_name, "UnityContainerWndClass"))
    {
        long style = GetWindowLong(hwnd, GWL_STYLE);
        style |= WS_OVERLAPPED;
        style &= ~(WS_POPUP);

        long exstyle = GetWindowLong(hwnd, GWL_EXSTYLE);
        exstyle |= WS_EX_APPWINDOW;
        exstyle &= ~(WS_EX_TOOLWINDOW);

        ShowWindow(hwnd, SW_HIDE);
        SetWindowLong(hwnd, GWL_STYLE, style);
        SetWindowLong(hwnd, GWL_EXSTYLE, exstyle);
        ShowWindow(hwnd, SW_SHOW);
    }

    return TRUE;
}

Spy++显示窗口样式已经修改成功,但实际行为没变化:任务栏里没有这些子窗口的标签,而且激活主窗口时子窗口还是会前置。请问还有什么办法能解决这个问题?

解决方案建议

  • 调整窗口所有者与Z序:调用SetWindowLongPtr将子窗口的所有者设置为Unity主窗口,所有者窗口和子窗口的Z序绑定逻辑和父窗口不同,能避免子窗口自动前置:
    // 先获取Unity主窗口的HWND,可通过查找窗口标题或类名实现
    SetWindowLongPtr(hwnd, GWLP_HWNDPARENT, (LONG_PTR)unityMainHwnd);
    SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
    
  • 替换Win32 API调用:将SetWindowLong换成SetWindowLongPtr,确保64位环境下样式修改真正生效:
    LONG_PTR style = GetWindowLongPtr(hwnd, GWL_STYLE);
    style |= WS_OVERLAPPED;
    style &= ~(WS_POPUP);
    SetWindowLongPtr(hwnd, GWL_STYLE, style);
    
    LONG_PTR exstyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
    exstyle |= WS_EX_APPWINDOW;
    exstyle &= ~(WS_EX_TOOLWINDOW);
    SetWindowLongPtr(hwnd, GWL_EXSTYLE, exstyle);
    
  • 拦截窗口激活消息:子类化子窗口,拦截WM_ACTIVATE消息,当主窗口激活时阻止子窗口自动获得焦点或前置:
    LRESULT CALLBACK SubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
    {
        if (uMsg == WM_ACTIVATE && LOWORD(wParam) == WA_ACTIVE)
        {
            // 返回FALSE阻止默认激活行为
            return FALSE;
        }
        return DefSubclassProc(hwnd, uMsg, wParam, lParam);
    }
    // 在找到子窗口后调用SetWindowSubclass进行子类化
    
  • 适配Unity自身逻辑:Unity可能在运行时重新覆盖窗口样式,建议在Unity的窗口初始化回调(比如EditorWindow的OnEnable)中注入修改代码,或者使用Unity内置的窗口层级控制API,而非直接修改Win32窗口属性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 01:50:20