Reputation: 1
I have developed a C++ application that creates a watermark on the screen. The watermark is displayed correctly on the current desktop, but when I create a new virtual desktop using Windows 10's built-in virtual desktop feature, the watermark only appears on the first virtual desktop and does not carry over to the new ones.
I am using the Windows API to manage the watermark display and handle virtual desktop changes. Despite my efforts, the watermark doesn't appear on newly created virtual desktops.
Here's a simplified version of my code for displaying the watermark:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// Create a memory DC and bitmap for drawing
HDC memDC = CreateCompatibleDC(hdc);
if (!memDC) {
DebugOutput(L"Failed to create memory DC\n");
EndPaint(hWnd, &ps);
return 0;
}
HBITMAP memBitmap = CreateCompatibleBitmap(hdc, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top);
if (!memBitmap) {
DebugOutput(L"Failed to create compatible bitmap\n");
DeleteDC(memDC);
EndPaint(hWnd, &ps);
return 0;
}
HBITMAP oldBitmap = (HBITMAP)SelectObject(memDC, memBitmap);
// Create Graphics object
Graphics graphics(memDC);
// Fill the background with black color
graphics.Clear(BackgroundColor); // Black background
// Draw the watermark
std::wstring watermarkText = EnsureTextLength(GetWatermarkText());
DrawWatermarks(graphics, watermarkText, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top);
// Copy the memory DC to the screen DC
BitBlt(hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top, memDC, 0, 0, SRCCOPY);
// Cleanup
SelectObject(memDC, oldBitmap);
DeleteObject(memBitmap);
DeleteDC(memDC);
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
UnregisterVirtualDesktopNotification();
PostQuitMessage(0);
break;
case WM_DISPLAYCHANGE:
RefreshWatermarkWindows(hInst); // Refresh watermark windows on display change
break;
case WM_ACTIVATEAPP:
case WM_NEXTDLGCTL:
case WM_SHOWWINDOW:
SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
break;
case WM_VIRTUAL_DESKTOP_CHANGED:
RefreshWatermarkWindows(hInst); // Handle virtual desktop change
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
HWND CreateWatermarkWindow(HINSTANCE hInstance, RECT screenRect) {
HWND hWnd = CreateWindowExW(
WS_EX_LAYERED | WS_EX_NOACTIVATE | WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT, // Add WS_EX_TRANSPARENT here
szWindowClass,
szTitle,
WS_POPUP,
screenRect.left,
screenRect.top,
screenRect.right - screenRect.left,
screenRect.bottom - screenRect.top,
nullptr,
nullptr,
hInstance,
nullptr
);
// Set layered window attributes with black background and opacity
BYTE alpha = static_cast<BYTE>(OpacityLevel * 255); // Compute opacity
SetLayeredWindowAttributes(hWnd, RGB(0, 0, 0), alpha, LWA_COLORKEY | LWA_ALPHA);
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
windows.push_back(hWnd);
return hWnd;
}
void RefreshWatermarkWindows(HINSTANCE hInstance) {
// Destroy all existing windows
for (HWND hWnd : windows) {
DestroyWindow(hWnd);
}
// Ensure all messages related to destruction are processed
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
windows.clear(); // Clear the windows vector
// Create watermark windows for all monitors`your text`
EnumDisplayMonitors(NULL, NULL, [](HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) -> BOOL {
HINSTANCE hInstance = reinterpret_cast<HINSTANCE>(dwData);
CreateWatermarkWindow(hInstance, *lprcMonitor);
return TRUE;
}, reinterpret_cast<LPARAM>(hInstance));
}
I have tried listening to the WM_VIRTUAL_DESKTOP_CHANGED
message to detect when the user switches or creates a virtual desktop, but the watermark still doesn't appear on the new desktops.
Upvotes: 0
Views: 209
Reputation: 597941
You can use IVirtualDesktopManager::MoveWindowToDesktop()
to display a HWND on a specific virtual desktop.
The catch is that you need to know the ID of the desktop. If you had other windows already shown on the desktop, you could use IVirtualDesktopManager::GetWindowDesktopId()
to get that ID. But it sounds like you are not. So, you will have to resort to using the undocumented IVirtualDesktopManagerInternal::GetCurrentDesktop()
and IVirtualDesktop::GetId()
instead to get the ID of the currently active virtual desktop.
Just be aware that Virtual desktops are an end-user window management feature, not a programmatic one.
Upvotes: 0