C Board  

Go Back   C Board > General Programming Boards > Game Programming

Reply
 
LinkBack Thread Tools Display Modes
Old 07-10-2005, 11:54 AM   #1
Epo
Registered User
 
Join Date: Jun 2003
Posts: 361
My Window Class

Hey all,

I wrote a sort of wrapper class for creating a skeleton window. I'll post the code first, and then discuss it:

Main.cpp
Code:
#define WIN32_LEAN_AND_MEAN

#include <Windows.h>
#include "cWindow.h"

//PROTOTYPE FOR OUR MISC. MESSAGE HANDLING FUNCTION
long __stdcall MessageProc(HWND hWnd, unsigned int Msg, WPARAM wParam, LPARAM lParam);

//OUR MAIN ENTRY POINT
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
	MSG Msg;	//RECEIVES OUR MESSAGES
	bool bRunning;	//KEEPS TRACK OF WHETHER WE'RE STILL RUNNING OR NOT

	cWindow* MainWindow;		//OUR WINDOW OBJECT
	MainWindow = new cWindow;	//CREATE THE WINDOW OBJECT

	//INITIALIZE OUR WINDOW
	bRunning = MainWindow->Init((HBRUSH)GetStockObject(LTGRAY_BRUSH), &hInstance, &MessageProc, CS_OWNDC, WS_POPUP, 200, 300);

	if(bRunning == true) //IF WE SUCCEEDED
	{
		//ACTIVATE THE WINDOW
		MainWindow->FocusOnMe();
		MainWindow->ShowMe();
		MainWindow->UpdateMe();

		while(bRunning == true) //MAKE SURE WE'RE STILL RUNNING
		{
			if(PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE) != 0) //DO WE HAVE ANY MESSAGES WAITING
			{
				//CHECK WHAT THE MESSAGE IS
				//
				//IT IS EASIER TO MANIPULATE OUR VARIABLES (bRunning, MainWindow, etc.)
				//BY KEEPING THE MESSAGE HANDLER OUT HERE
				switch(Msg.message)
				{
				case WM_KEYDOWN:		//A KEY WAS PRESSED
					bRunning = false;	//EXIT
				default:
					TranslateMessage(&Msg);	//CONVERT OUR VIRTUAL-KEY MESSAGE INTO A CHARACTER MESSAGE
					DispatchMessage(&Msg);	//SEND THE MESSAGE TO OUR MISC. MESSAGE HANDLER
				}
			}
			else
			{
				//THERE WAS NO MESSAGE
				//
				//UPDATE THE WINDOW
				MainWindow->UpdateMe();
			}
		}
	}

	//DESTROY OUR WINDOW
	bRunning = MainWindow->Kill(&hInstance);

	//CLEAN UP THE OBJECT
	delete MainWindow;
	MainWindow = NULL;

	return 0;
}

//long __stdcall MessageProc()
//
//THIS FUNCTION HANDLES ANY MESSAGES PASSED TO IT BY DispatchMessage()
//THAT WERE NOT HANDLED IN OUR WinMain() FUNCTION
long __stdcall MessageProc(HWND hWnd, unsigned int Msg, WPARAM wParam, LPARAM lParam)
{
	switch(Msg) //CHECK WHAT THE MESSAGE IS
	{
	case WM_CLOSE: //CLOSE THE WINDOW
		PostQuitMessage(0); //LET THE PROGRAM KNOW WE'RE QUITTING
		return 0;
	case WM_DESTROY: //DESTROY THE WINDOW
		PostQuitMessage(0); //LET THE PROGRAM KNOW WE'RE QUITTING
		return 0;
	}
	return(DefWindowProc(hWnd, Msg, wParam, lParam));
}
cWindow.h
Code:
#ifndef CWINDOW_H
#define CWINDOW_H

#include <Windows.h>
#include <String.h>

class cWindow
{
public:
	cWindow();
	virtual ~cWindow();

	//INITIALIZES OUR WINDOW
	bool Init(HBRUSH Colour, HINSTANCE *hInstance, long (__stdcall *MP)(HWND hWnd, unsigned int Msg, WPARAM wParam, LPARAM lParam),
		unsigned int ClassStyles, unsigned long WindowStyles, unsigned int Width, unsigned int Height);
	//DESTROYS OUR WINDOW
	bool Kill(HINSTANCE *hInstance);
	
	//SETS THE FOCUS ONTO OUR WINDOW
	void FocusOnMe(void);
	//SHOWS THE WINDOW
	void ShowMe(void);
	//UPDATES THE WINDOW
	void UpdateMe(void);
	
private:
	HWND hWnd;		//THE HANDLE TO OUR WINDOW
	char ClassName[10];	//THE NAME OF OUR CLASS
};

#endif 
cWindow.cpp
Code:
#include "cWindow.h"	

