Wrapper for OpenGL, can't user member function WndProc

Started by
27 comments, last by MikeD 22 years ago
Hmm, I decided to use smitty1276''s idea and it worked. Just one question though, is it normal for regular Windows app which paints "Hello World!" to the middle of a form to utilize 100% of the CPU?
Advertisement
I can see how this solves the problem of wrapping a window in a class, but what about deallocating the object? If the WndProc is inside the class the WM_QUIT message can''t call "delete this". You could have a static STL map of HWND''s->this'' and deallocate objects in the static WndProc, but how do you notify the remaining portion of your application? The part that called the object''s constructor? You could send an event or post a message, but this seems to be getting out of hand. Wrapping a window in an object ought to be easier than this.
Sort of makes me wonder if wrapping an OGL Window in a class is even worth the effort... :/
Bump
quote:Original post by Wheaty
The one method of implementing a solution to the WndProc problem that intrests me is the one that Heaven posted. However, I am curious: What does the MainWndProc() function handle, and what does the PrivateWndProc() function handle? Can you maybe explain the relationship between these two in greater detail? Are you using MFC to make use of the SetProperty() func? Any help is appreciated, thanks!


Let me show you how I''ve got things set up, and then how I use it (WindowProc). Keep in mind that I''ve stripped a lot of stuff not important in the relating of the concept.

class CWindow
{
BOOL Register(WNDPROC);
BOOL Create(CGameApp *);
HWND Handle;
}

BOOL CWindow::Register(WNDPROC WndProc)
{
WNDCLASS wc;
...
wc.lpfnWndProc=(WNDPROC)WndProc;
...
}

BOOL CWindow::Create(CGameApp *pThis)
{
...
if (!(Handle=CreateWindowEx(blah)))
return(FALSE);
SetProp(Handle,"WINDOWPROC",(HANDLE)pThis);
...
}

class CWinApp:public CWindow,
public CKeyboard,
public CMouse
{
BOOL Ready;
MSG Msg;
static LRESULT CALLBACK MainWindowProc(HWND,UINT,WPARAM,LPARAM);
BOOL Startup(CGameApp *);
}

BOOL CWinApp::Startup(CGameApp *pThis)
{
...
if (!Register(MainWindowProc))
return(FALSE);

if (!Create(pThis))
return(FALSE);
...
}

static LRESULT CALLBACK CWinApp::MainWindowProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
CGameApp *pThis=(CGameApp *)GetProp(hWnd,"WINDOWPROC");

if (pThis)
return(pThis->WindowProc(hWnd,msg,wParam,lParam));

return(DefWindowProc(hWnd,msg,wParam,lParam));
}

class CGameApp:public CWinApp,
public COpenGL, // could be CDirectX if I wanted to implement D3D style rendering
public CMap,
public CObjects
{
CGameApp(void);
LRESULT CALLBACK WindowProc(HWND,UINT,WPARAM,LPARAM);
}

CGameApp::CGameApp(void)
{
...
if (!Startup(this))
Ready=FALSE;
else
Ready=TRUE;
...
}

LRESULT CALLBACK CGameApp::WindowProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
switch(msg)
{
case WM_...:
{
...
return(0);
}
...
}
return(DefWindowProc(hWnd,msg,wParam,lParam));
}

int WINAPI WinMain(blah)
{
CGameApp GameApp;

if (!GameApp.Ready)
return(0);

// do main loop here
return(GameApp.Msg.wParam);
}

That should spell it out quite nicely for you.

If you have any questions please ask!

Care,
Chris Rasmus

Florida, USA
RTS Engine in Development
http://www.knology.net/~heaven
Jesus is LORD!
Florida, USA
Current Project
Jesus is LORD!
It worked!!

Now I don''t need that global callback func anymore!

