Ghaith Saaa
Ghaith Saaa

Reputation: 1

How to display an application across all virtual desktops in a Windows application?

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

Answers (1)

Remy Lebeau
Remy Lebeau

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

Related Questions