Alex Kindel
Alex Kindel

Reputation: 173

scaling GDI draw size to window size with Win32

I'm writing a Win32 application, and am trying to get the sizes of windows to scale consistently with the things I draw in them. As a simplest possible case, I'm trying to create a window with a drawn rectangle in it that exactly fills the window.

The documentation for CreateWindow() says the width and height parameters are in device units, while the documentation for Rectangle() says the width and height parameters are in logical coordinates, which I assume means they're measured in logical units. I thought setting a POINT struct with the length and width I use to create a window, passing the POINT through DPtoLP(), then using the resulting x and y values as the width and height of my rectangle should work, but the rectangle ends up being bigger than the window. In fact, the discrepancy seems to be exactly the same as when I don't try to translate the window dimensions at all before I use them for the rectangle. Where am I going wrong? The full test program I'm using:

POINT logicalUnitSize;

LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
    _In_opt_ HINSTANCE hPrevInstance,
    _In_ LPWSTR    lpCmdLine,
    _In_ int       nCmdShow)
{
    WNDCLASS wc{};
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszClassName = L"Main";
    RegisterClass(&wc);

    POINT deviceUnitSize{ 200,200 };//width and height of window in device units

    HWND hwnd = CreateWindow(wc.lpszClassName, L"Size Test", WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, deviceUnitSize.x, deviceUnitSize.y, nullptr, nullptr, hInstance, nullptr);

    //get width and height of window in logical units
    HDC hdc{ GetDC(hwnd) };
    logicalUnitSize = deviceUnitSize;
    DPtoLP(hdc, &logicalUnitSize, 1);

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    MSG msg;
    while (GetMessage(&msg, 0, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return (int)msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc{ BeginPaint(hWnd, &ps) };
        Rectangle(hdc, 0, 0, logicalUnitSize.x, logicalUnitSize.y);
        EndPaint(hWnd, &ps);
        break;
    }
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

Upvotes: 1

Views: 1871

Answers (1)

Sijmen Mulder
Sijmen Mulder

Reputation: 5819

I believe the main issue here is that the size parameters to CreateWindow are for the non-client area, that is, including decorations like the title bar and border.

Use GetClientRect after creating the window to get the client area, or use AdjustWindowRect[Ex].

Upvotes: 2

Related Questions