Advertisement

TOTWGPG

Started by December 12, 2001 04:16 PM
9 comments, last by Brian Jones 23 years ago
Hello, I am at the latter part of the second chapter in this book. I've made a program that opens two different windows, based on two different classes.
  
// Two Windows.cpp : Defines the entry point for the application.

// DEMO2_5.CPP - Creates two windows based on the same 

// window class


// INCLUDES ///////////////////////////////////////////////

#define WIN32_LEAN_AND_MEAN  // just say no to MFC


#include <windows.h>   // include all the windows headers
#include <windowsx.h>  // include useful macros
#include <stdio.h>     
#include <math.h>
#include <stdafx.h>


// DEFINES ////////////////////////////////////////////////


// defines for windows 

#define WINDOW_CLASS_NAME "WINCLASS1"
#define WINDOW_CLASS_NAME2 "WINCLASS2"

// GLOBALS ////////////////////////////////////////////////

HWND hWindow1 = NULL;
HWND hWindow2 = NULL;

// FUNCTIONS //////////////////////////////////////////////

LRESULT CALLBACK WindowProc(HWND hwnd, 
						    UINT msg, 
                            WPARAM wparam, 
                            LPARAM lparam)
{
// this is the main message handler of the system

PAINTSTRUCT		ps;		// used in WM_PAINT

HDC				hdc;	// handle to a device context


// what is the message 

switch(msg)
	{	
	case WM_CREATE: 
        {
		// do initialization stuff here


        // return success

		return(0);
		} break;

	case WM_PAINT: 
		{
		// simply validate the window

		hdc = BeginPaint(hwnd,&ps);	 
		// you would do all your painting here

        EndPaint(hwnd,&ps);

        // return success

		return(0);
   		} break;

	case WM_DESTROY: 
		{
		// kill the application, this sends a WM_QUIT message 

		if( hwnd == hWindow1 )
		hWindow1 = NULL;
		if( hwnd == hWindow2 )
		hWindow2 = NULL;
		if((!hWindow1)  && (!hWindow2) )
		PostQuitMessage(0);
        // return success

		return(0);
		} break;

	default:break;

    } // end switch


// process any messages that we didn't take care of 

return (DefWindowProc(hwnd, msg, wparam, lparam));

} // end WinProc


// WINMAIN ////////////////////////////////////////////////

int WINAPI WinMain(	HINSTANCE hinstance,
					HINSTANCE hprevinstance,
					LPSTR lpcmdline,
					int ncmdshow)
{

WNDCLASSEX winclass; // this will hold the class we create

WNDCLASSEX winclass2;
MSG		   msg;		 // generic message


// first fill in the window class stucture

winclass.cbSize         = sizeof(WNDCLASSEX);
winclass.style			= CS_DBLCLKS | CS_OWNDC | 
                          CS_HREDRAW | CS_VREDRAW;
winclass.lpfnWndProc	= WindowProc;
winclass.cbClsExtra		= 0;
winclass.cbWndExtra		= 0;
winclass.hInstance		= hinstance;
winclass.hIcon			= LoadIcon(NULL, IDI_APPLICATION);
winclass.hCursor		= LoadCursor(NULL, IDC_ARROW);
winclass.hbrBackground	= (HBRUSH)GetStockObject(BLACK_BRUSH);
winclass.lpszMenuName	= NULL;
winclass.lpszClassName	= WINDOW_CLASS_NAME;
winclass.hIconSm        = LoadIcon(NULL, IDI_APPLICATION);

// winclass2 struct

winclass2.cbSize		= sizeof(WNDCLASSEX);
winclass2.style			= CS_DBLCLKS | CS_OWNDC |
						  CS_HREDRAW | CS_VREDRAW;
winclass2.lpfnWndProc	= WindowProc;
winclass2.cbClsExtra	= 0;
winclass2.cbWndExtra	= 0;
winclass2.hInstance		= hinstance;
winclass2.hIcon			= LoadIcon(NULL, IDI_APPLICATION);
winclass2.hCursor		= LoadCursor(NULL, IDC_ARROW);
winclass2.hbrBackground	= (HBRUSH)GetStockObject(BLACK_BRUSH);
winclass2.lpszMenuName	= NULL;
winclass2.lpszClassName	= WINDOW_CLASS_NAME2;
winclass2.hIconSm		= LoadIcon(NULL, IDI_APPLICATION);



// register the window class

if (!RegisterClassEx(&winclass))
	return(0);
// register the window2 class

if (!RegisterClassEx(&winclass2))
	return(0);


// create the first window

if (!(hWindow1 = CreateWindowEx(NULL,                  // extended style

                            WINDOW_CLASS_NAME,     // class

						    "Window 1 Based on WINCLASS1", // title

						    WS_OVERLAPPEDWINDOW | WS_VISIBLE,
					 	    0,0,	    // initial x,y

						    400,400,  // initial width, height

						    NULL,	    // handle to parent 

						    NULL,	    // handle to menu

						    hinstance,// instance of this application

						    NULL)))	// extra creation parms

return(0);

// create the second window

if (!(hWindow2 = CreateWindowEx(NULL,                  // extended style

                            WINDOW_CLASS_NAME2,     // class

						    "Window 2 Based on WINCLASS2", // title

						    WS_OVERLAPPEDWINDOW | WS_VISIBLE,
					 	    100,100,  // initial x,y

						    400,400,  // initial width, height

						    NULL,	  // handle to parent 

						    NULL,	  // handle to menu

						    hinstance,// instance of this application

						    NULL)))	// extra creation parms

return(0);

// enter main event loop, but this time we use PeekMessage()

// instead of GetMessage() to retrieve messages

while(TRUE)
	{
    // test if there is a message in queue, if so get it

	if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
	   { 
	   // test if this is a quit

       if (msg.message == WM_QUIT)
           break;
	
	   // translate any accelerator keys

	   TranslateMessage(&msg);

	   // send the message to the window proc

	   DispatchMessage(&msg);
	   } // end if

    
    // main game processing goes here

	
	} // end while


// return to Windows like this

return(msg.wParam);

} // end WinMain


