C++ Win32 API Simple GUI Wrapper

How would you like to write your Windows Graphical (Win32 GUI) software as EASY as this?

MyWindowClass wndClass (hInstance, TEXT("GenericWindowClass"));
MyWindow wnd(hInstance, TEXT("My Window Title"), wndClass.className ());


Easy programming in Win32 isn't it?


Simple C++ Win32 API Wrapper Tutorial

You should understand C++ class inheritance and polymorphism, that is, abstract classes, virtual functions, pure virtual functions.

You should know that this tutorial assumes you have a thorough understanding of C++ and a basic understanding of Win32 API.

You'll notice the use of the C++ scope resolution operator when calling Win32 API functions such as ::CreateWindowEX () or ::RegisterWindowEx(). That's just a habit of mine when calling these kind of functions, basically it tells C++ to search the functions in the global namespace.

How would you like to write your Win32 programs like this?

MyWindowClass wndClass (hInstance, TEXT("GenericWindowClass"));
MyWindow wnd (hInstance, TEXT("My Window Title"), wndClass.className ());

wnd.Create ();
wnd.Show ();

/* message loop */

Everyone knows that creating a window is not an simple task but a rather tedious one, so I'm going to try and make it easier. This method is very similar to Qt, Java, or WxWidgets.

The Problem

If you ever tried wrapping a window's functionality I bet the first thing you asked yourself was: "What am I going to do with the window procedure?". I also bet this was the first answer that crossed your mind: "I'm just going to declare it as a member function within my window wrapper class and then I'm gonna pass it to the WNDCLASSEX structure as the lpfnWndProc field."
Well, unfortunately that won't work. Why? Because member functions have an additional hidden parameter, the this pointer, so instead of LRESULT CALLBACK wndProc (HWND, UINT, WPARAM, LPARAM) your member function will be LRESULT CALLBACK memberWndProc (YourClassName *this, HWND, UINT, WPARAM, LPARAM).
Obviously you won't be able to do the assignment wcx.lpfnWndProc = memberWndProc because the two function pointers are of different types.

So how do we solve this? We'll use a static member function that will act as a message router. A static member function can be called without creating an instance of the class, therefore it doesn't have the this pointer in its parameter list, allowing us to pass it as the lpfnWndProc member in WNDCLASSEX.

Message router you say? Yes, because the window procedure is going to be a static member function, we can't redefine its behavior in derived classes so we're gonna use a little hack. We're gonna declare another window procedure function that will be implemented in derived clasess and will do the actual message processing particular to each window. The static message router is going to determine which instance's window procedure to call by associating the window's HWND handle with a pointer to the derived class instance. This will be explained later.

Window Wrapper

First we create an abstract window class, let's call it AbstractWindow. Later, we are going to create our own windows by deriving this class and defining some of its member functions.

// This is "AbstractWindow.h"

class AbstractWindow {
                // window handle
                HWND _hwnd;

                // ... other members ...
                AbstractWindow () {}

                // this will be WNDCLASSEX::lpfnWndProc
                static LRESULT CALLBACK msgRouter (HWND, UINT, WPARAM, LPARAM);

                // this is the actual window procedure
                // this will be implemented in derived classes and will be called by msgRouter
                virtual LRESULT CALLBACK wndProc (HWND, UINT, WPARAM, LPARAM) = 0;

                // calls CreateWindowEx, creating the window
                virtual bool Create ();
                // ... other member functions ...

Notice the pure virtual function wndProc, this is the actual window procedure that will be implemented in derived classes, the static msgRouter function only determines the instance of AbstractWindow to send the message to and calls its wndProc. How?

