My Window Class

This is a discussion on My Window Class within the Game Programming forums, part of the General Programming Boards category; Hey all, I wrote a sort of wrapper class for creating a skeleton window. I'll post the code first, and ...

  1. #1
    Epo
    Epo is offline
    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.
    Last edited by Epo; 07-10-2005 at 03:42 PM.
    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)

  2. #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.

  3. #3
    Epo
    Epo is offline
    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)

Popular pages Recent additions subscribe to a feed

Similar Threads

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

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