///////////////////////////////////////////////////////////


   
It executes perfectly, but I'm not sure how WindowProc works. How does it know which window need to be repainted? I'm my code, it doesn't appear to know the handle of either window. Somebody please help so I can move on to the next chapter. Edited by - Brian Jones on December 12, 2001 5:24:02 PM Edited by - Brian Jones on December 12, 2001 5:28:01 PM
I don't have a signature
If you look at the function declaration, you will see hwnd.

LRESULT CALLBACK WindowProc(HWND hwnd,
UINT msg,
WPARAM wparam,
LPARAM lparam) {
....
}

When you window gets a system message such as window close, resize, repaint, etc....it calls WindowProc with hwnd, which is a handle to the current window (ie, itself). So when WindowProc is called, it does it''s work on hwnd, which points to the window that called it. Make sense?

And if you notice throughout your code below, you call all the functions to manipulate the window with hwnd again. So you always do the work on the calling window.

Good to see you asking the questions, g''luck with it all =)

R.
Advertisement
But, hWindow1, and hWindow2 are the handles to the two windows. How would I pass both of those handles to WindowProc?
I don't have a signature
Well, those handles are just pointers. You have more than one pointer to each window.

Say for example you tell your window to minimize. The window you created knows that it''s callback function is WindowProc because you created a Window Class and told it what function to use. So, when you minimize that window, it will call WindowProc for you using using hWindow1 or hWindow2 depending on which window does the calling. If you minimize hWindow2, it''ll call Windowproc with hWindow2 as it''s first paramater. Windowproc just create a new pointer called hwnd to point to hWindow2. At this point, hwnd = hWindow2.

Same thing if it was hWindow1 that sent a message to WindowProc. If it didn''t work this way, you''d have to write a seperate WindowProc for each Window. If you had an application with 10 windows, that''d be 10 WindowProcs?! Waste of time. Instead, you can create a common WindowProc and maybe a special WindowProc when you want the window to act differently or just write a lot of code to compare hwnd to hWindow1, hWindow2, etc. Just like you did in the code from the book. If you look at WM_DESTROY in WindowProc, you can see code where you see if hwnd == hWindow1 or if hwnd == hWindow2.

R.
Easily, they are both based on the same WndProc. In your WNDCLASS struct you assign the same WndProc to both.

This they both point to the same function, in this case the WndProc.

ECKILLER
ECKILLER
Ahhh I get it. I forgot about that. This Windows programming is hard. One more thing though

  case WM_DESTROY:{ // kill the application, this sends WM_QUIT  		if( hwnd == hWindow1 )		hWindow1 = NULL;		if( hwnd == hWindow2 )		hWindow2 = NULL;		if((!hWindow1)  && (!hWindow2) )PostQuitMessage(0);        // return success		return(0);} break;  


Somebody please explain that. That code is not mine, somebody added it to the program when I was writing it.
I don't have a signature
Advertisement
quote: if( hwnd == hWindow1 )
hWindow1 = NULL;
if( hwnd == hWindow2 )
hWindow2 = NULL;

Assign whichever window received the WM_DESTROY message to point to NULL. Whoever wrote it felt that it was necessary so that the application would be able to quit if both Windows had been closed. It was also necessary to explicitly refer to the variables by name because the window procedure gets a copy of the handle, not the original.

Not exactly a stroke of elegant genious, but it works.

[ GDNet Start Here | GDNet FAQ | MS RTFM | STL | Google ]
Thanks to Kylotan for the idea!
Ok.... I get it. But what does the last part mean?
  if((!hWindow1)  && (!hWindow2) )  


Everybody must be like "God this guy can''t figure out anything
for himself."
I don't have a signature
Read it out: "if not hWindow1 and not hWindow2..."

In other words, if both of them are "not" (zero values, such as NULL).

[ GDNet Start Here | GDNet FAQ | MS RTFM | STL | Google ]
Thanks to Kylotan for the idea!
I still don''t get it. Do that handle to a window point to NULL when a WM_DESTROY message is sent to that window?
I don't have a signature

This topic is closed to new replies.

Advertisement