Skip to main content
GameDev.net gamedev.net
🔒 Locked

Problem Passing WndProc as Parameter

Started by NickGravelyn Jun 6, 2006 at 2:04 PM 6 replies 900+ views
Original Post
NickGravelyn
NickGravelyn
I've created an OO window/app system, but it's not quite working. My WndProc function seems to become invalid after I create the window. I don't get any errors, but Alt-F4 and closing the window both fail to actually stop the app, whereas manually setting mainLoopDone elsewhere still does. Can anyone help me figure out what went wrong?
HRESULT App::Initialize(const AppParameters& ap)
{
	HRESULT hr = window.RegisterWindowClass(ap.wndStyle, App::StaticWndProc, ap.wndIcon, ap.wndCursor, NULL, ap.wndName);
	if(FAILED(hr))
		return hr;
        ...
}

LRESULT App::WndProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
	if(msg == WM_DESTROY ||
		msg == WM_CLOSE ||
		msg == WM_QUIT)
	{
		mainLoopDone = true;
		return 0;
	}

	return (DefWindowProc(wnd, msg, wparam, lparam));
}

LRESULT CALLBACK App::StaticWndProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
	App* parent;
	if(msg == WM_NCCREATE)
	{
		parent = (App*)((LPCREATESTRUCT)lparam)->lpCreateParams;
		SetWindowLongPtr(wnd, GWL_USERDATA, (LONG_PTR)parent);
	}
	else
	{
		parent = (App*)GetWindowLongPtr(wnd, GWL_USERDATA);
		if(!parent)
			return (DefWindowProc(wnd, msg, wparam, lparam));
	}

	return parent->WndProc(wnd, msg, wparam, lparam);
}

HRESULT Window::RegisterWindowClass(UINT style, WNDPROC wndproc, HICON icon, HCURSOR cursor, HBRUSH background, LPCSTR className)
{
	windowClass.cbClsExtra = 0;
	windowClass.cbWndExtra = 0;
	windowClass.hbrBackground = background;
	windowClass.hCursor = cursor;
	windowClass.hIcon = icon;
	windowClass.hInstance = GetModuleHandle(NULL);
	windowClass.lpfnWndProc = wndproc;
	windowClass.lpszClassName = className;
	windowClass.lpszMenuName = NULL;
	windowClass.style = style;
	
	HRESULT hr = RegisterClass(&windowClass);
        ...
}

Dave Hunt
Dave Hunt
A simple way to test your theory would be to add a MessageBox() call in your WndProc's "if (msg == WM_DESTROY...)" and see if it gets there.

The best way to solve these kinds of problems is to make use of your debugger. Set breakpoints at appropriate locations and step through the code to see where it's going wrong.
Anon Mike
Anon Mike
You need to call PostQuitMessage in your WM_DESTROY handler.
-Mike
Oluseyi
Oluseyi
Quote:
WM_CLOSE:
If an application processes this message, it should return zero.

...

By default, the DefWindowProc function calls the DestroyWindow function to destroy the window.
Quote:
WM_DESTROY:
If an application processes this message, it should return zero.
Quote:
WM_QUIT:
This message does not have a return value because it causes the message loop to terminate before the message is sent to the application's window procedure.


Your suspect message handling aside, you make some curious design decisions. Like mating window class registration to the (object-oriented) class, creating a bunch of redundant class/instance members in the process. Consider this alternative:

Window::Window(WNDCLASSEX * wcx){  WNDCLASSEX def;  if (0 == wcx)  {    // fill out 'def' structure with defaults    wcx = &def  }  RegisterClassEx(wcx); // you may wish to store the returned ATOM for, among                         // other things, an UnregisterClass call  hwnd = CreateWindowEx(...);}

In addition to eliminating an unnecessarily coupled member, this approach more closely adheres to the Resource Acquisition Is Initialization pattern, which will save you untold pain one day.
Washu
Washu
Or just use ATL...
class MainWindow : public CWindowImpl<MainWindow, CWindow, CFrameWinTraits> {public:	DECLARE_WND_CLASS_EX(L"MainWindow", CS_HREDRAW | CS_VREDRAW | CS_OWNDC, 0)	BEGIN_MSG_MAP(MainWindow)		MESSAGE_HANDLER(WM_CLOSE, OnClose)		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)		MESSAGE_HANDLER(WM_CREATE, OnCreate)	END_MSG_MAP()	LRESULT OnClose(UINT msg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);	LRESULT OnDestroy(UINT msg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);	LRESULT OnCreate(UINT msg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);};
In time the project grows, the ignorance of its devs it shows, with many a convoluted function, it plunges into deep compunction, the price of failure is high, Washu's mirth is nigh.
CrazyCdn
CrazyCdn
Like others have said, make sure you handle window messages properly. Hit google, do a "WM_SOMETHING +MSDN" search without quotes and find out exactly what you need to do. This should resolve the issue for you.

I actually had to work with WM_CREATE as WM_NCCREATE didn't work for me (it's suppose too, and has in the past but just one day my window wasn't being generated, took out the NC and it's 100%, no real loss of anything I need so I just work with it).

I'm sure ATL is fine but I hate it. I'd go mad having to do all that cap locks typing, feel like an AOL user.
"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin
NickGravelyn
NickGravelyn
It seems a large part of my problem isn't necessarily handling the messages (which after changing the handling from these response work great), but rather my window-app relationship. Does anyone have any code for how to properly (or just more efficiently) set up an OO approach to windows and app classes in C++?
hplus0603
hplus0603
I would suggest that the application has a collection of windows. Each time the message loop goes idle, the application checks whether the window collection is empty; if so, the application decides to terminate.

Windows should be responsible for adding/removing themselves in the application window collection.

Typically, object A having a collection of B, with automatic update, works well as a pattern implemented as a template.
enum Bool { True, False, FileNotFound };

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.