Delegators #1 – C++ & Win32

In the technical point of view a Delagator is a call-forwarder, as simple as that. But in the designing aspect it is a technique where an object outwardly expresses certain behaviour but in reality delegates responsibility for implementing that behavior… And thanks for Wiki for sparing me the ugly explanation. :)

The reason I came up to want to implement delegators as seamlessly as possible in C++ was because I got to a situation where I wanted to write a pure OOP wrapper for windows objects (CreateWindow). Now let me get into the juicy details before you raise your eyebrows. And even before that – yes, something like ATL but only for windows. So say you have a class that is responsible for creating a window and controling it by handling its messages and stuff. Sounds legitimate, right? It would look something like:

class Window {
public:
Window(const cstring& name) { m_hWnd = CreateWindow(…) }
void Show () { ShowWindow(m_hWnd, SW_SHOW); }
 …
 ..
private:
 HWND m_hWnd;
};

And you get the notion. It looks ok and it is right, but let’s get further and hit the problem. When we create a window we need to pass the name of the window-class, that is some structure that contains more general info about the class itself, like the background color, mouse cursor and other stuff, but the most important one of them is wndproc pointer. The wndproc pointer is a pointer to a callback function that handles the messages of the windows that belong to this window-class. I assume you know how Win32 Windows system works. Now, can you spot the problem already?

Well, since it asks for a pointer to a function, and we want to have an instance of our Window object per window, there is no way to bind between the two. (OK, I lie, but continue reading please). In our case we would like to have the method of our message-handler being called and not a global function. If you’re not sure why, then think that each window has some private members in its instance that tells special things about that window. So we gotta find a way to link between our instance and our “window-procedure” method.

This is a start:

class Window
private:
LRESULT WINAPI WndProc(HWND hWnd, UINT message, WPARAM wparam, LPARAM lparam)
{
 switch (message)
 {
  …
  ..
 }
 return DefWindowProc(hWnd, message, wparam, lparam);
}
public:
static LRESULT WINAPI WndProc(HWND hWnd, UINT message, WPARAM wparam, LPARAM lparam)
{
 // Delegate to the instance’s window procedure.
 return g_window.WndProc(hWnd, message, wparam, lparam);
}

So now the window-class structure will point to the static function WndProc which when called will delegate its parameters to the internal (private) WndProc that can access the members. It’s almost a good solution. But now we are allowed to have only one window and a global instance that contains it. The good thing is that a static public function can call a private method of the same class, so we can hide the core of it. The bad thing is we still expose an internal function we don’t want to in the first place.

The problem is now to find a way to link between a real window object and our instance. The ID of a window is its HWND (or Handle to Window). So we could hold a list with all HWND’s we created and look it up before delegation and then make the right call to the correct instance. This is too much hassle for nothing. There ought to be a way to store some private data on the window object itself, right? At least I would suspect so. Eventually, after reading some MSDN and searching the net, I found a savior function which is called SetProp (and GetProp ofc). Exmaining their prototypes:
BOOL SetProp(HWND hWnd, LPCTSTR lpString, HANDLE hData);
HANDLE GetProp(HWND hWnd, LPCTSTR lpString);
We actually have a kind of dictionary, we give a string and store a pointer (to anything we’re upto). Afterwards, we can retrieve that pointer by using GetProp. Let’s work it out again:

ctor:
m_hWnd = CreateWindow(…);
SetProp(m_hWnd, “THIS_POINTER”, (HANDLE)this); // Ah ha!

What we did was to link the HWND with the this pointer. The window procedure will look like this now:

static LRESULT WINAPI WndProc(HWND hWnd, UINT message, WPARAM wparam, LPARAM lparam)
{
 Window* pThis = (Window*)GetProp(m_hWnd, “THIS_POINTER”); // Some magic?
 if (pThis != NULL) return pThis->WndProc(…); // Forward the call to the correct instance.
 …
 …
 return DefWindowProc(…);
}

 Well, as for the code here, I don’t handle errors, and I use C casts, so sue me :). I merely wanna show you the mechanism. And if you really wanna get dirty, you will have to RemoveProp when you get WM_NCDESTROY, etc…

After I got this code really working, I still was wondering how ATL does this binding. So I took a look at their code… It seems to have a global linked list with all instances of the windows that ATL created. And then when the global window procedure is get called, it looks it up on that list. In reality it is much more complex then my explanation, since they need to synchronize accesses among threads, make sure the window belongs to the same thread, etc… All that for only the first time call of the window-procedure. Then it sets the REAL ‘window-procedure’ method of the instance itself, and there it uses Assembly, muwahaha. That will be covered next time.

BTW – SetWindowLong cannot work since all you can do is changing the window-class fields. Although, maybe there is some undocumented field you can play with to store anything you like. Never know? :)

3 Responses to “Delegators #1 – C++ & Win32”

  1. tom says:

    I asked for the reason for choosing assembly code in the WTL newsgroup, and here’s the reply from the Nanad:
    “Two very good reasons:
    1. Speed
    2. GetProp and GetWindowLong don’t guarantee that data won’t be overwritten by accident”
    “”
    http://tech.groups.yahoo.com/group/wtl/message/15160

  2. arkon says:

    Yep I said that myself, but again, if there is a malicous window runnin, it can screw up everything anyway, so it doesn’t really matter… Well it’s harder to screw up a delegator than overriding a prop/long by an accident.
    Thanks for info.

  3. Ahmed Essam says:

    I have been in same problem before, I fixed it with the observer pattern

    I did something called “CWindowMessageRotuer” :D nice name, it has register GUI Object (XObject is abstract class that has the events that will be sent to the object)
    there is unregistered, it works perfectly for me, the nice thing is I Was able to make it work for timers too.
    anyways, it is nice topic and I really learnt a lot about windows when I did this thing.
    By the way, my style was stable but it has some minor problems that could happen for people who don’t know how to play with virtual functions and stuff like that

Leave a Reply