如何在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
相关产品推荐
相关产品推荐

