(Classes) Setting a class pointer to NULL? (C++)

Started by
16 comments, last by fitfool 15 years, 4 months ago
Hi, I just got full screen mode working on my game finally, and now I run into a problem where the window is not checking for messages, WM_CLOSE, WM_KEYUP

LRESULT CALLBACK Core::WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
		
			Core* pWnd = NULL;
		static bool bProcessed = false;

		switch (message) {
			case WM_NCCREATE: {

				SetWindowLong(hWnd, GWL_USERDATA, (long) (LPCREATESTRUCT(lParam)->lpCreateParams));
		break;
			}
			default: {
				pWnd = (Core*) GetWindowLong(hWnd, GWL_USERDATA);
				if(NULL != pWnd) {
					bProcessed = pWnd->MessageHandler(message, wParam, lParam);
				}
			}
		}
		if(!bProcessed) {
		return DefWindowProc(hWnd, message, wParam, lParam);
		}

		return 0;
	} //Window Proc






What's supposed to happen is that MessageHandler() is supposed to get called, but can't since pWnd is NULL. I did look over other code, but seem's I can't get pWnd->MessageHandler function to execute, since GetWindowLong isn't doing anything for me. Core class just has the game variables and function, just like any other 'basic' class would. window height, width, bits, fps pointer, etc. I am not sure how to handle this situation, I would appreciate any feed back on this issue, since I don't know what I am doing wrong. Can this issue have anything to do with the last argument in the function for CreateWindowEx? I did have the last arg, (void*)this, but that just caused my window to be invisible, but if the last arg on CreaWindowEX was NULL, fullscreen and window mode works just not the Message Handler any more. [Edited by - ajm113 on December 16, 2008 6:36:21 PM]
Check out my open source code projects/libraries! My Homepage You may learn something.
Advertisement
Is the value in GWL_USERDATA actually getting set to something useful? Have you put a breakpoint there and looked at it?

Did you just copy this from somewhere or did you actually write it? Do you understand what its doing?
Yes, I break pointed it and looked through the pWned pointer and didn't see anything new or not NULL, so pretty much I don't know what I am looking for.

I did do a msdn on that function, but didn't have time to look over it, but it's supposed too retrieve information about the specified window?

I learned it from a video series.

[Edited by - ajm113 on December 16, 2008 7:52:44 PM]
Check out my open source code projects/libraries! My Homepage You may learn something.
IIRC, that GWL_USERDATA value lets you attach any 32-bits of data you want to the window. I've seen in used to allow object-oriented window abstraction and that sort of thing (tuck a pointer to the object into that value so that you can retrieve the object in the event handler, etc).

Actually, that appears to be exactly what the code is going. It's casting that value to a Core*. So it should be hitting the SetWindowLong after you instantiate your Core object. What is it putting in there? That's sort of integral to your problem.
Post the code to your MessageHandler(), you may not be returning the correct value for a certain message, thus causing it to be invisible.
Its not changing a thing on GetWindowLong still, sorry to sound dumb, but should I make a pointer in the class just for GetWindowLong? I'm kinda lost on what you said...

I don't want to seem I need to get spoon feed, but can you write a small example of what you want me to try? If it's not too much to ask?

@ fitfool, sure why not:


