Sign in to follow this  
NickGravelyn

Problem Passing WndProc as Parameter

Recommended Posts

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

Share this post


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

Share this post


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

Share this post


Link to post
Share on other sites
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);
};


Share this post


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

Share this post


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

Share this post


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

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this