Painting Gremlins and weird bitblt stuff
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 11 of 11

Thread: Painting Gremlins and weird bitblt stuff

  1. #1
    Join Date
    Apr 2011
    Posts
    9

    Painting Gremlins and weird bitblt stuff

    So I'm trying to write a relatively basic blackjack programming for learning purposes. It seems like something really odd is happening when WM_PAINT is called. It works fine until I introduce an if statement. Doing a watch the correct values pass, it goes through the whole function, watch it hit BitBlt and nothing draws. Take out the if statement and it draws just fine.

    Code:
    case WM_PAINT:
    {			
    	PAINTSTRUCT ps;		
    	HDC hdc = BeginPaint(hwnd, &ps);			
    	DrawTable(hwnd, ps, hdc);
    	//if (cardsDealt > 0)
    		DrawCard(hwnd, ps, hdc);			
    	EndPaint(hwnd, &ps);
    	break;
    }
    
    case IDC_DEALBUTTON:
    {
    	cardsDealt = 1;
    	ShowWindow(hWndDealButton, SW_HIDE);
    }
    
    void DrawCard(HWND hwnd, PAINTSTRUCT ps, HDC hdc)
    {	
    	HDC hdcMem = CreateCompatibleDC(hdc);
    	BITMAP bm;
    	GetObject(cardbmp, sizeof(bm), &bm);
    	HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, cardbmp);
    	BitBlt(hdc, 0, 750, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
    	SelectObject(hdcMem, hbmOld);
    	DeleteDC(hdcMem);
    	EndPaint(hwnd, &ps);
    }
    I'm sure the code is probably sloppy as I'm pretty new to this, so any recommendations on that end would be appreciated as well, but mainly just trying to figure out why the BitBlt won't paint for me. Thanks in advance.
    Last edited by ovidiucucu; April 19th, 2011 at 04:06 AM. Reason: Added [CODE] tags

  2. #2
    Join Date
    Apr 1999
    Posts
    27,434

    Re: Painting Gremlins and weird bitblt stuff

    Quote Originally Posted by RasputinII View Post
    So I'm trying to write a relatively basic blackjack programming for learning purposes. It seems like something really odd is happening when WM_PAINT is called. It works fine until I introduce an if statement. Doing a watch the correct values pass, it goes through the whole function, watch it hit BitBlt and nothing draws. Take out the if statement and it draws just fine.
    One thing about your code:

    None of your code checks for errors when calling the Windows API functions. This is not a habit you should get into -- all of those functions, including BitBlt return values that denote whether there is an error or not.
    Code:
    	BitBlt(hdc, 0, 750, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
    What if BitBlt returned a failure? You should always check your API calls for success or failure. I once had to rewrite a mountain of code, because the original authors did not check for API error codes -- they assumed that every function was successful, which wasn't the case.

    Secondly, your problem is not just the if() statement. Look at what you're uncovering when that statement is removed. You're unconditionally calling the DrawCard() function every single time without any constraints. So right there, that is a huge difference.

    Regards,

    Paul McKenzie

  3. #3
    ovidiucucu's Avatar
    ovidiucucu is offline Moderator/Reviewer Power Poster
    Join Date
    Feb 2003
    Location
    Iasi - Romania
    Posts
    8,051

    Re: Painting Gremlins and weird bitblt stuff

    [ Moved thread ]

    Even the posted code isn't complete, I can bet that BitBlt returns 0 and a further call of GetLastError will return 6 ("The handle is invalid").

    That's because you are calling EndPaint before the painting is complete (in DrawTable which is called before DrawCard).

    Isn't it?
    Last edited by ovidiucucu; April 19th, 2011 at 04:53 AM.
    Ovidiu Cucu
    "When in Rome, do as Romans do."
    Visit: Microsoft Virtual Academy
    Follow: https://twitter.com/#!/ovidiucucu
    My blog: http://codexpert.ro/blog/author/ovidiu-cucu/

  4. #4
    Join Date
    Apr 2011
    Posts
    9

    Re: Painting Gremlins and weird bitblt stuff

    Yeah, the end paint thing I noticed once I posted and saw them right next to each other. Unfortunately cleaning that up didn't seem to fix anything.

    Paul:

    As far as the error checking, it's slightly over my head at this point. I understand what you mean, but honestly no idea where to begin at this point to work that into the code. Pretty much my first foray into c++ with just enough knowledge in java and vb to be dangerous.

    I'm not sure I follow what you mean as far as uncovering. The unconditional call was really just to make sure the code in the drawcard function was working properly, which it seems to. My bafflement is it's lack of working when introducing what seems like a relatively simple condition. More baffling *at least to me* is that it does indeed go through all the code with the condition, just no paint.

    Here's full code:

    Code:
    #include <windows.h>
    #include <algorithm>
    #include "resource.h"
    
    const char g_szClassName[] = "myWindowClass";
    
    HBITMAP cardbmp, table;
    HWND hwnd, hWndDealButton;
    PAINTSTRUCT ps;
    enum Value {ACE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING};
    enum Suit {CLUBS, DIAMONDS, HEARTS, SPADES};
    int cardsDealt = -1;
    
    
    class Card
    {
    public:	
    	Value value;
    	Suit suit;
    };
    
    Card *Deck;
    
    void Shuffle(const int SIZE)
    {
    	for (int i = 0; i < 7; i++)
    		std::random_shuffle(&Deck[0], &Deck[SIZE]);
    }
    
    void BuildDeck(const int SIZE)
    {	
    	Deck = new Card [SIZE];	
    	int count = 0;
    	Card aCard;
    	for (int i = 0; i < 13; i++)
    	{
    		for (int j = 0; j < 4; j++)
    		{
    			aCard.value = static_cast<Value>(i);
    			aCard.suit = static_cast<Suit>(j);
    			Deck[count] = aCard;
    			count++;
    		}
    	}
    	Shuffle(SIZE);
    }
    
    
    void DrawTable(HWND hwnd, PAINTSTRUCT ps, HDC hdc)
    {	
    	HDC hdcMem = CreateCompatibleDC(hdc);
    	BITMAP bm;
    	GetObject(table, sizeof(bm), &bm);
    	HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, table);
    	BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
    	SelectObject(hdcMem, hbmOld);
    	DeleteDC(hdcMem);
    }
    
    void DrawCard(HWND hwnd, PAINTSTRUCT ps, HDC hdc)
    {	
    	
    	HDC hdcMem = CreateCompatibleDC(hdc);
    	BITMAP bm;
    	GetObject(cardbmp, sizeof(bm), &bm);
    	HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, cardbmp);
    	BitBlt(hdc, 0, 750, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
    	SelectObject(hdcMem, hbmOld);
    	DeleteDC(hdcMem);	
    }
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
    	switch(msg)
    	{
    		case WM_CREATE:
    		{
    			cardbmp = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BACK));
    			table = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_TABLE));
    			BuildDeck(52);
    			if(cardbmp == NULL)
    				MessageBox(hwnd, "Could not load IDB_BACK!", "Error", MB_OK | MB_ICONEXCLAMATION);
    			hWndDealButton=CreateWindowEx(NULL, "BUTTON", "DEAL", WS_TABSTOP|WS_VISIBLE|WS_CHILD|BS_DEFPUSHBUTTON,550,
    										  800, 100,24, hwnd, (HMENU)IDC_DEALBUTTON, GetModuleHandle(NULL), NULL);
    			break;
    		}
    		case WM_CLOSE:
    			DestroyWindow(hwnd);
    			break;
    		case WM_COMMAND:
    			switch(LOWORD(wParam))
    			{
    				case IDC_DEALBUTTON:
    				{
    					cardsDealt = 1;
    					ShowWindow(hWndDealButton, SW_HIDE);
    				}
    			}
    		case WM_PAINT:
    		{			
    			PAINTSTRUCT ps;		
    			HDC hdc = BeginPaint(hwnd, &ps);			
    			DrawTable(hwnd, ps, hdc);
    			//if (cardsDealt > 0)
    				DrawCard(hwnd, ps, hdc);			
    			EndPaint(hwnd, &ps);
    			break;
    		}		
    		case WM_DESTROY:
    			DeleteObject(cardbmp);
    			PostQuitMessage(0);
    		break;
    		default:
    			return DefWindowProc(hwnd, msg, wParam, lParam);
    	}
    	return 0;
    }
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    	LPSTR lpCmdLine, int nCmdShow)
    {
    	WNDCLASSEX wc;
    	HWND hwnd;
    	MSG Msg;
    
    	wc.cbSize		 = sizeof(WNDCLASSEX);
    	wc.style		 = 0;
    	wc.lpfnWndProc	 = WndProc;
    	wc.cbClsExtra	 = 0;
    	wc.cbWndExtra	 = 0;
    	wc.hInstance	 = hInstance;
    	wc.hIcon		 = LoadIcon(NULL, IDI_APPLICATION);
    	wc.hCursor		 = LoadCursor(NULL, IDC_ARROW);
    	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    	wc.lpszMenuName  = NULL;
    	wc.lpszClassName = g_szClassName;
    	wc.hIconSm		 = LoadIcon(NULL, IDI_APPLICATION);
    
    	if(!RegisterClassEx(&wc))
    	{
    		MessageBox(NULL, "Window Registration Failed!", "Error!",
    			MB_ICONEXCLAMATION | MB_OK);
    		return 0;
    	}
    
    	hwnd = CreateWindowEx(
    		WS_EX_CLIENTEDGE,
    		g_szClassName,
    		"Blackjack",
    		WS_OVERLAPPEDWINDOW,
    		CW_USEDEFAULT, CW_USEDEFAULT, 1200, 900,
    		NULL, NULL, hInstance, NULL);
    
    	if(hwnd == NULL)
    	{
    		MessageBox(NULL, "Window Creation Failed!", "Error!",
    			MB_ICONEXCLAMATION | MB_OK);
    		return 0;
    	}
    
    	ShowWindow(hwnd, nCmdShow);
    	UpdateWindow(hwnd);
    
    	while(GetMessage(&Msg, NULL, 0, 0) > 0)
    	{
    		TranslateMessage(&Msg);
    		DispatchMessage(&Msg);
    	}
    	return Msg.wParam;
    }
    Thanks again.

  5. #5
    Join Date
    Apr 2011
    Posts
    9

    Re: Painting Gremlins and weird bitblt stuff

    Just to test it out, I tried the GetLastError() after the first EndPaint even though it's not supposed to be there. BitBlt is returning 1 and GetLastError returns 0, only furthering my confusion.

  6. #6
    Join Date
    Apr 2011
    Posts
    9

    Re: Painting Gremlins and weird bitblt stuff

    Paul, do you mean something like this?

    Code:
    if (BitBlt(.....)
    [INDENT]BitBlt(....)
    else
    [INDENT]*some sort of error message*

  7. #7
    Join Date
    Nov 2002
    Location
    California
    Posts
    4,553

    Re: Painting Gremlins and weird bitblt stuff

    You have two different variables for PAINTSTRUCT ps (one global and one local to WM_PAINT), but I doubt that such might be causing an issue.

    What is the return value for LoadBitmap on IDB_TABLE? You test for the return value on IBD_BACK but not on IDB_TABLE.

    Please also confirm that your most recently posted code behaves the same as in your initial post. In other words, soes the code "work fine" without the "if" statement? What does "work fine" mean as compared to not.

    Mike

  8. #8
    Join Date
    Apr 1999
    Posts
    27,434

    Re: Painting Gremlins and weird bitblt stuff

    Quote Originally Posted by RasputinII View Post
    Paul, do you mean something like this?

    Code:
    if (BitBlt(.....)
    [INDENT]BitBlt(....)
    else
    [INDENT]*some sort of error message*
    http://msdn.microsoft.com/en-us/libr...=vs.85%29.aspx
    Return Value

    If the function succeeds, the return value is nonzero.

    If the function fails, the return value is zero. To get extended error information, call GetLastError.
    Look at the section that says "Return Values". That is how you're supposed to use these functions. You call them, and a return value is sent back to you and you query it to make sure it returns success.

    So to answer your question, the code should have looked like this:
    Code:
    if ( BitBlt( whatever ) == 0 )
    {
         DWORD err = GetLastError( );  // this is the reason for the failure
        // do other stuff, because there is an error
    }
    else
    {
        // the function was successful
    }
    This is an example. Otherwise, you'll wind up with code that doesn't check for errors, and thereby you'll be executing code with the wrong assumption that things worked OK when they didn't.

    Regards,

    Paul McKenzie

  9. #9
    Join Date
    Apr 1999
    Posts
    27,434

    Re: Painting Gremlins and weird bitblt stuff

    Quote Originally Posted by RasputinII View Post
    Pretty much my first foray into c++ with just enough knowledge in java and vb to be dangerous.
    All of those languages you mentioned has the concept of functions and return values. As a matter of fact, there are very few computer languages that do not have this concept.

    When you use any API, library, third-party code, etc., and the documentation says "when you call this function, an error code is returned if something goes wrong", or "an exception is thrown on error", or similar wording, it is imperative you write code to check for these possible error conditions. If not, when your program dies on you for some reason, you won't know the reason.

    Regards,

    Paul McKenzie

  10. #10
    ovidiucucu's Avatar
    ovidiucucu is offline Moderator/Reviewer Power Poster
    Join Date
    Feb 2003
    Location
    Iasi - Romania
    Posts
    8,051

    Re: Painting Gremlins and weird bitblt stuff

    Ovidiu Cucu
    "When in Rome, do as Romans do."
    Visit: Microsoft Virtual Academy
    Follow: https://twitter.com/#!/ovidiucucu
    My blog: http://codexpert.ro/blog/author/ovidiu-cucu/

  11. #11
    Join Date
    Apr 2011
    Posts
    9

    Re: Painting Gremlins and weird bitblt stuff

    Thank you all for the tips, I really appreciate it. A lot easier to get into the habit earlier than later.

    As far as the drawing issue, it ended up being something pretty simple. Minimized and restored and there it was... I stuck an IvalidateRect() in the button code and it worked like a charm.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center