Public Group

# "C++" double buffering mess

This topic is 2871 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

hy , im pretty new to the windows programing, i was tying to implement some sort of bitmap double buffering (dont know why , anyway bitmaps are not loaded directly to the screen as far as i'm aware but anyway).

My problem is that the BackBuffer::Present function doesn't output the bitmap onto the correct coords (of the client window) but instead i think it outputs onto another window's DC(hunch).here is my code , il appreciate if someone can tell me what i'v missed and maybe give me some "code formating tip" or tip of any sort thanks in advance.

P.S: the window is can not be resized ,and this is supposed to be just a trivial emplementation in training purposes.

//BackBuffer.h
#pragma once
#include <windows.h>
const int ciSwidth=600; //<---window size
const int ciSheight=600; //<---window size

class BackBuffer
{
public:
HDC bbDC;
HBITMAP hBmp;
HWND hWindow;
HBITMAP hBBsurface;
int iBBWidth; //<--the loaded bmp's size
int iBBHeight; //<--the loaded bmp's size
BackBuffer(HWND hWindow);
~BackBuffer();
void Present(int x, int y);
void Load(int iBmpID, HINSTANCE ghAppInst,int iWidth,int iHeight);//<--loads the bmp onto the babkbuffer,iBmpId is the resource.h image's id
};

//BackBuffer.cpp
#include "BackBuffer.h"

HDC hWndDC;
BackBuffer::BackBuffer(HWND hWindow)
{
this->hWindow=hWindow;
HDC hWndDC=GetDC(hWindow);
bbDC = CreateCompatibleDC(hWndDC);
ReleaseDC(hWindow, hWndDC);
}

BackBuffer::~BackBuffer()
{
SelectObject(bbDC, hBmp);
DeleteDC(bbDC);
}

void BackBuffer::Load(int iBmpID,HINSTANCE ghAppInst,int iWidth,int iHeight)
{
this->iBBWidth=iWidth;
this->iBBHeight=iHeight;
(HBRUSH)::GetStockObject(WHITE_BRUSH);
Rectangle(bbDC,0,0,ciSwidth,ciSheight);
/*BITMAP oldBM = */(HBITMAP)SelectObject(bbDC, hBBsurface);
}

void BackBuffer::Present(int x, int y)
{
HDC hWndDC=GetDC(hWindow);
BitBlt(hWndDC,x,y,x+iBBWidth,y+iBBHeight,bbDC,0,0,SRCCOPY);
ReleaseDC(hWindow,hWndDC);
}

//WinMain.cpp
#include "BackBuffer.h"

BackBuffer *Buffer=NULL;
HINSTANCE ghAppInst=0;
HWND hWindow=0;
RECT rClientRect;

bool InitMainWindow();
int Run();
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR cmdLine, int showCmd)
{
ghAppInst = hInstance;
if( !InitMainWindow() )
{
MessageBox(0, "Window Creation Failed.", "Error", MB_OK);
return 0;
}
return Run();
}

bool InitMainWindow()
{
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = ghAppInst;
wc.hbrBackground = (HBRUSH)::GetStockObject(NULL_BRUSH);
wc.lpszClassName = "MyWndClassName";
RegisterClass( &wc );
hWindow = ::CreateWindow("MyWndClassName","Anim", WS_OVERLAPPED | WS_SYSMENU,200, 200, ciSwidth, ciSheight, 0,0, ghAppInst, 0);
//char a[10];
//MessageBox(hWindow,itoa((int)hWindow,a,10)," ",IDOK);
if(hWindow == 0)
{
::MessageBox(0, "CreateWindow - Failed", 0, 0);
return false;
}
ShowWindow(hWindow, SW_NORMAL);
UpdateWindow(hWindow);
return true;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_CREATE:
//GetClientRect(hWindow,&rClientRect);
//char a[10];
//MessageBox(hWindow,itoa(rClientRect.bottom,a,10)," ",IDOK);
Buffer= new BackBuffer(hWindow);
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}

