API to OO

PGUI: API to OO

Here we explain how to use object-oriented -programming in creating Windows API -programs. We use an example program that also demonstrates the implementation of class libraries (like MFC) on top of Windows API.

API programming

The central idea in Windows API -programming is the use of window classes for dispatching event messages to windows. Each window class stores a pointer to the window procedure function with signature

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, 
WPARAM wParam, LPARAM lParam)

Where the hWnd is a handle to a window structure (of a window object), and message is an identifier of the message type. The window class is created by registering it to the Windows-system.

WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WndProc;
...
return RegisterClass(&wc);

When the application receives a message it dispatches the message to a window. The window includes a reference to the window class where the window procedure can be called with the message details. All of this gets done in a message loop which resides in the WinMain-function (entry point of the application):

int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, 
LPSTR lpCmdLine, int nCmdShow)

See Hello, Win API -example program for further details.

Making it simple

To make Windows API programming simple and OO we aim to hide all of the detaile about window classes. Thus we also hide the registration of window classes and actually the whole main program (WinMain). To implement a very simple demonstration program we would only write:

class TestWindow: public Window
{
protected:
	void OnPaint(HDC);
};

class TestApplication: public Application
{
  protected:
  BOOL InitApplication();
};

// the application object must be created somewhere
TestApplication testApp;

void TestWindow::OnPaint(HDC hdc)
{
  ::TextOut(hdc, 0, 0, "Testing...", 10);
}

// create the main window in here
BOOL TestApplication::InitApplication()
{
  mainWindow = new TestWindow();
  mainWindow->Create("API to OO");
  return true;
}

There are two problems in making the above possible in API programming:

  1. How to initialize the application an start the message loop without changing the WinMain -function.
  2. How to pass the messages to the virtual member functions of the TestWindow -class.

Window procedure

The event messages are sent to the window procedure. The window procedure has the signature shown above. The window procedure cannot be a member function of the Window -class. Why?

We can, however, implement a generic window procedure that calls the member function of our window object. We need to store a pointer to the window object into the Win32 window structure with

Window *wPtr;
...
SetWindowLong(hWnd, 0, (long) wPtr);

This can be called in the generic window procedure during the creation of the window. After that we can get the pointer by calling

wPtr = (Window*) ::GetWindowLong(hWnd, 0);

Now we can call a method that is almost like the window procedure:

wPtr->WndProc(message, wParam, lParam);

This method can be a protected member function of the base window class. It can call more detailed message processing functions like OnPaint.

WinMain

Hiding WinMain involves creating a singleton application object that is available to generic processing. We can store the singleton as a static member of the Application -class:

public:
// the singleton application object
static Application* theApp;

This application object is used in the WinMain -function

int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hPrevInst,
                     LPSTR lpCmdLine, int nCmdShow)
{
   if (!Application::theApp) return 0;
   Application::theApp->InitApplication(hInst, lpCmdLine, nCmdShow);
   return Application::theApp->RunApplication();
}

The reference to the application object gets created when one application object is constructed:

Application::Application()
{
   theApp = this;
   mainWindow = NULL;
}

The application program can create an application object by declaring it as a global variable. See above.

Example program

Here is the complete example program called "APItoOO":

Example directory (zipped)
Application.h, Application.cpp
Window.h, Window.cpp
TestApplication.cpp

See also:
Hello, World -examples