PDA

View Full Version : Elegant handling of windows messages



chronozphere
21-09-2009, 09:34 PM
Hey guys 8)

I have a little problem. I've written a simple openGL renderer from scratch, including a Window class, which is just a WinAPI wrapper. Now, I'm looking for an elegant way to let every window-object handle it's own messages.

The problem is that all the windows messages dispatched by DispatchMessage() end up in the WndProc function which doesn't belong to any class. At this point, we must find the window object that is associated with the HWND and call it's methods to handle the message. To do this search, a global list of window objects is neccesary. I don't think this is an elegant approach because of the use of globals. I'd rather use an elegant OOP way of dealing with this.

Can someone help me find a more elegant sollution? Does someone know how the VCL is doing this?

Thanks alot. :)

Ñuño Martínez
22-09-2009, 07:23 AM
The WinAPI window object has an extra memory space that you can use for your own purpose (i.e. store the reference of the Object Pascal's window object). I did it on C++ with the good old Windows 3.1 a lot of years ago, when Delphi and Visual were wet dreams. I was looking on the Internet and I've found the SetWindowLong/GetWindowLong functions, which are the functions I used (IIRC ::)).

The idea is to create the window object and use its handler to assign your object reference. Then the "WndProc" will extract the object reference and call the method. Be careful. The WndProc should check if the reference was assigned before to call the method and provide default behaviour because "in theory" each window object has it's own threads (on Windows 3.1 that wasn't completely true but I think it is true in modern Windows systems). IIRC there are some messages it must process before the extra memory is assigned.

Pseudo code:


(*** Remember this is PSEUDO code. ***)
CONSTRUCTOR TMyWindowClass.Create;
BEGIN
INHERITED;
SELF.WinClass := RegisterWindowClass (...);
SELF.WinHandle := CreateWindow (...);
IF SetWindowLong (SELF.WinHandle, GWL_USERDATA, LONGINT (@SELF)) <> OK THEN
RAISE Error;
END;

...

FUNCTION WindowProc (hwnd: HWND; msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT;
VAR
Window: TMyWindowClass;
BEGIN
Window := GetWindowLong (hwnd, GWD_USERDATA);
IF Window <> OK THEN
DefaultMessageProc (...)
ELSE
Window.ProcessMessage (...);
END;


I hope you get the idea. I did it a lot of time ago, when Windows 3.1 was The Future.

Investigate about the SetWindowLong, GetWindowLong and related functions.

chronozphere
22-09-2009, 07:46 AM
Thanks, I'll try that. ;)