固定 window 到桌面/粘贴 window 到桌面/"Always-on-bottom" window

Pin window to desktop / Glue window to desktop / "Always-on-bottom" window

我正在使用 C++/Win32 开发一个基本的桌面应用程序。

我现在的目标是创建一个基本的“便利贴”应用程序,它将固定/粘贴到桌面,即总是在桌面前面但总是在桌面后面任何其他应用程序。 那里确实是一个个人项目,只是为了克服我的坏记忆,让我的 tasks/notes 始终在桌面上可见,这样我就不会在启动计算机等时错过它们。

我的目标行为类似于 Stardock Fences (“有点”,因为我不打算将任何桌面图标存储在在那里,但希望你能明白)

我从 sample code from the Get Started with Win32 and C++ docs 开始,以获得最基本的 Win32 最小 window 设置。

到目前为止我得到了什么:

  1. 通过在 window 过程中调用 SetWindowPos (WindowProc),我设法将我的 window 保持在所有其他应用程序的底部和桌面前面,在处理事件 WM_SETFOCUS 时(我首先尝试将事件 WM_WINDOWPOSCHANGING 作为 suggested in this answer 但这导致在拖动 window 时出现烦人的闪烁).
case WM_SETFOCUS:
        SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
        return 0;
  1. 问题:我的window停留在桌面前面除非我点击 在任务栏中的 “显示桌面” 按钮上(或点击 Windows + D 快捷方式)。因为我自己经常使用这个快捷方式,所以我希望我的 window 无论如何都保留在桌面上。
  2. 我设法做的一个不太令人满意但仍然存在的事情是,在点击 Windows + D (这对多台显示器很有意义,例如,在第一个显示器上打开一个随机应用程序,将在另一个屏幕上切换回桌面前我自己的应用程序). 这次我可以使用事件 WM_SIZE 并调用 ShowWindow 然后 SetWindowPos,仍然在 WindowProc
case WM_SIZE:
        ShowWindow(hwnd, SW_SHOWNORMAL);
        SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
        return 0;

虽然不理想,因为我真的希望我的应用程序始终保留在桌面前面并“存活”到“显示桌面”操作。

我试过的:

我查看了这些答案,但不知道如何实现我想要的。

  1. How to make 'always-on-bottom'-window
  2. Window “on desktop” :注意这个,我在 wWinMain
  3. 中尝试了 SetParent 这样的技巧
HWND desktop = FindWindow(L"ProgMan", L"Program Manager");
if (desktop == NULL)
{
    return 0;
}

ShowWindow(hwnd, nCmdShow);
SetParent(hwnd, desktop);

但是,即使 FindWindow 不是 return NULL 而是一个实际的句柄,我的应用程序再也看不到了。

  1. Make aplication always on Bottom (pinned to desktop, behind all other apps) in C++/WinAPI [duplicate]
  2. 我试过这些来“拦截”显示桌面事件,但似乎这个事件并没有被显示桌面操作触发。

我是不是漏掉了什么?

正如@JonathanPotter 指出的那样,当点击 Windows + D 或显示桌面按钮时,事件 WM_WINDOWPOSCHANGING 被触发,并且 window 被移动到 -32 000, -32 000 (它的大小也改变了)

注意:没有样式 WS_MINIMIZEBOX 的 window 在点击 Windows + D 时似乎没有收到 WINDOWPOSCHANGING 事件。因此,在那种情况下没有 -32 000 坐标检测......在使用 ex 样式 WS_EX_TOOLWINDOW 时也注意到了同样的问题(因为这个摆脱了最小化框,即使你设置了样式标志 WS_MINIMIZEBOX)。 没有找到针对这种情况的解决方案,所以我坚持使用重叠的 window.

要防止这种移动,只需在 lParam

中传递的 WINDOWPOS 结构上设置标志 SWP_NOMOVESWP_NOSIZE

因此,作为最终结果,要实现所需的行为 (即始终落后于其他 window 但始终位于桌面前面),唯一需要的代码添加到 doc's sample 的是以下内容,放在 window 过程 WindowProc 的 switch 语句中:

EDIT :使用 HWND_BOTTOM 强制 Z 顺序的最佳位置,从而确保 window 始终位于底部也在 WM_WINDOWPOSCHANGING 事件。事实上,当拖动 window 时,在 WM_SIZE 事件中调用 SetWindowPos 强制它,就像我之前所做的那样,在调整 window 大小时会导致一些闪烁,而WM_WINDOWPOSCHANGING.

WINDOWPOS结构直接设置hwndInsertAfter属性不闪烁
case WM_WINDOWPOSCHANGING:
{
    WINDOWPOS* pos = (WINDOWPOS*)lParam;
    // Show desktop (Windows + D) results in the window moved to -32000, -32000 and size changed
    if (pos->x == -32000) {
        // Set the flags to prevent this and "survive" to the desktop toggle
        pos->flags |= SWP_NOMOVE | SWP_NOSIZE;
    }
    // Also force the z order to ensure the window is always on bottom
    pos->hwndInsertAfter = HWND_BOTTOM;
    return 0;
}