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

如何在Qt/C++中实现桌面固定窗口并阻止Win+D最小化?

在Windows 11下用Qt/C++实现桌面固定底层窗口(不受Win+D影响)

核心思路

Rainmeter这类工具的本质是将窗口嵌入到系统桌面的WorkerW容器窗口中,而非单纯设置“始终底层”。直接用Qt窗口标志或普通SetWindowPos无法绕过Win+D的行为——因为Win+D会隐藏所有顶层窗口,而WorkerW是桌面的一部分,嵌入其中的窗口会和桌面一起保留。

具体实现步骤

1. 获取WorkerW窗口句柄

系统桌面由Progman窗口管理,触发Win+D时,Progman会创建WorkerW作为桌面图标和壁纸的容器。我们需要找到正确的WorkerW句柄:

#include <windows.h>
#include <QDesktopWidget>

HWND getWorkerWHandle() {
    HWND progman = FindWindow(L"Progman", nullptr);
    // 发送特殊消息触发WorkerW创建
    SendMessageTimeout(progman, 0x052C, 0, 0, SMTO_NORMAL, 1000, nullptr);

    HWND workerW = nullptr;
    HWND window = FindWindowEx(nullptr, nullptr, L"WorkerW", nullptr);
    // 遍历找到带有桌面图标的WorkerW的下一个容器
    while (window) {
        HWND shelldll = FindWindowEx(window, nullptr, L"SHELLDLL_DefView", nullptr);
        if (shelldll) {
            workerW = FindWindowEx(nullptr, window, L"WorkerW", nullptr);
            break;
        }
        window = FindWindowEx(nullptr, window, L"WorkerW", nullptr);
    }
    return workerW;
}

2. 配置Qt窗口属性与样式

初始化窗口时,设置合适的标志避免被系统当作顶层窗口处理:

#include <QMainWindow>

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
    // 无边框、作为子窗口嵌入,同时保留底层标志
    setWindowFlags(Qt::FramelessWindowHint | Qt::SubWindow | Qt::WindowStaysOnBottomHint);
    // 允许透明背景(如果需要)
    setAttribute(Qt::WA_TranslucentBackground, true);
    setStyleSheet("background-color: rgba(0,0,0,0);");
    // 适配桌面全屏大小
    QDesktopWidget* desktop = QApplication::desktop();
    setGeometry(desktop->screenGeometry());
}

其中Qt::SubWindow是关键,它让Qt窗口以子窗口形式存在,后续设置父窗口为WorkerW时才能生效。

3. 将Qt窗口嵌入WorkerW

必须在窗口显示后执行(此时才会生成有效HWND句柄),重写showEvent:

void MainWindow::showEvent(QShowEvent *event) {
    QMainWindow::showEvent(event);
    HWND workerW = getWorkerWHandle();
    if (workerW) {
        HWND hwnd = reinterpret_cast<HWND>(winId());
        // 将Qt窗口设置为WorkerW的子窗口
        SetParent(hwnd, workerW);
        // 强制窗口置于桌面图标下方
        SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
    }
}

4. 拦截窗口隐藏消息(可选)

部分场景下需监听系统消息,防止窗口被意外隐藏,重写nativeEvent:

bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, qintptr *result) {
    MSG* msg = static_cast<MSG*>(message);
    if (msg->message == WM_WINDOWPOSCHANGING) {
        WINDOWPOS* wp = reinterpret_cast<WINDOWPOS*>(msg->lParam);
        // 禁止窗口被隐藏
        if (wp->flags & SWP_HIDEWINDOW) {
            wp->flags &= ~SWP_HIDEWINDOW;
            *result = 0;
            return true;
        }
    }
    return QMainWindow::nativeEvent(eventType, message, result);
}

为什么之前的方法无效?

  • Qt::WindowStaysOnBottomHint:Windows系统中,顶层窗口的层级会被WorkerW覆盖,单纯设置底层无法让窗口嵌入桌面容器。
  • SetWindowPos(HWND_BOTTOM):仅调整顶层窗口层级,Win+D会隐藏所有顶层窗口,因此无效。
  • SetParent到桌面:直接设置父窗口为GetDesktopWindow()无效,因为桌面窗口并非真正的桌面容器,Win+D依然会隐藏它。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 09:55:09