Sliferslacker
Sliferslacker

Reputation: 43

GUI Window keeps closing when I minimize it

I created a window and made a rectangle on it. When i minimize my window the program crashes. I'm aware it's because when i minimize the buffer that the function used to create the rectangle is accessing memory outside of the buffer and that's why it keeps crashing.

So i tried to use a clamp function called limit() to keep the limits inside of the buffer. But no matter what i try it still crashes when i minimize the window. I copied my code below, i think the main problems are from somewhere in the limit() and draw_rect() function. When i don't run the draw_rect() function and just have the render_background(), my window works fine and doesn't collapse when minimized.

#include <windows.h>
#include <Memoryapi.h>
#include <stdio.h>
#pragma comment(lib, "Gdi32.lib")
#pragma comment(lib, "onecore.lib")

//global variables
bool run = true;
int width, height, buffer_memory_size;
void *memory;
BITMAPINFO BMINFO;

//function used to color background
void render_background()
{
     unsigned int *ptr = (unsigned int *)memory;

     for (int y = 0; y < height; y++)
     {
        for (int x = 0; x < width; x++)
        {
            *ptr = 0xff5500;

            ptr++;
        }
     }
}

//function used to keep draw_rect inside buffer 
void draw_rect(int x0, int y0, int x1, int y1, unsigned int color)
{   
    for (int y = limit(0,height - 1,y0); y <= limit(0,height - 1,y1); y++)
    {
        unsigned int *ptr = (unsigned int *)memory + y * width;

        for (int x = limit(0,width - 1,x0); x <= limit(0,width - 1,x1); x++)
        {
            ptr[x] = color;
        }
    }
}

//function used to draw rectangle
void draw_rect(int x0, int y0, int x1, int y1, unsigned int color)
{   
    for (int y = limit(0,height - 1,y0); y <= limit(0,height - 1,y1); y++)
    {
        unsigned int *ptr = (unsigned int *)memory + y * width;

        for (int x = limit(0,width - 1,x0); x <= limit(0,width - 1,x1); x++)
        {
            ptr[x] = color;
        }
    }
}

LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_DESTROY:
        run = false;
        return 0;

    case WM_SIZE:
        //obtain the new size of the window and the memory size of new needed buffer
        RECT R;
        GetClientRect(hwnd,&R);

        width = R.right - R.left;
        height = R.bottom - R.top;
        buffer_memory_size = width*height*sizeof(unsigned int); //buffer memory size in terms of bytes

        //allocate memory in the heap for new buffer
        if (memory != NULL)
        {
            VirtualFree(memory,0,MEM_RELEASE);
        }

        memory = VirtualAlloc(0, buffer_memory_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

        //update BMINFO with updated class members
        BMINFO.bmiHeader.biSize = sizeof(BMINFO.bmiHeader);
        BMINFO.bmiHeader.biWidth = width;
        BMINFO.bmiHeader.biHeight = height;
        BMINFO.bmiHeader.biPlanes = 1;
        BMINFO.bmiHeader.biBitCount = 32;
        BMINFO.bmiHeader.biCompression = BI_RGB;

        return 0;
    }
    
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    //create window class
    const wchar_t name[] = L"window class";

    WNDCLASS wc = {};

    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpszClassName = name;
    wc.lpfnWndProc = MainWndProc;

    //register window class
    RegisterClass(&wc);

    //create window and display window
    HWND H = CreateWindowExW(0, name, L"First Window", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 1280, 720, 0, 0, hInstance, 0);
    HDC hdc = GetDC(H);


    //game loop
    while (run)
    {   
        MSG msg;

        //input
        while (PeekMessage(&msg, H, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        //logic
        render_background();

        //drawing rectangle x0 = 400, x1 = 700, y0 = 300, y1 = 500  
        draw_rect(400,300,700,500,0xff00ff);


        //rendering
        StretchDIBits(hdc,0,0,width,height,0,0,width,height,memory,&BMINFO,DIB_RGB_COLORS,SRCCOPY);
    }

    return 0;
}

Upvotes: 0

Views: 165

Answers (1)

Ahmed AEK
Ahmed AEK

Reputation: 18297

when you minimize, GetClientRect returns {0,0,0,0}, which has a size of 0, and allocating a buffer of zero size fails and returns a nullptr

if you check GetClientRect remarks.

In conformance with conventions for the RECT structure, the bottom-right coordinates of the returned rectangle are exclusive. In other words, the pixel at (right, bottom) lies immediately outside the rectangle.

almost all drawing and coordinates in windows API assumes end is exclusive, you should follow this convention in your code to avoid similar bugs, therefore the following code is wrong

for (int y = y0; y <= y1; y++)

and should be

for (int y = y0; y < y1; y++)

which will correctly not try to write to a zero sized buffer.

Upvotes: 1

Related Questions