bugger
bugger

Reputation: 313

Why can't I replace BeginPaint() with ValidateRect()?

From my understanding, BeginPaint and EndPaint helps paint the screen and validates the rectangle that it paints, this also prevents WM_PAINT messages from being spammed since there will be no more invalid regions in the window.

With my understanding, I thought that theoretically speaking, if I were to use BitBlt() to paint the window in WM_CREATE, then use ValidateRect to Validate the entire client region, the code would work. However, I tried it and it doesn't, suggesting that there could be something possibly wrong with my understanding, or code. Could someone please explain to me where I went wrong?

Here is the code that I used, IDB_BITMAP1 can be replaced with any appropriate Bitmap. Do note the comment in WM_PAINT to reproduce the issue. Thanks for reading!

#include <windows.h>
#include "resource.h"

HBITMAP hBitMap = NULL;

LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_CREATE:
    {
        BITMAP infoBM;
        hBitMap = LoadBitmap(GetModuleHandle(NULL), IDB_BITMAP1);
        if (hBitMap == NULL)
        {
            MessageBoxA(NULL, "COULD NOT LOAD CAT BITMAP", "ERROR", MB_OK);
        }
        HDC winDC = GetDC(hwnd);
        HDC hMem = CreateCompatibleDC(winDC);
        GetObject(hBitMap, sizeof(infoBM), &infoBM);
        HBITMAP hMemOld = SelectObject(hMem, hBitMap);
        BitBlt(winDC, 0, 0, infoBM.bmWidth, infoBM.bmHeight, hMem, 0, 0, SRCCOPY);
        SelectObject(hMem, hMemOld);
        DeleteDC(hMem);
        ReleaseDC(hwnd,winDC);
        break;
    }
    case WM_PAINT: //<<<--------- I replaced the entire segment here with ValidateRect(hwnd,NULL);break; And the whole window doesnt show anymore, why is that so?
    {
        BITMAP infoBM;
        PAINTSTRUCT ps;
        HDC winDC = BeginPaint(hwnd, &ps);
        GetObject(hBitMap, sizeof(infoBM), &infoBM);
        HDC hMem = CreateCompatibleDC(winDC);
        HBITMAP hOldMem = SelectObject(hMem, hBitMap);
        BitBlt(winDC, 0, 0, infoBM.bmWidth, infoBM.bmHeight, hMem, 0, 0, SRCCOPY);
        SelectObject(hMem, hOldMem);
        DeleteObject(hMem);
        EndPaint(hwnd, &ps);
        break;
    }
    case WM_CLOSE:
        DestroyWindow(hwnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:return DefWindowProcA(hwnd, msg, wParam, lParam);
    }
return 0;
}

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevIstance, LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wc = { sizeof(WNDCLASSEX),0,WindowProc,0,0,hInstance,NULL,LoadCursor(NULL,IDC_ARROW),(HBRUSH)(COLOR_WINDOW+1),NULL,"WindowClass",LoadIcon(NULL,IDI_APPLICATION)};
    if (!RegisterClassEx(&wc))
    {
        MessageBoxA(NULL, "WINDOW REGISTRATION FAILED", "ERROR", MB_OK);
    }

    HWND hwnd = CreateWindowEx(WS_EX_LAYERED, "WindowClass", "Title", WS_POPUP, 200, 200, 300, 300, NULL, NULL, hInstance, NULL);
    if (!hwnd)
    {
        MessageBoxA(NULL, "WINDOW CREATION FAILED", "ERROR", MB_OK);
    }

    ShowWindow(hwnd, SW_SHOW);
    UpdateWindow(hwnd);

    if (!SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), 255, LWA_ALPHA))
    {
        MessageBoxA(NULL, "WINDOW LAYERED ATTRIBUTES FAILED", "ERROR", MB_OK);
    }

    MSG msg;
    while (GetMessage(&msg, hwnd, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}

Upvotes: 2

Views: 183

Answers (1)

YangXiaoPo-MSFT
YangXiaoPo-MSFT

Reputation: 2130

Typically,

You use the GetDC function to carry out drawing that must occur instantly rather than when a WM_PAINT message is processing.

And if you'd like, you can ValidateRect the entire client area instead of real painting when a WM_PAINT message is processing.
The following code is adapted from the thread.

LRESULT CALLBACK MyWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static int i = 0;
    switch (message)
    {
    case WM_PAINT:
    {
        if (i++ < 100)
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);

            RECT rect;
            GetClientRect(hWnd, &rect);
            COLORREF clrbak = SetBkColor(hdc, RGB(255, 0, 0));
            ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);

            int x = (rect.right - rect.left) / 8;
            int y = (rect.bottom - rect.top) / 8;
            rect.left += x; rect.right -= x;
            rect.top += y; rect.bottom -= y;
            SetBkColor(hdc, RGB(0, 255, 0));
            ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);



            rect.left += x; rect.right -= x;
            rect.top += y; rect.bottom -= y;
            SetBkColor(hdc, RGB(0, 0, 255));
            ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);

            rect.left += x; rect.right -= x;
            rect.top += y; rect.bottom -= y;
            SetBkColor(hdc, RGB(0, 0, 0));
            ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);

           SetBkColor(hdc, clrbak);
            EndPaint(hWnd, &ps);
        }
        else
        {
            ValidateRect(hWnd,NULL);
        }
    }
    break;
    case WM_ERASEBKGND:
        return 1;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

Upvotes: 1

Related Questions