Please help: problem with creating a win32 window

Started by
16 comments, last by EGD Eric 20 years ago
When I try to make a window in win32, its giving me this error: error C2440: ''='' : cannot convert from ''LRESULT (__stdcall glApplication::* )(HWND,UINT,WPARAM,LPARAM)'' to ''WNDPROC'' On the line where I do this: wndclass.lpfnWndProc = WinProc; I don''t understand. Previous code I''ve seen does this and it works. Here''s my window''s creation code:


//Called once. Creates the window

HWND glApplication::CreateglWindow(LPSTR strWindowName, int width, int height, DWORD dwStyle, bool bFullScreen, HINSTANCE new_hInstance)
{
	HWND hWnd;				
	WNDCLASS wndclass;
	
	memset(&wndclass, 0, sizeof(WNDCLASS));				
	wndclass.style = CS_HREDRAW | CS_VREDRAW;			
	wndclass.lpfnWndProc = WinProc;						
	wndclass.hInstance = hInstance;						
	wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);	
	wndclass.hbrBackground = (HBRUSH) (COLOR_WINDOW+1);
	wndclass.lpszClassName = appName;		

	RegisterClass(&wndclass);							
	
	if(bFullScreen && !dwStyle) //Don''t show the cursor when in fullscreen				

	{													
		dwStyle = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
		ChangeToFullScreen();							
		ShowCursor(FALSE);								
	}
	else if(!dwStyle)									
		dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
	
	hInstance = new_hInstance;	//set the application''s handle to the app				


	RECT rWindow;
	rWindow.left	= 0;								
	rWindow.right	= width;							
	rWindow.top	    = 0;								
	rWindow.bottom	= height;							

	AdjustWindowRect( &rWindow, dwStyle, false);		

														
	hWnd = CreateWindow(appName, strWindowName, dwStyle, 0, 0,
						rWindow.right  - rWindow.left, rWindow.bottom - rWindow.top, 
						NULL, NULL, hInstance, NULL);

	if(!hWnd) return NULL;							

	ShowWindow(hWnd, SW_SHOWNORMAL);					
	UpdateWindow(hWnd);									

	SetFocus(hWnd);										

	return hWnd;

}


The WinProc function is defined just above it. If you want to see it, the following is its declaration:


LRESULT CALLBACK glApplication::WinProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	LONG    lRet = 0; 
//	GetPos(LOWORD(lParam), HIWORD(lParam));

	
    switch (uMsg)
	{ 
    case WM_SIZE:									
		if(!fullScreen)							
		{
			SizeOpenGLScreen(LOWORD(lParam),HIWORD(lParam));
			glGetClientRect(hWnd, &clientRect);				
		}
        break; 

	case WM_KEYDOWN:
//		keys[wParam] = true; 

		break;

	case WM_KEYUP: 
//		keys[wParam] = false;

		break;
	case WM_MOUSEMOVE:

		break;
	case WM_LBUTTONDOWN:
//		MouseButtons[0] = true;

		break;
	case WM_LBUTTONUP:
//		MouseButtons[0] = false;

		break;
    case WM_CLOSE:									
        PostQuitMessage(0);							
        break; 

    default:										
        lRet = (long) DefWindowProc (hWnd, uMsg, wParam, lParam); 
        break; 
    } 
 
    return lRet;									
}

Advertisement
It probably doesn''t like the function being part of a class. Either make the function static in the class or a regular global function and it should be okay.
I put it as a global, and now it works. I had to make the application class global as well, so that winproc could access its members. That''s too bad, I was hoping for an app without globals. Oh well.
You could also have made it a friend of the class.
.
So, if I make it a friend, can I still access member variables of the application class without making the application class global?

I noticed in an example from the book: "OpenGL game programming", they somehow get a pointer to the OGlWindow that's currently being used with this:

COGLWindow *glWindow = (COGLWindow*)GetWindowLong(hWnd, GWL_USERDATA);

They do this right at the top of their WinProc function. I don't understand how that's supposed to work, because GetWindowLong returns a long. I don't understand how that could possibly be cast to a COGLWindow pointer.


If you want to see their windProc, here it is:
(Its a friend of the COGLWindow by the way)

