App0 is a C++ wrapper over Windows API calls for a typical windowed application. This is similar to the framework used in curve. The design is mostly drawn from Win32 Programming by James M. Newcomer and Brent Rector.
The BaseWnd
class wraps around a HWND
. CreateWindowEx
is called in the constructor. Before the CreateWindowEx
call, I register the window class if it has not already been registered.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
BaseWnd::BaseWnd(void): hwnd(0) { if(wndClassAtom == 0){ if(Register() == 0) throw app0_exception(ERR_CLASS_REGISTRATION_FAILED); } hwnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, MAKEINTATOM(wndClassAtom), WINDOW_TITLE, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0, 0, GetModuleHandle(0), this); if(hwnd == 0) throw app0_exception(ERR_WINDOW_CREATION_FAILED); } |
Since the WindowProc
cannot be a member function, I use two non-members: InitWndProc
is used till a WM_CREATE
is received and BaseWndProc
is used for the rest of the windows lifetime.
InitWndProc
forwards all messages except WM_CREATE
to DefWindowProc
. WM_CREATE
is forwarded to BaseWnd_OnCreate
which saves the object pointer (passed to CreateWindowEx
) at GWL_USERDATA
and also replaces the window procedure (currently InitWndProc
) with BaseWndProc
.
1 2 3 4 5 6 7 8 9 |
LRESULT CALLBACK InitWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){ if(msg == WM_CREATE){ return HANDLE_WM_CREATE(hwnd, wParam, lParam, App0::BaseWnd_OnCreate); } else return ::DefWindowProc(hwnd, msg, wParam, lParam); } |
BaseWndProc
forwards all messages to the static BaseWnd::WndProc
method which retrieves the object pointer and forwards messages to the BaseWnd::WndProc
instance method. The instance method behaves like a typical WindowProc
and forwards selected messages to other instance methods (OnWmClose
, OnWmDestroy
) while relegating all other messages to DefWindowProc
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
LRESULT CALLBACK BaseWndProc(HWND hwnd, UINT msg, // non-member WPARAM wParam, LPARAM lParam){ return BaseWnd::WndProc(hwnd, msg, wParam, lParam); } // static member LRESULT BaseWnd::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){ LONG_PTR ptr = ::GetWindowLongPtr(hwnd, GWL_USERDATA); BaseWnd* window = reinterpret_cast if(window == 0) throw app0_exception(_T("Object pointer is 0.")); return window->WndProc(msg, wParam, lParam); } LRESULT BaseWnd::WndProc(UINT msg, WPARAM wParam, LPARAM lParam){ switch(msg){ HANDLE_MSG(hwnd, WM_CLOSE, OnWmClose); HANDLE_MSG(hwnd, WM_DESTROY, OnWmDestroy); } return ::DefWindowProc(hwnd, msg, wParam, lParam); } |
I use InitWndProc
initially because until WM_CREATE
the object pointer has not yet been attached to the HWND
and BaseWndProc
depends on the object pointer.
Download source here.