I'm working on a basic desktop app in C++ / Win32.
My goal right now is to create a basic "sticky note" app that would be pinned / glued to the desktop, i.e always in front of the desktop but always behind of any other application. Really a personal project there, just to fight my bad memory and have my tasks/notes always visible on the desktop so I couldn't miss them when starting the computer & so on.
The behaviour I'm aiming for would be similar to Stardock Fences ("kind of" because I'm not going to store any desktop icon in there, but you hopefully get the idea)
I started with the sample code from the Get Started with Win32 and C++ docs to have the most basic Win32 minimal window setup.
What I got so far :
SetWindowPos
in the window procedure (WindowProc
), when handling the event WM_SETFOCUS
(I first tried with the event WM_WINDOWPOSCHANGING
as suggested in this answer but this resulted in an annoying flickering when dragging the window).case WM_SETFOCUS:
SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
return 0;
Windows + D
shortcut). As I often use this shortcut myself, I'd like my window to stay over the desktop no matter what.WM_SIZE
and calling ShowWindow
then SetWindowPos
, still in the WindowProc
case WM_SIZE:
ShowWindow(hwnd, SW_SHOWNORMAL);
SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
return 0;
Not ideal though, as I'd really want my app to always remain in front of the desktop and "survive" to the Show Desktop action.
What I tried :
I checked out those answers but couldn't figure out how to achieve what I want.
SetParent
like this in the wWinMain
HWND desktop = FindWindow(L"ProgMan", L"Program Manager");
if (desktop == NULL)
{
return 0;
}
ShowWindow(hwnd, nCmdShow);
SetParent(hwnd, desktop);
However, my app isn't visible at all anymore with this, even though the FindWindow
didn't return NULL
but an actual handle.
Did I miss something ?
As @JonathanPotter pointed out, when hitting Windows + D
or the Show Desktop button, the event WM_WINDOWPOSCHANGING
gets fired, and the window gets moved to -32 000, -32 000
(its size also gets changed)
NOTE : a window without the style WS_MINIMIZEBOX
seems not receiving WINDOWPOSCHANGING
event when hitting Windows + D. Thus, no -32 000 coordinates detection in that case... Also noticed the same issue when using the ex style WS_EX_TOOLWINDOW
(as this one gets rid of the minimize box, even if you set the style flag WS_MINIMIZEBOX
).
Didn't find a solution for that case, so I'm sticking to an overlapped window.
To prevent this movement, just set the flags SWP_NOMOVE
and SWP_NOSIZE
on the WINDOWPOS
structure passed in the lParam
So as a final result, to achieve the wanted behaviour (i.e always behind every other window but always in front of the desktop), the only needed code to add to the doc's sample is the following, placed in the window procedure WindowProc
's switch statement :
EDIT : the best place to force the Z order with HWND_BOTTOM
thus ensuring the window is always on bottom is also in the WM_WINDOWPOSCHANGING
event. Indeed, calling SetWindowPos
to force it in the WM_SIZE
event when dragging the window over, as I was doing previously, causes some flickering on the window when resizing it, whereas no flickering occurs when setting directly the hwndInsertAfter
property of the WINDOWPOS
structure in WM_WINDOWPOSCHANGING
.
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;
}