int Run()
{
//GetClientRect(hWindow,&rClientRect);
//char a[10];
//MessageBox(hWindow,itoa(rClientRect.right,a,10)," ",IDOK);
MSG msg;
ZeroMemory(&msg, sizeof(MSG));
while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else

{
Buffer->Present(rClientRect.left,rClientRect.left);//if i put 0,0 the image is suposed to be in the top left corner of the window , instead it shown in the left top corner of the desktop
Sleep(200);
}

}
return 0;
}

##### Share on other sites
Try using the source tags so we can see your code formatted well etc. Real hard to read as it is!

##### Share on other sites
Or, to make your life much easier just use a 3rd party library like SDL

-me

##### Share on other sites
Ok, here are all 3 files in source tags. Took me roughly a minute. I've included my own commentary in form of comments.

//BackBuffer.h#pragma once#include <windows.h>/* The meaning of these constants could have been more meaningful. For example:const int WND_WIDTHconst int WND_HEIGHTIt's a common convention to make constants in all caps. Besides, why do you need these? You store them in the back buffer anyway so just pass them as an argument to the constructor */const int ciSwidth=600; //<---window sizeconst int ciSheight=600; //<---window size/* Since you are using a class, the general idea behind the design of these is to abstract the functionality so that the user doesn't have to deal with it. Ifyou're going to make everything fully available, the purpose of having one is eliminated. You could have used a struct and that would've spared you the public: statement at the least. Frankly, none of the variables are needed to bepublic, unless they are often needed outside, but, in the given example, this isn't the case. Make your variables private and let the class handle everything on it's own. */class BackBuffer{public:	// from here	HDC bbDC;	HBITMAP hBmp;	HWND hWindow;	HBITMAP hBBsurface;	int iBBWidth; //<--the loaded bmp's size	int iBBHeight; //<--the loaded bmp's size	// to here should be private. All the rest is public	BackBuffer(HWND hWindow);	~BackBuffer();	void Present(int x, int y); // Why does this function take x and y arguments?/* This function seems impractical. It's better to load the bitmap somewhere else and let the BackBuffer handle the drawing with a single function. */	void Load(int iBmpID, HINSTANCE ghAppInst,int iWidth,int iHeight);//<--loads the bmp onto the babkbuffer,iBmpId is the resource.h image's id};//BackBuffer.cpp#include "BackBuffer.h"HDC hWndDC; /* <-- why is this here? */BackBuffer::BackBuffer(HWND hWindow){/* There is no need to use this-> over here. Why is the argument the same name as the member variable? Change this. Append an m to the member hWindow or something so you can distinguish it from the arguments. */	this->hWindow=hWindow;/* I cannot believe you haven't got a compile error for this. This variable is defined right outside of this function. Programming is like a ninja -.- You think you know it, and it strikes you when you least expect it. */	HDC hWndDC=GetDC(hWindow);/* Now what is your program supposed to do? You've got two of the same variables redefined and now you're trying to use them. That doesn't seem safe */	bbDC = CreateCompatibleDC(hWndDC);	ReleaseDC(hWindow, hWndDC);}BackBuffer::~BackBuffer(){/* Why are you selecting hBmp into the backbuffer before deleting it? */	SelectObject(bbDC, hBmp);	DeleteDC(bbDC);}void BackBuffer::Load(int iBmpID,HINSTANCE ghAppInst,int iWidth,int iHeight){/* Again, this-> is not necessary here. I'm beginning to think that you would want to create a Back Buffer for all images separately which isn't the idea behind a back buffer */	this->iBBWidth=iWidth;	this->iBBHeight=iHeight;	(HBRUSH)::GetStockObject(WHITE_BRUSH); /* What? Where does that brush go? */	Rectangle(bbDC,0,0,ciSwidth,ciSheight);	hBBsurface=LoadBitmap(ghAppInst,MAKEINTRESOURCE(iBmpID)); 	/*BITMAP oldBM = */(HBITMAP)SelectObject(bbDC, hBBsurface); /* Unfinished? */}void BackBuffer::Present(int x, int y){/* The same mistake. Have you compiled this yet? I cannot believe this went through a compiler without problems. This variable is defined in a global scope and it's redefined in 2 places. O.o?! */	HDC hWndDC=GetDC(hWindow);/* The 3rd and 4th arguments to BitBlt are the width and height of the bitmap to be drawn, not the x and y of the bottom right corner. This is drawing the bitmap into oblivion depending what x, y, iBBWidth, and iBBHeight are. Take out the x+ and y+ and leave the width and height on their own. */	BitBlt(hWndDC,x,y,x+iBBWidth,y+iBBHeight,bbDC,0,0,SRCCOPY);	ReleaseDC(hWindow,hWndDC);}//WinMain.cpp#include "BackBuffer.h"BackBuffer *Buffer=0;HINSTANCE ghAppInst=0; HWND hWindow=0;	RECT rClientRect; bool InitMainWindow(); /* <-- Why does this exist? Just merge it with WinMain or at least put it all the way at the bottom. *//* Put these two functions up here. There is no reason why they should be on the bottom. You do not need access to WinMain or the InitMainWindow functions therefore they only create superfluous code that you have to skip over in order to get to the cogs and wheels of your program. This isn't helping you, it's only slowing you down. Replace these two up here. */int Run();LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR cmdLine, int showCmd){	ghAppInst = hInstance;	if( !InitMainWindow() )	{		MessageBox(0, "Window Creation Failed.", "Error", MB_OK);		return 0;	}	return Run();}bool InitMainWindow(){	WNDCLASS wc;	wc.style = CS_HREDRAW | CS_VREDRAW;	wc.lpfnWndProc = WndProc;	wc.cbClsExtra = 0;	wc.cbWndExtra = 0;	wc.hInstance = ghAppInst;	wc.hIcon = ::LoadIcon(0, IDI_APPLICATION);	wc.hCursor = ::LoadCursor(0, IDC_ARROW);	wc.hbrBackground = (HBRUSH)::GetStockObject(NULL_BRUSH);	wc.lpszMenuName = 0;	wc.lpszClassName = "MyWndClassName";	RegisterClass( &wc );	hWindow = ::CreateWindow("MyWndClassName","Anim", WS_OVERLAPPED | WS_SYSMENU,200, 200, ciSwidth, ciSheight, 0,0, ghAppInst, 0);	//char a[10];	//MessageBox(hWindow,itoa((int)hWindow,a,10)," ",IDOK);	if(hWindow == 0)	{		::MessageBox(0, "CreateWindow - Failed", 0, 0);		return false;	}	ShowWindow(hWindow, SW_NORMAL);	UpdateWindow(hWindow);	return true;}LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){	switch (msg)	{	case WM_DESTROY:		PostQuitMessage(0);		return 0;	break;	case WM_CREATE:		//GetClientRect(hWindow,&rClientRect);		//char a[10];		//MessageBox(hWindow,itoa(rClientRect.bottom,a,10)," ",IDOK);		Buffer= new BackBuffer(hWindow);	break;	}	return DefWindowProc(hWnd, msg, wParam, lParam);}int Run(){	//GetClientRect(hWindow,&rClientRect);	//char a[10];	//MessageBox(hWindow,itoa(rClientRect.right,a,10)," ",IDOK);	MSG msg;	ZeroMemory(&msg, sizeof(MSG));	while(msg.message != WM_QUIT)	{		if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))		{			TranslateMessage(&msg);			DispatchMessage(&msg);		}		else		{			Buffer->Load(101,ghAppInst,200,200);/* Look into the BackBuffer implementations and fix everything. I'm willing to bet that the problem is there */			Buffer->Present(rClientRect.left,rClientRect.left);//if i put 0,0 the image is suposed to be in the top left corner of the window , instead it shown in the left top corner of the desktop			Sleep(200);		}	}		return 0;}