//cWindow::cWindow() (a.k.a. Constructor)
//
//PARAMETERS: None
//RETURNS: None
//
//DESCRIPTION:
//This function just makes sure our handle starts off as NULL and sets a name for our class
cWindow::cWindow()
{
	hWnd = NULL;
	strcpy(ClassName, "MyClass");
}

//cWindow::~cWindow() (a.k.a. Destructor)
//
//PARAMETERS: None
//RETURNS: None
//
//DESCRIPTION:
//This function does nothing because it assumes the programmer has already called the cWindow::Kill() function
//to clean everything up.
cWindow::~cWindow()
{}

//bool cWindow::Init()
//
//PARAMETERS:
//The colour for our background
//A pointer to the HINSTANCE generated by our WinMain() function
//A pointer to the misc. message handling function
//The styles for the class
//The sytles for the window
//The width of the window
//The height of the window
//RETURNS:
//Whether or not the window is created with success
//
//DESCRIPTION:
//This function is a wrapper for creating a window in the centre of the screen.
bool cWindow::Init(HBRUSH Colour, HINSTANCE *hInstance, long (__stdcall *MP)(HWND hWnd, unsigned int Msg, WPARAM wParam, LPARAM lParam),
		unsigned int ClassStyles, unsigned long WindowStyles, unsigned int Width, unsigned int Height)
{
	WNDCLASS WCL;			//OUR CLASS OBJECT
	unsigned short Registration; //KEEPS TRACK OF THE SUCCESS OF THE RegisterClass() FUNCTION

	//INITIALIZE OUR WINDOW CLASS
	WCL.cbClsExtra		= 0;							//SET ASIDE 0 EXTRA BYTES FOR THE CLASS
	WCL.cbWndExtra		= 0;							//SET ASIDE 0 EXTRA BYTES FOR THE WINDOW
	WCL.hbrBackground	= Colour;						//APPLY OUR COLOUR
	WCL.hCursor		= LoadCursor(NULL, IDC_ARROW);				//MAKE OUR CURSOR THE STANDARD ARROW
	WCL.hIcon		= LoadIcon(NULL, IDI_APPLICATION);			//CHOOSE THE STANDARD APPLICATION ICON
	WCL.hInstance		= *hInstance;						//PASS THE HINSTANCE FROM WinMain()
	WCL.lpfnWndProc		= *MP;							//PASS OUR MISC. MESSAGE HANDLER
	WCL.lpszClassName	= ClassName;						//THE NAME OF OUR CLASS
	WCL.lpszMenuName	= NULL;							//NO DEFAULT MENU
	WCL.style		= ClassStyles;						//APPLY OUR CLASS STYLES

	Registration = RegisterClass(&WCL);	//ATTEMPT TO REGISTER THE CLASS
	if(Registration == false)
		return false;

	//CREATE OUR WINDOW
	hWnd = CreateWindow(
		ClassName,						//OUR CLASS NAME
		"Game",							//THE TITLE FOR OUR WINDOW
		WindowStyles,						//APPLY OUR STYLES
		(GetSystemMetrics(SM_CXSCREEN) / 2) - (Width / 2),	//PLACE IN THE HORIZONTAL CENTRE
		(GetSystemMetrics(SM_CYSCREEN) / 2) - (Height / 2),	//PLACE IN THE VERTICAL CENTRE
		Width,							//WIDTH OF THE WINDOW
		Height,							//HEIGHT OF THE WINDOW
		NULL,
		NULL,
		*hInstance,						//OUR HINSTANCE
		NULL);

	if(hWnd == NULL) //CHECK IF OUR hWnd WAS INITIALIZED
		return false;

	return true; //SUCCESS
}

//bool cWindow::KILL()
//
//PARAMETERS:
//A pointer to the HINSTANCE from WinMain()
//RETURNS:
//Whether or not everything was removed
//
//DESCRIPTION:
//This function cleans up our window variables
bool cWindow::Kill(HINSTANCE *hInstance)
{
	MSG Msg;	  //CYCLES THROUGH OUR MESSAGES
	int Destroyed;	  //KEEPS TRACK OF SUCCESS FOR DestroyWindow()
	int Unregistered; //KEEPS TRACK OF SUCCESS FOR UnregisterClass()

	if(hWnd != NULL) //MAKE SURE THERE'S SOMETHING TO REMOVE
	{
		Destroyed = DestroyWindow(hWnd); //DESTROY THE WINDOW 
		if(Destroyed != false)
		{
			//REMOVE ALL MESSAGES
			while(PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE));
			{
				DispatchMessage(&Msg);
			}
		}
		hWnd = NULL; //CLEAR THE HANDLE TO OUR WINDOW
	}

	//UNREGISTER OUR CLASS
	Unregistered = UnregisterClass(ClassName, *hInstance);

	if((Destroyed == false)||(Unregistered == false)) //IF EITHER FAILED...
		return false; //...RETURN FAILURE

	return true; //RETURN SUCCESS
}

