Layered window size bigger than the size of the contents

145 views Asked by At

I want to create a layered window, the size of which is bigger than the size of its contents (hdcSrc). So that the window is for example 900x900, and we can place a 300x300 image inside of it anywhere we want, while the rest of the window is transparent.

Here is my code so far:

#include <Windows.h>
#include <string>

#include <objidl.h>
#include <gdiplus.h>
using namespace Gdiplus;
#pragma comment( lib, "Gdiplus.lib" )

HWND hwnd;

int screenWidth = GetSystemMetrics(SM_CXSCREEN);
int screenHeight = GetSystemMetrics(SM_CYSCREEN);

void updateTestWindow();

LRESULT CALLBACK windowProcedure(HWND hwnd, UINT message,
    WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    default:
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
}

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, INT iCmdShow)
{
    MSG msg;

    // GDI+ elements
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;

    // Initialize GDI+.
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    // Register Window Class

    WNDCLASS testWindowClass;

    testWindowClass.lpszClassName = TEXT("TestWindow");
    testWindowClass.hInstance = hInstance;
    testWindowClass.style = CS_HREDRAW | CS_VREDRAW;
    testWindowClass.lpfnWndProc = windowProcedure;
    testWindowClass.hIcon = 0;
    testWindowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    testWindowClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    testWindowClass.cbClsExtra = 0;
    testWindowClass.cbWndExtra = 0;
    testWindowClass.lpszMenuName = NULL;

    RegisterClass(&testWindowClass);

    // Create a layered window

    hwnd = CreateWindowEx(
        WS_EX_LAYERED,
        TEXT("TestWindow"), // window class name
        TEXT("TestWindow"), // window caption
        WS_POPUP,           // window style
        0,      // initial x position
        0,      // initial y position
        screenWidth,                    // initial x size
        screenHeight,                   // initial y size
        NULL,               // parent window handle
        NULL,               // window menu handle
        hInstance,          // program instance handle
        NULL);              // creation parameters

    ShowWindow(hwnd, iCmdShow);

    
    // Update the layered window using a custom function
    updateTestWindow();




    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}


void updateTestWindow()
{
    // Let's imagine that in reality we are drawing an image, but to test it, just draw a rectangle
    int imageWidth = 300;
    int imageHeight = 300;

    HDC screenDC = GetDC(NULL);

    // Create a DC for drawing
    HDC drawingDC = CreateCompatibleDC(screenDC);

    // Create a new bitmap for drawing on it
    HBITMAP newBitmap = CreateCompatibleBitmap(screenDC, imageWidth, imageHeight);

    // Select the new bitmap to draw on it and save the old one
    HBITMAP oldBitmap = (HBITMAP)SelectObject(drawingDC, newBitmap);

    // Create graphics object
    Graphics graphics(drawingDC);

    // Draw a rectangle
    Pen redPen(Color(255, 255, 0, 0), 15);
    Rect windowRect(0, 0, imageWidth, imageWidth);
    graphics.DrawRectangle(&redPen, windowRect);

    // The position of the layered window
    POINT windowPosition = { 0, 0 };
    
    // The size of the layered window   
    SIZE windowSize = { imageWidth, imageHeight };    // <----------------------------------!!!!

    POINT drawingDCPosition = { 0,0 };

    // Create a blend function
    BLENDFUNCTION blend = { 0 };
    blend.BlendOp = AC_SRC_OVER;
    blend.SourceConstantAlpha = 255;
    blend.AlphaFormat = AC_SRC_ALPHA;

    // Call UpdateLayeredWindow
    UpdateLayeredWindow(hwnd, screenDC, &windowPosition, &windowSize,
        drawingDC, &drawingDCPosition, 0, &blend, ULW_ALPHA);

    // Clean up
    SelectObject(drawingDC, oldBitmap);
    DeleteObject(newBitmap);
    DeleteDC(drawingDC);
    ReleaseDC(NULL, screenDC);
}

This creates a window that is exactly the size of the image that's drawn on it. We can reduce the window size: SIZE windowSize = { imageWidth-100, imageHeight-100 }; and the window will be drawn as expected - smaller size, while the image is the same size but now it's clipped (in this case, the rectangle is clipped).

However, if we want to achieve what I described in the beginning, SIZE windowSize = { imageWidth+100, imageHeight+100 }; doesn't work. The window is just not rendered at all, yet it opens (window taskbar icon is visible).

I probably just can't understand how a layered window works completely yet, which is why I can't understand why in this example it's not being rendered.

Is it possible to create such a layered window at all? And if yes, then how?

Or maybe this is not something I should be doing at all?

Just as a note: The reason I want to do this, is to use the layered window as a sort of an overlay, that would constantly be the size of the screen but the images, figures and text would be drawn on to it, updated, moved and so on.

0

There are 0 answers