Everything that I could find that looks fishy I've pointed out with /* */ style comments. They appear in gray in the above source listing. Good luck fixing it :D

##### Share on other sites
Put a break point in the WM_CREATE handler and check the value of the global variable hWindow. I think that the problem you're talking about is caused by the fact that hWindow is NULL at that time. The global hWindow is being filled with the value returned by CreateWindow() but the WM_CREATE handler will get called before CreateWindow() returns. Use the local hWnd in there instead.

Anyway, this code has lots of problems. You should be handling WM_PAINT and blitting from the offscreen buffer there, shouldn't be sleeping in the message loop, etc. If it's any help I talk about doing this sort of thing at the end of this thread from a couple of weeks ago.

##### Share on other sites
off-topic:

It can does largely improve code quality when instead of

const int ciSwidth=600; //<---window size

you give meaningful, non-encrypted/-mnenomic names for all your entities:

const int windowWidth=600;

Don't use comments when the same a better effect can be achieved by meaningful names.

##### Share on other sites
Quote:
 Original post by boogyman19946Ok, here are all 3 files in source tags. Took me roughly a minute. I've included my own commentary in form of comments.*** Source Snippet Removed ***Everything that I could find that looks fishy I've pointed out with /* */ style comments. They appear in gray in the above source listing. Good luck fixing it :D