Btw, one prob I encountered with the methodes described above
is that the window "looses" a couple (4 last time i checked) of msg''s sent to the window when it''s created.
That ment that WM_CREATE never reached my WindowProc() =(

Ie.

CLASSNAME::Create()
{
CreateWindowEx(.....);
// I added a breakpoint in the MainWindowProc func, and it
// breaked before the one on SetProp.
SetProp(....);
}
What you are trying to do is to write your own MFC.

Now if you could just use the search, you''d get LOADS of threads that answered this very question, and presented elegant solutions.

The way you do it is this.

When you register class, allocate 4 extra bytes per-window. Set cbWndExtra to 4.

When you call CreateWindow, it takes lpParam. Set it to "this". In your static WndProc, handle WM_NCCREATE. WM_NCCREATE''s lParam is an LPCREATESTRUCT which contains lpCreateParams. You set lpCreateParams earlier to "this". Now call SetWindowLong(hwnd, GWL_USERDATA, lpCreateParams). Don''t return yet.

Now for all messages, including WM_NCCREATE, do the following.
CWindow *pWindow = (CWindow *) GetWindowLong(hwnd, GWL_USERDATA);pWindow->PrivateWndProc(hwnd, msg, wParam, lParam); 

Your PrivateWndProc will get all messages from the first to the last. You should add a check to make sure pWindow is not NULL here.

Finally, if you allocated CWindow pointer with new, in your PrivateWndProc handle WM_NCDESTROY and do a delete this; in it.

It would be nice to add answers to WNDCLASS and link error questions to FAQ.
---visit #directxdev on afternet <- not just for directx, despite the name
IndirectX, here's what I came up with from your description:

LRESULT CALLBACK CWindow::MainWndProc(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam){	switch (umsg)	{	case WM_NCCREATE:		SetWindowLong(hwnd, GWL_USERDATA, lparam);	default:		CWindow *pWindow = (CWindow*)GetWindowLong(hwnd, GWL_USERDATA);		if (pWindow)			pWindow->PrivWndProc(hwnd, umsg, wparam, lparam);		break;	}	return DefWindowProc(hwnd, umsg, wparam, lparam);}LRESULT CALLBACK CWindow:: PrivWndProc(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam){	PAINTSTRUCT paintStruct;	char string[] = "Hello World!";	switch (umsg)	{	case WM_CREATE:		return 0;		break;	case WM_CLOSE:		PostQuitMessage(0);		return 0;		break;	case WM_PAINT:		hDC = BeginPaint(hwnd, &paintStruct);		SetTextColor(hDC, COLORREF(0x00FF0000));		TextOut(hDC, 150, 150, string, sizeof(string)-1);		EndPaint(hwnd, &paintStruct);		return 0;		break;        case WM_NCDESTROY:		delete this;		return 0;		break;	default:                return 0;		break;	}	return DefWindowProc(hwnd, umsg, wparam, lparam);}  

Everything seems to work fine, however, when I quit the program, it still remains running in memory.

[edited by - Wheaty on March 24, 2002 3:40:18 PM]
if (pWindow) RETURN pWindow->PrivWndProc(hwnd, umsg, wparam, lparam);
return what you get from the windowprocedure..

dunno if this helps yet



[edited by - davepermen on March 24, 2002 4:30:48 PM]
If that's not the help you're after then you're going to have to explain the problem better than what you have. - joanusdmentia

My Page davepermen.net | My Music on Bandcamp and on Soundcloud

quote:Original post by davepermen
if (pWindow) RETURN pWindow->PrivWndProc(hwnd, umsg, wparam, lparam);
return what you get from the windowprocedure..

dunno if this helps yet



[edited by - davepermen on March 24, 2002 4:30:48 PM]


Ah yes, actually it was a combination of returning the pWindow->PrivWndProc() call, and removing the "return 0;" from the "default:" action in PrivWndProc().

Here's the fixed code for anyone who's interested:

LRESULT CALLBACK CWindow:: PrivWndProc(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam){	PAINTSTRUCT paintStruct;	char string[] = "Hello World!";	switch (umsg)	{	case WM_CREATE:		return 0;		break;	case WM_CLOSE:		PostQuitMessage(0);		return 0;		break;	case WM_PAINT:		hDC = BeginPaint(hwnd, &paintStruct);		SetTextColor(hDC, COLORREF(0x00FF0000));		TextOut(hDC, 150, 150, string, sizeof(string)-1);		EndPaint(hwnd, &paintStruct);		return 0;		break;	case WM_NCDESTROY:		delete this;		return 0;		break;	default:		break;	}	return DefWindowProc(hwnd, umsg, wparam, lparam);}LRESULT CALLBACK CWindow::MainWndProc(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam){	switch (umsg)	{	case WM_NCCREATE:		SetWindowLong(hwnd, GWL_USERDATA, lparam);	default:		CWindow *pWindow = (CWindow*)GetWindowLong(hwnd, GWL_USERDATA);		if (pWindow)			return pWindow->PrivWndProc(hwnd, umsg, wparam, lparam);		break;	}	return DefWindowProc(hwnd, umsg, wparam, lparam);} 



[edited by - Wheaty on March 24, 2002 4:34:10 PM]

This topic is closed to new replies.

Advertisement