  1. In the AbstractWindow::Create () method, we're gonna pass the this pointer as the last parameter of CreateWindowEx().
  2. Then, CreateWindowEx() sends it to msgRouter through a WM_NCCREATE message. (Details: the pointer is stored in the LPARAM parameter as a LPCREATESTRUCT structure, in the lpCreateParams field. Not important)
  3. We then handle the WM_NCCREATE message and associate the AbstractWindow pointer with the window's HWND using SetWindowLong ().
  4. Then, we retrieve the AbstractWindow pointer using GetWindowLong () and call its wndProc method that will do the actual processing.

So basically that is what will happen for every newly created window. For an existing one, when messages arrive in msgRouter, we'll have the window's handle which we'll use to retrieve the pointer to its AbstractWindow object that contains its window procedure, then we'll forward the message there.

Here's the code:

// This is "AbstractWindow.cpp"
#include "AbstractWindow.h"

bool AbstractWindow::Create ()
        // we'll just assume CreateWindowEx ()'s parameters are protected members of AbstractWindow
        _hwnd = ::CreateWindowEx (
                        this                    // pointer to this class instance

        if (!_hwnd) return false;
        else return true;      
LRESULT CALLBACK AbstractWindow::msgRouter (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
        AbstractWindow *wnd = 0;        // pointer to the window that should receive the message

        if (message == WM_NCCREATE) {  
                // if this message gets sent then a new window has just been created,
                // so we'll asociate its handle with its AbstractWindow instance pointer
                ::SetWindowLong (hwnd, GWL_USERDATA, long((LPCREATESTRUCT(lParam))->lpCreateParams));

        // --- messages different from WN_NCCREATE / or WM_NCCREATE was just processed ---
        // we retrieve the instance of AbstractWindow that corresponds to the destination window's HWND
        wnd = (AbstractWindow *) (::GetWindowLong (hwnd, GWL_USERDATA));

        // we then route the message to the wndProc method defined in the derived AbstractWindow class
        if (wnd)
                wnd->wndProc (hwnd, message, wParam, lParam);
                // for messages that arrive prior to WM_NCCREATE
                // and the HWND <-> AbstractWindow * association was not made
                return ::DefWindowProc (hwnd, message, wParam, lParam);

Now the only thing left is to derive a class from AbstractWindow and define its wndProc method. Before doing that I'm gonna show you how to wrap the WNDCLASSEX structure so you can easily create a Window Class that uses the AbstractWindow::msgRouter as its window procedure.

The Window Class Wrapper

Before creating a window we must first create a Window Class. I'm hoping that by this time you know what I mean by a Window Class. The following C++ class will wrap a Window Class more precisely the WNDCLASSEX structure, the other one above wrapped a window.
There are several ways of doing this, but the only thing each implementation must have in common is setting the lpfnWndProc field of WNDCLASSEX to AbstractWindow::msgRouter, because that's the place we want all the messages for our windows to go.

So let's call this class SimpleWindowClass. Basically, the only input the class' constructor needs is the application's HINSTANCE and the Window Class name.
This would be one way of implementing it:

// This is "SimpleWindowClass.h"

class SimpleWindowClass : protected WNDCLASSEX {
                SimpleWindowClass (HINSTANCE hInst, const TCHAR * className);

                // registers the class
                virtual bool Register ();
                //retrieve the class name
                virtual const TCHAR * className () const { return lpszClassName; }

                // --- all WNDCLASSEX's members are protected, so they can be inherited by derived classes ---

The class inherits from the WNDCLASSEX structure, has a virtual member function that retrieves the Window Class' name, a Register() member function that calls the RegisterClassEx() Win32 function to register the window class, and a constructor that will fill in the WNDCLASSEX structure.
Here's the implementation:

// This is "SimpleWindowClass.cpp"
// include the AbstractWindow header,
// we need it for the lpfnWndProc = AbstractWindow::msgRouter assignment
#include "AbstractWindow.h"    
#include "SimpleWindowClass.h"

SimpleWindowClass::SimpleWindowClass (HINSTANCE hInst, const TCHAR *className)
        // could've used GetModuleHandle (NULL) instead of passing the instance as a parameter
        hInstance = hInst;                             
        // all messages for windows belonging to this Window Class will get sent to msgRouter
        lpfnWndProc = AbstractWindow::msgRouter;       
        lpszClassName = className;

        // --- set default values for the rest of the WNDCLASSEX structure ---
        // --- later you can derive your own class and modify this behavior ---
        lpszMenuName = 0;
        cbSize = sizeof (WNDCLASSEX);
        cbClsExtra = 0;
        cbWndExtra = 0;
        style = 0;
        hIcon = ::LoadIcon (NULL, IDI_APPLICATION);
        hIconSm = ::LoadIcon (NULL, IDI_APPLICATION);
        hCursor = ::LoadCursor (NULL, IDC_ARROW);
        hbrBackground = (HBRUSH) ::GetStockObject (COLOR_BTNFACE);     

        // --- the constructor won't call the Register () member function ---
        // --- that was my choice, again, you can change the behavior in your code ---

bool SimpleWindowClass::Register ()
        if (::RegisterClassEx (this)) // we pass the this pointer because our class inherits from WNDCLASSEX
                return true;
                return false;

Great! We've just simplified the Window Class creation from manually filling a WNDCLASSEX structure and calling RegisterClassEx() to declaring a SimpleWindowClass object and calling its Register() member function.
Now let's create a SimpleWindow class that will inherit from AbstractWindow and implement the wndProc member function allowing our window to "work".

4. Create windows by subclassing AbstractWindow

The only thing left to do now is to inherit from AbstractWindow and create our window's behavior by defining the wndProc pure virtual function.
Let's start:

// This is "SimpleWindow.h"
#include "AbstractWindow.h"     // include the AbstractWindow header file, needed for inheritance

class SimpleWindow : public AbstractWindow {
                // the constructor takes two arguments, the window's title, and the Window Class' name
                // the Window Class must be registered using the SimpleWindowClass object
                // you can retrieve the Window Class name using the SimpleWindowClass::className () method
                SimpleWindow (const TCHAR *windowName, const TCHAR *className);

                // this is our window's procedure, you're gonna implement it like any other window procedure
                virtual LRESULT CALLBACK wndProc (HWND, UINT, WPARAM, LPARAM);
                // shows the window on the screen and updates its client area
                void Show () {
                        ::ShowWindow (_hwnd, SW_SHOW);
                        ::UpdateWindow (_hwnd);

Now we're gonna define the constructor and the window procedure. In this case the constructor is just going to set default values for CreateWindowEx()'s parameters.

// This is "SimpleWindow.cpp"
#include "SimpleWindow.h"

SimpleWindow::SimpleWindow (const TCHAR *windowName, const TCHAR *className)
        :       AbstractWindow ()
        // --- we're going to assume the following members are declared in AbstractWindow as protected ---
        _windowName = windowName;
        _className = className;
        _hInstance = ::GetModuleHandle (NULL); // or you could've passed the HINSTANCE as a constructor parameter
        _y = _x = CW_USEDEFAULT;
        _height = _width = CW_USEDEFAULT;
        _styleEx = 0;
        _hwndParent = 0;
        _hMenu = 0;
        // --- again those were supposed to be protected members of AbstractWindow ---

// our window procedure, this is were we define our window's behavior
LRESULT CALLBACK SimpleWindow::wndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
        switch (message)
                case WM_CREATE:
                        ::MessageBox (hwnd, TEXT("Window has been successfully created"), TEXT("Succes"), MB_OK);
                        return 0;
                case WM_DESTROY:
                        ::PostQuitMessage (0);
                        return 0;
                        return ::DefWindowProc (hwnd, message, wParam, lParam);

By this time we've drastically reduced WinMain's size.

Your New Simple WinMain

In the new WinMain we'll just create a Window Class by creating a SimpleWindowClass object and calling its Register() member function, then we're gonna create a window by creating a SimpleWindow object, and calling its Create() and Show() member functions. Of course we're also going to need a message loop.

#include "SimpleWindowClass.h"  // create a Window Class
#include "SimpleWindow.h"       // create a window

int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
        // create the Window Class
        SimpleWindowClass wndClass (hInstance, TEXT ("My window class"));
        wndClass->Register ();

        // create the window,
        SimpleWindow wnd (TEXT ("Generic Window Title"), wndClass->className ());

        // show the window on the screen
        wnd->Show ();
        // pump messages:
        MSG  msg;
        int status;
        while ((status = ::GetMessage (&msg, 0, 0, 0 )) != 0)
                if (status == -1) {
                        // handle the error, break
                ::TranslateMessage (&msg);
                ::DispatchMessage (&msg);                              
        return msg.wParam;

That's all there is to it. From now on there are endless possibilities. You can modify your window wrapper or your Window Class wrapper the way you want them to work.
An interesting thing you could do is add message handlers, such as OnCommand (), OnCreate (), OnPaint () and so on. You would need to define their default behavior in the AbstractWindow class and then in the msgRouter you would forward each message to its handler. Then in your derived classes you would only define handlers for the messages you'd like to handle, the rest will be handled by the base class, that is, AbstractWindow. The final result would be an MFC-like window class, with member functions for each message, this way you would get rid of the window procedure for ever.
Let me show you what I mean:

/* ---- AbstractWindow.h ---- */
class AbstractWindow {
        // --- previous class definition here ---

                virtual bool OnCommand (int ctrlId, int notifyCode) { return false; }
                virtual bool OnDestroy () { ::PostQuitMessage (0); return false; }
                virtual bool OnClose () { return false; }
                // --- and so on, add as many handlers as necessary ---
                // --- and define their default behavior ---
                // --- usually they return 0, but check MSDN for details ---

/* ---- AbstractWindow.cpp ---- */
LRESULT CALLBACK AbstractWindow::msgRouter (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
        AbstractWindow *wnd = 0;       
        if (message == WM_NCCREATE) {
                wnd = (AbstractWindow *) ((LPCREATESTRUCT(lParam))->lpCreateParams);
                ::SetWindowLong (hwnd, GWL_USERDATA, long(wnd));
                wnd->OnNCCreate (/* params */);
        } else {
                wnd = (AbstractWindow *) (::GetWindowLong (hwnd, GWL_USERDATA));

                if (wnd) {
                        switch (message)
                                case WM_COMMAND:
                                        return OnCommand (LOWORD (wParam), HIWORD(wParam))
                                case WM_DESTROY:
                                        return OnDestroy ();
                                case WM_CLOSE:
                                        return OnClose ();

                                // --- and so on, it'll be a lot of work to do,
                                // but most apps don't use every window message ---
                                default:        // for the messages you did not define any handlers
                                        return ::DefWindowProc (hwnd, message, wParam, lParam);
                else    // for messages that arrive prior to WM_NCCREATE
                        // and the HWND -> AbstractWindow * association was not made
                        return ::DefWindowProc (hwnd, message, wParam, lParam);

In your derived class instead of defining the old long window procedure you will only define handlers for the messages you'd like to handle, the rest of the messages will either be handled by their default handler implementation in AbstractWindow or by DefWindowProc() in msgRouter.

class SimpleWindowClass : public AbstractWindow {
        // --- rest of code here ---
        // --- constructors, private data, etc etc...
                // there is no need for a window procedure now, just add handlers.
                virtual bool OnCommand (int ctrlId, int notify Code) { /* do stuff */ }
                virtual bool OnCreate () { ::MessageBox (_hwnd, TEXT("Window created"), TEXT ("Success"), MB_OK); }
                // and so on, every message you want to handle must have a default handler in AbstractWindow
                // and you're going to implement it here, change its behavior the way you needs


Jesse's picture

Thanks, this helped a lot!

Thanks, this helped a lot!

Anonymous's picture

it'd be nice if there's a

it'd be nice if there's a downloadable code

Post new comment

The content of this field is kept private and will not be shown publicly. If you have a Gravatar account associated with the e-mail address you provide, it will be used to display your avatar.