Search code examples
c++windowswinapigdi

MSPaint-like app writing. How to do BitBlt right?


I'm writing now simple mspaint-like program in C++ using windows.h (GDI). For my program I need only pen tool. So, I need to store somewhere main window's picture (for ex. in memory HDC and HBITMAP) to draw it after in WM_PAINT message.

  1. When I first have to store window's HDC to my memory HDC and HBITMAP? In what message I should store window? For example, I think we can't do it in WM_CREATE because we have no window yet.

  2. What is the difference between PatBlt and BitBlt? What should I use for my app?

  3. How to copy window's HDC content to my memory HDC and Bitmap? I'm trying to do something like this:

        LPRECT lpRect;
        GetClientRect(hwnd, lpRect);
        width = lpRect->right - lpRect->left;
        height = lpRect->bottom - lpRect->top;
    
        HDC hDC = GetDC(hwnd);
        memoryDC = CreateCompatibleDC(hDC);
        memoryBitmap = CreateCompatibleBitmap(hDC, width, height);
        SelectObject(memoryDC, memoryBitmap);
        PatBlt(memoryDC, 0, 0, width, height, PATCOPY);
        ReleaseDC(hwnd, hDC);
    

But this don't work: program crashes.

  1. How to restore window in WM_PAINT after that?

  2. How to clear my window with white color?


Solution

  • 1: I would recommend you lazy load your off-screen canvas as late as possible. If you need it in WM_PAINT and you haven't created it yet, create it then. If you need it at the point someone begins drawing, create it then. If it exists when you need it, then use it.

    2: PatBlt fills a region of a bitmap using the device context's current brush. Brushes define patterns, which is why it's called PatBlt. BitBlt copies data from a source bitmap to a destination bitmap. You would use a BitBlt when you wanted to move the image from the off-screen bitmap to the frame buffer.

    3: The lpRect parameter of GetClientRect is an output parameter. That means you have to supply the memory. In this case, GetClientRect is trying to write the rectangle to a null pointer and causing the crash.

    RECT clientRect;
    GetClientRect(hwnd, &clientRect);
    width = clientRect.right - clientRect.left;
    height = clientRect.bottom - clientRect.top;