Thread: Default Message Handler in a Class

  1. #1
    Registered User
    Join Date
    Jun 2003
    Posts
    361

    Default Message Handler in a Class

    Hey all, I've done all the reading:
    Thread 1 (Started by me a long time ago)
    Thread 2
    Thread 3

    And numerous others, which have explained over and over how to incorporate a member function of a class as the default message handler for the WNDPROC.

    My important code looks like this:
    Code:
    long __stdcall cWindow::SMessageProc(HWND hWnd, unsigned int Msg, WPARAM wParam, LPARAM lParam)
    {
    	long Temp = 0;	
    	cWindow *TempWindow = NULL;
    
    	if(Msg == WM_NCCREATE)
    	{
    		LPCREATESTRUCT LPC = (LPCREATESTRUCT)lParam;
    
    		Temp = SetWindowLong(hWnd, GWL_USERDATA, (long)LPC->lpCreateParams);
    		if(Temp == 0)
    			MessageBox(NULL, "SetWindowLong1 Failed", "Error", MB_OK);
    
    		Temp = SetWindowLong(hWnd, 0, 1);
    		if(Temp == 0)
    			MessageBox(NULL, "SetWindowLong2 Failed", "Error", MB_OK);
    
    		return DefWindowProc(hWnd, Msg, wParam, lParam);
    	}
    
    	if((GetWindowLong(hWnd, 0)) != 0)
    	{
    		TempWindow = (cWindow*)GetWindowLong(hWnd, GWL_USERDATA);
    		return TempWindow->MessageProc(hWnd, Msg, wParam, lParam);
    	}
    	else
    	{
    		MessageBox(NULL, "GetWindowLong Failed", "Error", MB_OK);
    	}
    
    	return(DefWindowProc(hWnd, Msg, wParam, lParam));
    }
    However, both SetWindowLong() functions fail, and as a result, so does my GetWindowLong(), which results in my secondary MessageProc to never fire (and never handle any events).

    In the thread I posted above (started by me a longer time ago), it seems I hit this very same snag, but it wasn't ever really solved. So, here I am again, hoping for some help :-) If anybody can guess why SetWindowLong() is failing, I would love to hear it.

    I also looked up the GWL_USERDATA flag, which appears to be defined in Winuser.h. But tossing an:
    #include <Winuser.h>
    Still didn't change anything.

    P.S. I didn't post any more code because it seems most of the values for the SetWindowLong() calls are declared/initialized in this function.
    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
    erstwhile
    Join Date
    Jan 2002
    Posts
    2,227
    The return value of SetWindowLong is the "previous value of the specified 32-bit integer." So, if you haven't set GWL_USERDATA, the return value of your first call to SetWindowLong during your handling of WM_NCREATE will be zero - and will result in the 'failure' you observe. It would probably be better to ensure that lpCreateParams is valid and base your success/failure on that. Consider:
    Code:
    LRESULT CALLBACK cWindow::SMessageProc(HWND hWnd, unsigned int Msg, WPARAM wParam, LPARAM lParam)
    {
    /*first see if this is stored*/
    cWindow *TempWindow=reinterpret_cast<cWindow*>(GetWindowLong(hWnd, GWL_USERDATA));
    if (!cWindow)
      {
      /*it's not so it needs to be done*/
      if (Msg == WM_NCCREATE)
        {
        LPCREATESTRUCT LPC = reinterpret_cast<LPCREATESTRUCT>(lParam);
        if (LPC->lpCreateParams)
          {
          TempWindow=reinterpret_cast<cWindow*>(LPC->lpCreateParams);
          SetWindowLong(hWnd, GWL_USERDATA, reinterpret_cast<LONG>(TempWindow));
          }
        else
          {
          /*problem: invalid creation parameter, report it and fail wnd creation*/
          MessageBox(0, "WM_NCCREATE fail", "Error", MB_OK);
          return -1;
          }
        }
      else
        {
        /*msg is prior to WM_NCCREATE so this unavailable*/
        return DefWindowProc(hWnd, Msg, wParam, lParam);
        }
      }
    /*this is good*/
    return TempWindow->MessageProc(hWnd, Msg, wParam, lParam);
    }
    You may also wish to consider using SetWindowLongPtr which supersedes SetWindowLong.
    Last edited by Ken Fitlike; 07-23-2005 at 08:19 PM. Reason: much reinterpret_casting
    CProgramming FAQ
    Caution: this person may be a carrier of the misinformation virus.

  3. #3
    Registered User
    Join Date
    Jun 2003
    Posts
    361
    Ken you're a saviour when it comes to windows programming.
    MSDN says:
    GWLP_WNDPROC
    Sets a new address for the window procedure.
    Just a quick question:
    As far as my reading goes, wouldn't that mean you can change the WNDPROC from your static, to your non-static after creation?

    I.e.
    Code:
    SetWindowLongPtr(hWnd, GWLP_WNDPROC, &MessageProc);
    Where MessageProc() is the non-static message handler.

    Although, a quick test of that after the creation of my hWnd object yielded the error:
    error C2276: '&' : illegal operation on bound member function expression
    Which makes me think that it can't be that simple.

    So, back on topic.

    I've switched my GetWindowLong() and SetWindowLong() to their superceding counterparts (though none of the parameters change, which makes me wonder why these were ever available in the first place...were the Ptrs added after?)

    And it is indeed the (LPCREATESTRUCT) that is causing the problem (the MessageBox is popping up).

    Another quick question:
    Code:
    reinterpret_cast<LPCREATESTRUCT>(lParam);
    Is that the equivalent typecast of:
    Code:
    (LPCREATESTRUCT)lParam;
    Is one C, and the other C++ related?

    And back to the main problem:
    lpCreateParams is failing.

    Just to show I'm researching and really trying to figure this out on my own...MSDN says:
    lpCreateParams
    Contains additional data which may be used to create the window. If the window is being created as a result of a call to the CreateWindow or CreateWindowEx function, this member contains the value of the lpParam parameter specified in the function call.
    However, lpCreateParams doesn't take any parameters, so it can't really be blamed for anything. I'm assuming the lpParam being referred to is the one in the CreateWindow() function.
    Code:
    //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);							//OUR lpParam!!!
    Looks like I'm setting it to NULL...so, off I go to find a value to set here...hmm...what would be appropriate? (It is now 11:02PM)

    11:28
    My first logical guess is to pass this as the lpParam...no dice...

    I'll throw the question out there: what do I add? I'll keep on tossing in random variable names until somebody helps me out in hopes of getting lucky

    Thanks for reading/skimming.

    Edit:
    Whoa, whoa whoa.

    MSDN:
    lpParam
    [in] Pointer to a value to be passed to the window through the CREATESTRUCT structure passed in the lpParam parameter of the WM_CREATE message. If an application calls CreateWindow to create a multiple-document interface (MDI) client window, lpParam must point to a CLIENTCREATESTRUCT structure.
    CREATESTRUCT??? Jeez. Okay, I'm gonna go make one and see what happens. (11:41)

    11:43
    No! No! No!

    lpCreateParams is a parameter of the CREATESTRUCT? It's one big vicious circle! I'm gonna go watch Saturday Night Live in hopes that it'll be funny finally.

    12:56
    It WAS this

    Turns out I misread the code before and wrote:
    Code:
    long __stdcall cWindow::SMessageProc(HWND hWnd, unsigned int Msg, WPARAM wParam, LPARAM lParam)
    {
    	cWindow *TempWindow = (cWindow*)GetWindowLong(hWnd, GWL_USERDATA);
    
    	if(!TempWindow)
    	{
    		if(Msg == WM_NCCREATE)
    		{
    			LPCREATESTRUCT LPC = (LPCREATESTRUCT)lParam;
    
    			if(LPC->lpCreateParams)
    			{
    				TempWindow = (cWindow*)LPC->lpCreateParams;
    				SetWindowLong(hWnd, GWL_USERDATA, (LONG)TempWindow);
    			}
    			else
    			{
    				MessageBox(NULL, "WM_NCCREATE Failed", "Error", MB_OK);
    				return -1;
    			}
    		}
    	}
    	else
    	{
    		return DefWindowProc(hWnd, Msg, wParam, lParam);
    	}
    
    	return TempWindow->MessageProc(hWnd, Msg, wParam, lParam);
    }
    Note the position of the last else. Meaning the TempWindow->MessageProc() would never fire. The else has to be nested one level deeper in that chunk of code.

    Hooray! Thanks for the point in the right direction Ken
    Last edited by Epo; 07-23-2005 at 10:57 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)

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Problem in message handling VC++
    By 02mca31 in forum Windows Programming
    Replies: 5
    Last Post: 01-16-2009, 09:22 PM
  2. Replies: 7
    Last Post: 11-17-2008, 01:00 PM
  3. template class default constructor problem
    By kocika73 in forum C++ Programming
    Replies: 3
    Last Post: 04-22-2006, 09:42 PM
  4. constructors
    By shrivk in forum C++ Programming
    Replies: 7
    Last Post: 06-24-2005, 09:35 PM
  5. Tab Controls - API
    By -KEN- in forum Windows Programming
    Replies: 7
    Last Post: 06-02-2002, 09:44 AM