//void cWindow::FocusOnMe()
//
//PARAMETERS: None
//RETURNS: None
//
//DESCRIPTION:
//Sets the focus to our window
void cWindow::FocusOnMe(void)
{
	SetFocus(hWnd);
}

//void cWindow::ShowMe()
//
//PARAMETERS: None
//RETURNS: None
//
//DESCRIPTION:
//Show our window
void cWindow::ShowMe(void)
{
	ShowWindow(hWnd, SW_SHOW);
}

//void cWindow::UpdateMe()
//
//PARAMETERS: None
//RETURNS: None
//
//DESCRIPTION:
//Redraws our window
void cWindow::UpdateMe(void)
{
	UpdateWindow(hWnd);
}
The problem with trying to make a class for a window (as far as I know) is getting that default message handling function assigned. It can't be a member function of the class since it must be statically declared (this is going on what I heard a couple of years back when I was trying this, so it may sound like I'm talking out of my...especially if you know the real terminology).

Now, the way I usually do the message loop in my programs is like what you see in my WinMain() function. So, all in all, I find the MessageProc() very useless. But, when creating a window, you DO need a MessageProc() function to handle messages (as far as I know). The reason I wrote it like that is so I can manipulate/make calls to my objects (I.e. MainWindow->UpdateMe) or something when necessary, say on a keypress. Hope you get the idea. However, with a bit of tinkering, I'm sure anyone who's written a skeleton window like this will be able to adjust the MessageProc() to handle ALL messages, if that's what they desire.

Note that the MessageProc() is defined in Main.cpp, and the Class uses the prototpye as one of its parameters. I think this is an okay mix, and wouldn't really have any issues if somebody tried to re-write the program from scratch, using the class, since there is only one way (as far as I know) to declare the default MessageProc() and its parameters.

The three "files" above will compile and run as an example of how the class is used.

Feel free to try it out, but more importantly, I'm hoping for some feedback. Are there any aspects that you think can be improved/written better? Any issues? Or just any comments?

Thanks for the read.
__________________
Pentium 4 - 2.0GHz, 512MB RAM
NVIDIA GeForce4 MX 440
WinXP
Visual Studio .Net 2003
DX9 October 2004 Update (R.I.P. VC++ 6.0 Compatability)

Last edited by Epo; 07-10-2005 at 02:42 PM.
Epo is offline   Reply With Quote
Old 07-10-2005, 12:01 PM   #2
Pursuing knowledge
 
confuted's Avatar
 
Join Date: Jun 2002
Posts: 1,916
You could try passing a function pointer that points at the desired message handling function for the dialog in the constructor for this class. That way, each dialog can have its own procedure, etc, easily.
__________________
Away.
confuted is offline   Reply With Quote
Old 07-10-2005, 02:33 PM   #3
Epo
Registered User
 
Join Date: Jun 2003
Posts: 361
Perhaps I misunderstood, but I think what you suggested is happening in my cWindow::Init() function already...

I like to keep things out of the constructor other than simple init stuff (no gobs of code). Right now, my cWindow::Init() function takes a pointer to a message handling function of the form:
long (__stdcall *MP)(HWND hWnd, unsigned int Msg, WPARAM wParam, LPARAM lParam)

The problem is that any message handling function you wish to use must be declared in Main.cpp. You can't use a member function of the class (I.e. cWindow::MessageProc()) for the WCL.lpfnWndProc variable (it has something to do with not being static? Again, I was told this about 3 years ago so my terminology may be off). Either way, it's next to impossible (I remember hearing of people who pulled it off, but it seemed too crazy for me at the time) to use a class's member function for the default message handler.

Right now, the message handling procedure is declared in Main.cpp and passed into the class through the cWindow::Init() function. Sorry, I got side-tracked a little bit in there. But is this what you meant?
__________________
Pentium 4 - 2.0GHz, 512MB RAM
NVIDIA GeForce4 MX 440
WinXP
Visual Studio .Net 2003
DX9 October 2004 Update (R.I.P. VC++ 6.0 Compatability)
Epo is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
WM_CAPTION causing CreateWindowEx() to fail. Necrofear Windows Programming 8 04-06-2007 08:23 AM
creating a child window rakan Windows Programming 2 01-23-2007 03:22 PM
how i create a window whith all it's elements rasheed Windows Programming 1 05-31-2006 06:53 PM
Window Wrapper Class, WM_NCCREATE never sent bennyandthejets Windows Programming 5 04-18-2004 06:02 AM
opengl code not working Unregistered Windows Programming 4 02-14-2002 10:01 PM


All times are GMT -6. The time now is 08:11 PM.


Powered by vBulletin® Version 3.8.1
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.3.2

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22