Archived

This topic is now archived and is closed to further replies.

EGD Eric

Please help: problem with creating a win32 window

Recommended Posts

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;									
}

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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 window

LRESULT 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]

Share this post


Link to post
Share on other sites
Here's some pseudocode:

// This creates the window

bool 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 procedure

LRESULT 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 static

LRESULT CWindow::wndproc (HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
{
// Handle messages normally

}

Part of the CWindow declaration (pseudocode again):

class CWindow
public:
{
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]

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Setting the window procedure as friend allows that function to access all of the members of the class, without it being in the scope of the class.

Share this post


Link to post
Share on other sites
Alright. Thanks for the info people. Now that I''ve put enough time into studying the articlue Oluseyi sent me, along with the good abreviated version from nonpop, There''s still something that escapes me: Where is the application''s Message procedure actually called? I know that WinProc is called somewhere behind the win32 scenes (that was something that I kept trying to find when first learning Win32: "Where''s Winproc being called??"),

but... here you''re declaring your own static _winProc (or, with the tutorial it was called: "msgRouter") which calls the default WinProc at the end. Now, where''s msgRouter (_winProc, or whatever you call it) called? How do I make sure that Win32 calls it?

With PeekMessage, TranslateMessage and DispatchMessage?

How does it know which function to call? Wouldn''t it automatically call WinProc? Or does it matter what its called?

Share this post


Link to post
Share on other sites
quote:
Original post by EGD Eric
How do I make sure that Win32 calls it?

With PeekMessage, TranslateMessage and DispatchMessage?


Aye

quote:
How does it know which function to call?

You gave it a pointer to the function (it''s the line that was causing your original error)

quote:
Or does it matter what its called?

No

Share this post


Link to post
Share on other sites
Assuming that you aren''t using MFC...
To call this message handling function, either WndProc or msgRouter, you have to set up a windows message loop to translate and dispatch the messages. Here is a sample:


//========================================================

//*** RunMessageLoop ***

//*** Description: Runs the windows message loop ***

//========================================================

WPARAM CMainWindow::RunMessageLoop ()
{
MSG wndMessage;

wndMessage.message = WM_NULL;
PeekMessage (&wndMessage, NULL, 0, 0, PM_NOREMOVE);

while (wndMessage.message != WM_QUIT)
{
if (PeekMessage (&wndMessage, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage (&wndMessage);
DispatchMessage (&wndMessage);
}
// Do something here...

}

return (wndMessage.wParam);
}


This function is taken out of my wrapper class and is called from my WinMain funciton. When you call DispatchMessage, DispatchMessage will call the correct WndProc function...I hope this helps..

Share this post


Link to post
Share on other sites
quote:
Original post by EGD Eric
Why does it need to be static?


callback functions as the windowproc need to be static if they are inside a class

Share this post


Link to post
Share on other sites