Thread: Strange graphical effects, and memory leaks. Help!

  1. #1
    Registered User
    Join Date
    Aug 2009
    Posts
    3

    Question Strange graphical effects, and memory leaks. Help!

    As a beginner of C++, I have made a Windows application that fails. You control a line with w, a, s, and d respectively, however the line flashes and sometimes makes permanent paint on the window.

    A couple things to note:
    My comments are just code snippets with handy functions and whatnot.
    Resizing the window will reset the strangely permanent paint.
    The application must have memory leaks because when checking a process manage you can see memory usage rising infinitely.
    Because of these memory leaks, the line slows down in movement speed, therefore the entire program is slowing down.

    Could I ask for someone to help me seal the memory leaks and provide some tips on how to manage window painting better?

    Code:
    #include <windows.h>
    #include <windef.h>
    #include <stdlib.h>
    #include <string.h>
    #include <tchar.h>
    #include <stdio.h>
    #include <math.h>
    
    HBRUSH foregroundbrush = CreateSolidBrush(RGB(255, 255, 255));
    HBRUSH backgroundbrush = CreateSolidBrush(RGB(255, 255, 255));
    
    static TCHAR szWindowClass[] = _T("win32app");
    static TCHAR szTitle[] = _T("Win32 Guided Tour Application");
    HINSTANCE hInst;
    
    RECT background;
    
    int windowwidth = 1000;
    int windowheight = 500;
    
    int mf = 0x57;
    int mb = 0x53;
    int ml = 0x44;
    int mr = 0x41;
    
    double mx = 100;
    double my = 100;
    double ma = 0;
    
    int test = 0;
    
    void Line (HDC _hdc, int x1, int y1, int x2, int y2, int w)
    {
    
    	MoveToEx(_hdc, x1, y1, NULL);
        LineTo(_hdc, x2, y2);
    	int i = 1;
    	while(i < w)
    	{
    		MoveToEx(_hdc, x1 + i, y1, NULL);
    		LineTo(_hdc, x2 + i, y2);
    		MoveToEx(_hdc, x1, y1 + i, NULL);
    		LineTo(_hdc, x2, y2 + i);
    		MoveToEx(_hdc, x1 - i, y1, NULL);
    		LineTo(_hdc, x2 - i, y2);
    		MoveToEx(_hdc, x1, y1 - i, NULL);
    		LineTo(_hdc, x2, y2 - i);
    		i++;
    	}
    }
    
    /*
    
    hdc = GetDC(hwnd);					//hdc is handle to device context
    x = LOWORD(lParam);					//Store the current x 
    y = HIWORD(lParam);					//Store the current y
    if (wParam & MK_LBUTTON)			//If Left mouse button is down then draw
    {	
    	Line(hdc, lastx, lasty, x, y);		//Draw the line frome the last pair of coordiates to current
    	lastx = x;						//The current x becomes the lastx for next line to be drawn
    	lasty = y;						//The current y becomes the lasty for next line to be drawn
    }
    ReleaseDC(hwnd, hdc);
    
    */
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        PAINTSTRUCT ps;
        HDC hdc;
    	//const RECT *background = {0, 0, 1000, 500};
    	/*background->left = 0;
    	background->top = 0;
    	background->right = windowwidth;
    	background->bottom = windowheight;*/
    	if(GetAsyncKeyState(ml) < 0)
    	{
    		ma = ma + 0.001;
    	}
    	if(GetAsyncKeyState(mr) < 0)
    	{
    		ma = ma - 0.001;
    	}
    	if(GetAsyncKeyState(mf) < 0)
    	{
    		mx = mx + (0.1 * cos(ma));
    		my = my + (0.1 * sin(ma));
    	}
    	if(GetAsyncKeyState(mb) < 0)
    	{
    		mx = mx - (0.1 * cos(ma));
    		my = my - (0.1 * sin(ma));
    	}
    	/*if(test == 0)
    	{
    		test = 1;
    	} else
    	{
    		test = 0;
    	}*/
        switch (message)
        {
        case WM_PAINT:
            BeginPaint(hWnd, &ps);
    		GetWindowRect(hWnd , &background);
    		hdc = GetDC(hWnd);
    		//backgroundbrush = CreateSolidBrush(RGB(255 * test, 255 * test, 255 * test));
    		FillRect(hdc, &background, backgroundbrush);
    		//int FillRect(HDC hDC, CONST RECT *lprc, HBRUSH hbr);
    		//FillRectangle(
    		Line(hdc, (int)mx, (int)my, (int)(mx + (10 * cos(ma))), (int)(my + (10 * sin(ma))), 3);
    		InvalidateRect(hWnd , &background, true);
    		UpdateWindow(hWnd);
            EndPaint(hWnd, &ps);
    		break;
        case WM_DESTROY:
            PostQuitMessage(0);
    		break;
    	case WM_MOUSEMOVE:
    		break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        return 0;
    }
    
    int WINAPI WinMain(HINSTANCE hInstance,
                       HINSTANCE hPrevInstance,
                       LPSTR lpCmdLine,
                       int nCmdShow)
    {
        WNDCLASSEX wcex;
    
        wcex.cbSize			= sizeof(WNDCLASSEX);
        wcex.style          = CS_HREDRAW | CS_VREDRAW;
        wcex.lpfnWndProc    = WndProc;
        wcex.cbClsExtra     = 0;
        wcex.cbWndExtra     = 0;
        wcex.hInstance      = hInstance;
        wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
        wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
        wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
        wcex.lpszMenuName   = NULL;
        wcex.lpszClassName  = szWindowClass;
        wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
    
        if (!RegisterClassEx(&wcex))
        {
            MessageBox(NULL, _T("Call to RegisterClassEx failed!"), _T("Win32 Guided Tour"), NULL);
            return 1;
        }
    
        hInst = hInstance;
    
        HWND hWnd = CreateWindow(
            szWindowClass,
            szTitle,
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, CW_USEDEFAULT,
            windowwidth, windowheight,
            NULL,
            NULL,
            hInstance,
            NULL
        );
    
        if (!hWnd)
        {
            MessageBox(NULL, _T("Call to CreateWindow failed!"), _T("Win32 Guided Tour"), NULL);
    
            return 1;
        }
    
        ShowWindow(hWnd, nCmdShow);
        UpdateWindow(hWnd);
    
        MSG msg;
        while (GetMessage(&msg, NULL, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    
        return (int) msg.wParam;
    }
    main.cpp, compiled with Visual C++ 2008 Express Edition

  2. #2
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    You call GetDC() but you never call ReleaseDC()
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  3. #3
    Registered User
    Join Date
    Aug 2009
    Posts
    3
    I tried that out and it works rather perfectly, thanks a ton!

    Any idea why it flickers? Should I have a system of ticks to only reset on a tick?
    I suppose I am referring to frames per second, in which time must be accounted for.

  4. #4
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by bwackwat View Post
    I tried that out and it works rather perfectly, thanks a ton!

    Any idea why it flickers? Should I have a system of ticks to only reset on a tick?
    I suppose I am referring to frames per second, in which time must be accounted for.
    The flickering is caused by clearing the window to the background color on every frame. You see GDI drawing events as they happen -- there is no double buffering. The solution is to blast the entire updated window to the screen in a single piece. To do this, create a memory DC which is compatible with the window DC, draw onto that, then transfer the whole thing in one fell swoop using BitBlt().

    Also, your call to UpdateWindow() is redundant, since you are already calling InvalidateRect(). InvalidateRect() will cause WIndows to generate a WM_PAINT automatically (although it does wait until the message queue is empty).

    EDIT: As far as frames per second, this can be a factor, but I suspect your flicker is due to the lack of double buffering more so than frame tearing.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  5. #5
    Registered User
    Join Date
    Aug 2009
    Posts
    3
    Interesting...

    I've been messing around with BitBlt and have gotten it running the application similar to how it ran before, with the moving unit...

    However it seems that the issue was double buffering and frame tearing because the flickering continues.

    Also, when I switch to another program it is as if the application lost its window, and begins to paint across the entire screen causing all kinds of graphical tearing to occur.

    I suppose that this is because my application does not handle user-focus of any kind...

    ----------->I will be researching.

    Code:
    			GetWindowRect(hWnd , &background);
    
    			phdc = GetWindowDC(hWnd);
    			whdc = CreateCompatibleDC(phdc);
    
    			FillRect(phdc, &background, backgroundbrush);
    			Line(phdc, (int)mx, (int)my, (int)(mx + (10 * cos(ma))), (int)(my + (10 * sin(ma))), 3);
    
    			BeginPaint(hWnd, &ps);
    
    			BitBlt(phdc, 0, 0, 1000, 500, whdc, 0, 0, SRCCOPY);
    			InvalidateRect(hWnd , &background, true);
    			EndPaint(hWnd, &ps);
    			ReleaseDC(hWnd, phdc);
    Any thoughts?

  6. #6
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    I have posted code recently for buffering paint and how this should be done.

    To stop the flickering;

    try handling WM_ERASEBKGND msgs

    and don't ask for the background to be erased so frequently, let the OS handle that.

    Code:
    InvalidateRect(hWnd , &background, false);
    EDIT:
    InvalidateRect() //send the app a WM_PAINT msg
    UpdateWindow() // post the WM_PAINT directly to the window's callback, not to the OS queue.

    Your code is calling for another WM_PAINT while processing a WM_PAINT msg, which then is calling for another WM_PAINT while processing a WM_PAINT msg, which then is calling for another WM_PAINT while processing a WM_PAINT msg, which then is calling for another WM_PAINT while processing a WM_PAINT msg, which then is calling for another WM_PAINT while processing a WM_PAINT msg etc.....
    Last edited by novacain; 08-08-2009 at 01:51 AM.
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

Popular pages Recent additions subscribe to a feed

Tags for this Thread