Re: winprocs as member functions

Cameron Hutchison (camh@nospam.orthanc.apana.org.au)
Sun, 7 Jul 1996 12:16:51 +1000 (EST)

Once upon a time Deadman said...
>
> If the x faithful will humor me, i have a ms windows programming query.

Ok, as long as you forget that I answered this. I will disavow any
knowledge of this message :-)

> Does anyone know a way to specify a member function of a class as the
> window procedure (the lpfnWndProc member in a WNDCLASS struct) for a
> window. Apparently it is illegal to simply assign a member function of
> an object to a WNDPROC variable. This makes it very difficult to write an
> elegant abstract window class while maintaining *pure* oo.

First of all, forget *pure* oo. If it can be done more easily reverting
to a little procedural programming, do it. In the case of callbacks, its
usually necessary to break out of *pure* oo as the thing doing the
callbacks is often not *pure* oo. So you need some sort of interface.

If I remember correctly, each windows process has a single callback from
windows, called the windows procedure. From what you've written, it looks
like it is also possible to assign a separate callback for separate
windows. As long as each of these callbacks include the window handle
(HWND or something), then you're set. If you can specify some sort of
client data to be passed to the callback that can be different for each
window, then you're set.

Its illegal to assign a member function to a callback because it doesnt
make sense to do so. A callback is a global function that operates on no
particular object and has all the necessary parameters passed to it. A
member function implicitly operates on an object, and usually has the
object on which it is to operate passed implicitly (ie. a hidden first
parameter called 'this'; this method is compiler dependent, but its also
widely used). The windows callbacks has no implicit objects, so it cannot
be a member function.

So, what you need to do is use one of the windproc arguments to identify
an object onto which to pass the callback. If you can only identify the
window by the handle (HWND), then you'll need a map to map the handle
into an object pointer. If you can specify your own client data in the
callback, you could make this the address of the object and just cast the
data to the appropriate object pointer and call it directly. I dont
recommend this method - its not very robust. So, here's some sample code
for the HWND method.

[set your tab stops to 8]

class MSWindow
{
public:

virtual long wndProc(...);

friend long WndProc(HWDN window, ...) = 0;

protected:
void addSelfToMap(HWND window);

private:
static Map<HWDN, MSWindow *> MyWindowMap;
};

long FAR PASCAL _export
WndProc(HWND window, ...)
{
if (MSWindow::MyWindowMap.contains(window))
{
return MSWindow::MyWindowMap.item(window)->wndProc(...);
// return MSWindow::MyWindowMap[window]->wndProc(...);
}
// Handle unknown window here
}

void
MSWindow::addSelfToMap(HWND window)
{
if (!MyWindowMap.contains(window))
{
MyWindowMap.add(window, this);
}
// handle case of HWND already in map
}

All your window objects should be derived from the MSWindow class. If
the window wanted to receive callbacks, it would call the <addSelfToMap>
member function to bind a HWND to itself, and it should provide an
implementation of the virtual function <wndProc>.

The Map object is just a standard map that exists in most class
libraries. They are also known as associative arrays or dictionaries.

So the only non-pure oo stuff is the window procedure, but that cant be
pure oo because windows requires it to be an external function (with
pascal linkage, no less). The rest can be as oo as you want it.

Cheers

-- 
Cameron Hutchison (camh@nospam.orthanc.apana.org.au) | Beware of the clams
GCS d--@nospam. -p+ c++(++++) l++ u+ e+ m+(-) s n- h++ f? !g w+ t r+