Thank vm for the effort, how did u do that? :))

##### Share on other sites
Quote:
 Original post by phresneloff-topic:It can does largely improve code quality when instead of*** Source Snippet Removed ***you give meaningful, non-encrypted/-mnenomic names for all your entities:*** Source Snippet Removed ***Don't use comments when the same a better effect can be achieved by meaningful names.

true , i commented to be clear for the eventual code reader, but thats a very good piece of advice , thanks

##### Share on other sites
Quote:
 Original post by boogyman19946Ok, here are all 3 files in source tags. Took me roughly a minute. I've included my own commentary in form of comments.*** Source Snippet Removed ***Everything that I could find that looks fishy I've pointed out with /* */ style comments. They appear in gray in the above source listing. Good luck fixing it :D

P.S i understand what you mean in those comments. Here is my point of view , why i did things like that:

1) the redefinition of the Window's DC: iv read in... Microsoft - Programming Windows API 5th
that a Dc should be released right after you did the operations with it (painting or in this example creating a compatible dc) lots of resources lost otherwise.

2) the actual redefinition of the same DC : "HDC hwndDC" since i get the dc again and again for every function it made no sense to make it global , so i defined it in the functions, and since it's local when the function ends , it goes out of scope , thats why that was redifined that way.

3) the splitting of the window cration process and message handling into functions: i did that because my programing is still very messy (im sure you figured that out already :P )and it makes things a little more clear , when a certain task is performed by appropriate function (at least for me).

4)the Prototypes in win main: I gues it was in K&R that was said that it's a good habit to write the actual functions at the end of the cpp file (and i believed it with no other questions asked , like ppl read the bible :p)

5) oh and the encapsulation problem, i got lazy and i didnt make functions for returning the private data so i made all data public, by bad.

6) and that thing compiles , builds and even outputs the right thing... but in the wrong place

##### Share on other sites
Quote:
 Original post by jwezorekPut a break point in the WM_CREATE handler and check the value of the global variable hWindow. I think that the problem you're talking about is caused by the fact that hWindow is NULL at that time. The global hWindow is being filled with the value returned by CreateWindow() but the WM_CREATE handler will get called before CreateWindow() returns. Use the local hWnd in there instead.Anyway, this code has lots of problems. You should be handling WM_PAINT and blitting from the offscreen buffer there, shouldn't be sleeping in the message loop, etc. If it's any help I talk about doing this sort of thing at the end of this thread from a couple of weeks ago.

that sounds the most reasonable thing i heard so far (not only here , but everywhere i asked)
,that went throw my mind also (like a hunch as i said in the post) il try fixing that up .

("Anyway, this code has lots of problems." told ya its not a real application, i'm learning)

thanks

• 10
• 17
• 9
• 13
• 41