[C++ Winapi] SetWindowLong and modal dialog problem

Started by
3 comments, last by adeyblue 14 years, 11 months ago
Hi I've been writing my own winapi wrapper based on the article here on gamedev.net by Oluseyi Sonaiya. This is the code for the static callback handler using SetWindowLong/GetWindowLong:

LRESULT CALLBACK WinClass::WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	// On window creation, WindowProc receives lParam as a LPCREATESTRUCT 
	// Store *this* pointer as long in GWL_USERDATA
	if (msg == WM_NCCREATE)
		::SetWindowLong(hwnd, GWL_USERDATA, reinterpret_cast<long>(reinterpret_cast<LPCREATESTRUCT>(lParam)>lpCreateParams));
	WinClass *wnd = reinterpret_cast<WinClass*>(::GetWindowLong(hwnd, GWL_USERDATA));
	
        // Call the actual winproc function
	if (wnd)
		wnd->WndProc(hwnd, msg, wParam, lParam);

	return ::DefWindowProc(hwnd, msg, wParam, lParam);
}
This works fine but I cant figure out where to store pointers to the main wnd and a modal dialog class if i create instances of both. Im using the same wrapper code above for the modal dialog within a separate MDlgClass class. If I store the long pointer for the modal dialog in the GWL_USERDATA for the dialog, it works okay but acts as a modeless dialog not modal. I've tried using DWL_USER for the dialog ptr instead but without success. I thought about using a hashmap to map the pointers but I want to implement it within SetWindowLong. Is there another way to approach this or isn't it possible?
Advertisement
I'm not sure about your problem with dialogs, but there's an error in that code you posted. You always call DefWindowProc, even when you call the WndProc method of the WinClass instance. You'll only want to call DefWindowProc if you don't have a pointer to a WinClass:

if (wnd)    return wnd->WndProc(hwnd, msg, wParam, lParam);else    return ::DefWindowProc(hwnd, msg, wParam, lParam);
Shouldn't the DefWindowProc be called for unhandled messages too?

In other words, something like this (pseudo)

if (wnd) {

retval = wnd->WndProc(hwnd, msg, wParam, lParam);

if ( retval == unhandled )
return ::DefWindowProc(hwnd, msg, wParam, lParam);
else
return retval;

} else

return ::DefWindowProc(hwnd, msg, wParam, lParam);

"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
Thanks for the help so far.

MJP, even after correcting the code to only call wndproc when I have pointer to a winclass, the dialog still doesnt return focus to the main window when I call EndDialog or DestroyWindow.

LessBread, I forgot to mention that the wndproc method contains a switch-case handle the messages and defaults to calling DefWindowProc

Any other ideas, I'm completely stuck!

message handler for winclass:
LRESULT CALLBACK WinClass::WndProc(HWND &hwnd, UINT &msg, WPARAM &wParam, LPARAM &lParam){	switch (msg)	{	case WM_COMMAND:                // virtual function overriden in classes derived from WinClass		OnCommand(hwnd, LOWORD(wParam), HIWORD(wParam));		break;	case WM_CLOSE: 		::DestroyWindow(hwnd);		break;	case WM_DESTROY:		::PostQuitMessage(0);		break;	default:		return ::DefWindowProc(hwnd, msg, wParam, lParam);	}	return 0;}


message handler for mdlgclass:
BOOL CALLBACK MDlgClass::DlgProc(HWND &hwnd, UINT &msg, WPARAM &wParam, LPARAM&){	switch (msg)	{	case WM_INITDIALOG:		break;	case WM_CLOSE:		EndDialog(hwnd, 0);		break;	case WM_COMMAND:                // virtual function overridden in classes derived from mdlgclass		OnCommand(hwnd, LOWORD(wParam));		break;	default:		return FALSE;	}	return TRUE;}
Dialogs don't receive WM_NCCREATE so if the code in the initial post is all you have in the window procedure, your DlgProc will never be called because wnd will never be set. It'll also be calling DefWindowProc which is a no-no for dialogs. Looks like you call DefWindowProc twice too, once for unhandled messages in WinClass::WndProc and then unconditionally at the end of WinClass::WindowProc, that's also something to avoid.

If you desire 64-bit portability, you'll need to use the Ptr versions of Set/GetWindowLong and change the cast type in the setting of the wnd. Something like this:

::SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(reinterpret_cast<LPCREATESTRUCT>(lParam)->lpCreateParams));WinClass *wnd = reinterpret_cast<WinClass*>(::GetWindowLongPtr(hwnd, GWLP_USERDATA));


You'd also need to change the return type of your DlgProc to INT_PTR, rather than BOOL.

This topic is closed to new replies.

Advertisement