// WndProcOGL()// desc: the WndProc for the OpenGL windowLRESULT APIENTRY WndProcOGL(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){	COGLWindow *glWindow = (COGLWindow*)GetWindowLong(hWnd, GWL_USERDATA);	// make sure window has been created	if ((glWindow == NULL) && (uMsg != WM_CREATE))	{			return DefWindowProc(hWnd, uMsg, wParam, lParam);	}	// dispatch messages	switch (uMsg)	{			case WM_CREATE:			// window creation		{			HINSTANCE hInst = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE);			glWindow = (COGLWindow*)(((LPCREATESTRUCT)lParam)->lpCreateParams);			SetWindowLong(hWnd, GWL_USERDATA, (LONG)glWindow);			glWindow->hWnd = hWnd;			return glWindow->Create();		}		case WM_QUIT:		case WM_CLOSE:				// window close			glWindow->Destroy();			PostQuitMessage(0);			return 0;		case WM_DESTROY:			// window destroy			glWindow->Destroy();			PostQuitMessage(0);			return 0;		case WM_ACTIVATEAPP:		// activate app						if (wParam)			{					if (glWindow->fullscreen)					glWindow->BeginFullScreen(glWindow->width, glWindow->height, glWindow->bits);				ShowWindow(hWnd, SW_RESTORE);				UpdateWindow(hWnd);			}			else			{					ShowWindow(hWnd, SW_MINIMIZE);				UpdateWindow(hWnd);								if (glWindow->fullscreen)					glWindow->EndFullScreen();			}			return 0;		case WM_PALETTECHANGED:		// palette change			glWindow->PaletteChanged(wParam);			return 0;		case WM_QUERYNEWPALETTE:		// new palette			return glWindow->QueryNewPalette();		case WM_PAINT:				// paint			glWindow->Paint();			return 0;		case WM_SIZE:				// window size			if (wParam != SIZE_MINIMIZED)			{					glWindow->width = LOWORD(lParam);				glWindow->height= HIWORD(lParam);				glWindow->Size();			}			return 0;		case WM_LBUTTONDOWN:		// left mouse button			if (!glWindow->useDInput)			{				SetCapture(hWnd);				Drag = lParam;				bLMB = true;				glWindow->OnMouseDownL(glWindow->GetNormalizedPosX(lParam), glWindow->GetNormalizedPosY(lParam));			}			break;		case WM_RBUTTONDOWN:		// right mouse button			if (!glWindow->useDInput)			{				SetCapture(hWnd);				Drag = lParam;				bRMB = true;				glWindow->OnMouseDownR(glWindow->GetNormalizedPosX(lParam), glWindow->GetNormalizedPosY(lParam));			}			break;		case WM_MOUSEMOVE:			// mouse movement		{				if (!glWindow->useDInput)			{				int x  = glWindow->mouseX = glWindow->GetMouseX(lParam); 				int y  = glWindow->mouseY = glWindow->GetMouseY(lParam);				int dx = x - glWindow->GetMouseX(Drag);				int dy = y - glWindow->GetMouseY(Drag);				glWindow->OnMouseMove(x,y, glWindow->width, glWindow->height);				if (GetCapture() == hWnd)				{					// left mouse button					if (bLMB)					{						glWindow->OnMouseDragL(x,y, dx,dy);					}										// right mouse button					if (bRMB)					{							glWindow->OnMouseDragR(x,y, dx,dy);					}					Drag = lParam;				}			}			break;		}		case WM_LBUTTONUP:			// left button release			if (!glWindow->useDInput)			{				if ((GetCapture() == hWnd) && !bRMB)				{					ReleaseCapture();				}				bLMB = false;				glWindow->OnMouseUpL();			}			break;		case WM_RBUTTONUP:			// right button release			if (!glWindow->useDInput)			{				if ((GetCapture() == hWnd) && !bLMB)				{					ReleaseCapture();				}				bRMB = false;				glWindow->OnMouseUpR();			}			break;		case WM_KEYUP:			if (!glWindow->useDInput)			{				glWindow->OnKeyUp((int)wParam);			}			return 0;		case WM_KEYDOWN:			if (!glWindow->useDInput)			{				glWindow->OnKeyDown((int)wParam);			}			return 0;		default:			break;	}	return DefWindowProc(hWnd, uMsg, wParam, lParam);}


[edited by - EGD Eric on March 21, 2004 4:49:53 PM]
Here's some pseudocode:
// This creates the windowbool CWindow::Create (whatever params...){    WNDCLASSEX wc = { ..., _wndproc, ... };    // Put _wndproc where you would normally put your window procedure    // Register class    ...    // Create window    m_handle = CreateWindowEx (..., (LPVOID)this);    // (LPVOID)this is the last parameter for CreateWindowEx. It will be passed in the WM_NCCREATE (and WM_CREATE, I think) messages    return (true if succeeded);}// This is a static (and private, perhaps) function to wrap the real window procedureLRESULT CALLBACK CWindow::_wndproc (HWND wnd, UINT msg, WPARAM wp, LPARAM lp){    if (msg == WM_NCCREATE)  // This is the first message a window will receive    {        SetWindowLong (wnd, GWL_USERDATA, (LONG)((LPCREATESTRUCT)lp)->lpCreateParams);    }        CWindow* caller = (CWindow*) GetWindowLong (wnd, GWL_USERDATA);    assert (caller != NULL);    return (caller->wndproc (wnd, msg, wp, lp));}// And here's the real window procedure. There's no need for it to be staticLRESULT CWindow::wndproc (HWND wnd, UINT msg, WPARAM wp, LPARAM lp){    // Handle messages normally}

Part of the CWindow declaration (pseudocode again):
class CWindowpublic:{    bool Create (...);private:    static LRESULT CALLBACK _wndproc (HWND, UINT, WPARAM, LPARAM);    LRESULT wndproc (HWND, UINT, WPARAM, LPARAM);};


[edited by - nonpop on March 21, 2004 5:07:19 PM]

[edited by - nonpop on March 21, 2004 5:09:17 PM]

[edited by - nonpop on March 21, 2004 5:11:12 PM]
Thanks for the pseudocode, nonpop. I still don''t get how GetWindowLong manages to be cast to a pointer to the window that you want though... But as long as it works I''m happy.
In CWindow::Create() you pass the this pointer to the windows'' create parameters. When the WM_NCCLIENT message arrives, CWindow::_wndproc() reads the parameter from the CREATESTRUCT and uses SetWindowLong() to store the pointer in the windows'' user data area. When the window gets its next message, _wndproc() retrieves the caller object''s pointer from the user area and uses it to call the correct CWindow''s wndproc().

And, just in case the problem wasn''t that, if you didn''t know, pointers are just regular 32-bit integers (on 32-bit platforms). LONG, which is the type GetWindowLong() and SetWindowLong() use, is one such 32-bit integer and can thus be cast to a pointer. However, if the original integer wasn''t a valid pointer (eg. referring to a valid/allocated/etc memory address) there would be no point in casting it to a pointer.
So is it like casting a void pointer to a specified type of pointer?
Well, yes.

This topic is closed to new replies.

Advertisement