Wrapper for OpenGL, can't user member function WndProc
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?
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.
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!
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(....);
}
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.
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.
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.
IndirectX, here's what I came up with from your description:
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]
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]
return what you get from the windowprocedure..
dunno if this helps yet
[edited by - davepermen on March 24, 2002 4:30:48 PM]
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
Popular Topics
Advertisement