bool Core::MessageHandler(UINT message, WPARAM wParam, LPARAM lParam) {					switch(message) {				case WM_CREATE: {				if(MaxMe) {  ShowWindow(hWnd, SW_MAXIMIZE); }					return true;								}			case WM_CLOSE: {			DestroyWindow(hWnd);			ClearAll();			return true;				   }			case WM_DESTROY: {				m_pErrorHandler.Message("#Game Closing!");		PostQuitMessage(0);		return true;				}			case WM_ACTIVATE: {				if(LOWORD(wParam) == WA_INACTIVE) {		m_bActive = false;		WindowFocusLost();				}else{		m_bActive = false;		WindowFocusRecived();				}				return true;		  }			case WM_SYSKEYDOWN:{            m_bKeys[wParam] = true;			break;}			case WM_SYSKEYUP:{            m_bKeys[wParam] = false;			break;}			case WM_SYSCOMMAND: {				switch (wParam) {			case SC_SCREENSAVE:			case SC_MONITORPOWER: {				return true;								  }			default: {				return false;					 }				}			}			case WM_SIZE: {							RECT rect;	GetClientRect (hWnd, &rect);	//MoveWindow (RenderWindow, 0, 0, rect.right-rect.left-0, rect.bottom-rect.top, true);		GetClientRect (hWnd, &rect);	ResizeGLWindow (rect.right-rect.left, rect.bottom-rect.top);	m_iWidth = rect.right-rect.left;	m_iHeight = rect.bottom-rect.top;	break; 			return 0;						  }			case WM_KEYDOWN: {								m_bKeys[wParam] = true;				return true;							 }		    case WM_KEYUP: {				m_bKeys[wParam] = false;				return true;							}			default: {				return false;					 }			}			return false;		}


Had to git rid of a few cases to make it shorter and easier too look at.

[Edited by - ajm113 on December 17, 2008 12:22:32 AM]
Check out my open source code projects/libraries! My Homepage You may learn something.
The WindowProc is entered for every single message. Your pWnd variable is redeclared and reset to NULL everytime.

Either make pWnd a member of Core or static to the procedure.


And, i see it once again, if your message gets processed you return 0 as default. This is wrong!
There is no simple single return value for handled messages. It completely depends on the message and can be any value. If a message gets handled you should usually still pass it on to DefWindowProc (unless the MSDN states you shouldn't).

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

Alright, well I fixed those problems with my code. I changed pWned into a static and got rid of making it NULL and removed the if(bProcessed) for DefWindowProc and removed return 0; in the code.

I am still having the same issue, becuase pWned isn't being set to anything thing when it goes through the if statment. If MessageHandler was called with pWned being NULL I get a access violation error, FYI.
Check out my open source code projects/libraries! My Homepage You may learn something.
pWnd was *supposed* to be set to NULL everytime, and it MUST be set to NULL evertime for it to work... that isn't the problem. I'm asking "what is put in the GWL_USERDATA when your window is created?"... you keep telling me what comes out of GetWindowLong, but I'm not interested in that because it is CLEARLY wrong. I want to know what gets put into GWL_USERDATA in the first place.

Here's what's supposed to be happening... you create an instance of Core, which presumably creates a window using CreateWindowEx(). CreateWindowEx() (or CreateWindow()) takes an LPVOID lpParam value, which Core presumably sets to "this"--meaning a pointer to itself. That CreateWindow() call results in a WM_NCCREATE message sent to that method you posted.

Your event handler sees that it has a WM_NCCREATE message, so it uses SetWindowLong to set the GWL_USERDATA value for that hwnd to that same pointer that it passed to CreateWindowEx (which is passed along to the handler there as an argument lParam [EDIT: the pointer is actually passed as a member of a CREATEPARAMS struct, and the lParam argument is a pointer to that struct... sorry for the confusion, I screwed up my description there a bit, but it isn't too important for you at this point]

Now, anytime a message comes in, the call to GetWindowLong pulls that pointer out as a LONG, and casts it to a Core*. That gives you the pointer to the actual Core* associated with the hwnd for which you just received a message.

Does that makes sense? That bit of GWL_USERDATA that is placed/removed using Set/GetWindowLong is a pointer to a Core instance. Windows uses a C API... if you want an object oriented wrapper you have to use tricks like this.

Now, what I want to know and have been asking, is WHAT EXACTLY IS IT STICKING INTO THE GWL_USERDATA VALUE in the WM_NCCREATE message handler?

EDIT:

I just saw in your OP:
Quote:Can this issue have anything to do with the last argument in the function for CreateWindowEx?

I did have the last arg, (void*)this, but that just caused my window to be invisible, but if the last arg on CreaWindowEX was NULL, fullscreen and window mode works just not the Message Handler any more.

YES, it has everything to do with it. If you put NULL in there, you get NULL out to be assigned to pWnd. Of course I can't see the rest of your code, but I see no reason why that wouled make your window invisible. More likely, the "invisibility" is a side effect of something else you're doing in your message handler after you get the pWnd pointer.


[Edited by - smitty1276 on December 17, 2008 12:19:37 AM]
Oh, I understand now, sorry. This hasn't been my day today.. So I must have been thinking about my frustration with Maya today at school.

Anyways

Well the return value is 0 for SetWindowLong, and the value entered is 0 as well.

(EDIT)
I knew it! (Slap To The Head)

Well I'll cast it as (void*)this and check around for the problem, unless you can spot it in a minute, be my guest and go a head and tell me.

//TmainWNDCLASS	wc;	hInstance		= GetModuleHandle(NULL);			// Grab An Instance For Our Window	wc.style		= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;		// Redraw On Move, And Own DC For Window	wc.lpfnWndProc		= (WNDPROC) core.WindowProc;				// WndProc Handles Messages	wc.cbClsExtra		= 0;						// No Extra Window Data	wc.cbWndExtra		= 0;						// No Extra Window Data	wc.hInstance		= hInstance;					// Set The Instance	wc.hIcon		= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SMALL));			// Load The Default Icon	wc.hCursor		= LoadCursor(NULL,  IDC_CROSS);			// Load The Arrow Pointer	wc.hbrBackground	= NULL;						// No Background Required For GL	wc.lpszMenuName		= NULL;						// We Don't Want A Menu	wc.lpszClassName	= "OpenGL";					// Set The Class Name	if(!RegisterClass(&wc)) {		hInstance = NULL;		return false;		}//End of tMain//Create inside of core classif(fullscreen){				DEVMODE dmScreenSettings;					// Device Mode		memset(&dmScreenSettings,0,sizeof(dmScreenSettings));		// Makes Sure Memory's Cleared		dmScreenSettings.dmSize=sizeof(dmScreenSettings);		// Size Of The Devmode Structure		dmScreenSettings.dmPelsWidth	= m_iWidth;			// Selected Screen Width		dmScreenSettings.dmPelsHeight	= m_iHeight;			// Selected Screen Height		dmScreenSettings.dmBitsPerPel	= 32;				// Selected Bits Per Pixel		dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;				if(ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)				{				// If The Mode Fails, Offer Two Options.  Quit Or Run In A Window.			if (MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?","NeHe GL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)			{			fullscreen=FALSE;				// Select Windowed Mode (Fullscreen=FALSE)			}				}	}	hInst = _hInst;	//LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);	//LoadString(hInstance, IDC_THEARICLE, szWindowClass, MAX_LOADSTRING);	if((m_iHeight <= 0) || (m_iWidth <= 0) || (m_iRefreshRate <= 0)) {						m_pErrorHandler.Message("Window Parameters Are Invalid!");						m_pErrorHandler.SetError(EC_Windows, "Window Parameters Are Invalid!");						m_pErrorHandler.ShowErrorMessage();				return false;	}   RECT rcWnd;   rcWnd.left   = 0;		rcWnd.right  = m_iWidth;		rcWnd.top    = 0;		rcWnd.bottom = m_iHeight;		DWORD dwStyle, dwStyleEx;		if(fullscreen) { //Fullscreen Application		dwStyle = WS_POPUP;		dwStyleEx = WS_EX_APPWINDOW;		}else{ //Windowed Game!		dwStyle = WS_VISIBLE | WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;		dwStyleEx = WS_EX_APPWINDOW;		}		AdjustWindowRectEx(&rcWnd, dwStyle, FALSE, dwStyleEx);		// Adjust Window To True Requested Siz if (!(hWnd = CreateWindowEx(dwStyleEx, "OpenGL", "Space Music 1.0", dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,      CW_USEDEFAULT, 0, 	  rcWnd.right  - rcWnd.left, 	  rcWnd.bottom - rcWnd.top,   	  NULL, 	  NULL, 	  hInst, NULL))) {						m_pErrorHandler.Message("Could Not Create Window!");						m_pErrorHandler.SetError(EC_Windows, "Could Not Create Window!");						m_pErrorHandler.ShowErrorMessage();		return FALSE;							// Return FALSE  }//Skipping To EndShowWindow(hWnd, SW_SHOW);			SetForegroundWindow(hWnd);			SetFocus(hWnd);			UpdateWindow(hWnd);			ResizeGLWindow (rcWnd.right-rcWnd.left, rcWnd.bottom-rcWnd.top);		Core::SetGLDefaults();      while(!bQuit)		{			Core::Render();		if(PeekMessage(&message, NULL, 0, 0, PM_REMOVE))		{			if(WM_QUIT == message.message) {			bQuit = true;			}else{			TranslateMessage(&message);			DispatchMessage(&message);			}		}else{			Core::Frame();		}	}
Check out my open source code projects/libraries! My Homepage You may learn something.

This topic is closed to new replies.

Advertisement