[RE: [Re: [lazarus] wndproc]]

Jeff Wormsley daworm at cdc.net
Fri Aug 20 15:24:10 EDT 1999


On 8/20/99, at 6:52 PM, Michal Bukovjan wrote: 

>Now, as I remember, intercepting owner's or parent's WndProc (I know that
>trick) is generally considered a dirty hack and should be used with great
>care. Again, the form designer in Lazarus may use a completely different
>approach, since it has to be Linux-compatible. In Linux, there is no Win32 API
>to intercept any WndProc !

Something of a dirty hack, and certainly the only way to do certain things.

>Enough. Just once again - if the WndProc is really inevitable, it may be
>there, after all. But we should double-check the need for any OS
>platform-specific code.

This is very much along the lines of the problems I am having with Win32 native development.  I am passing around so many pointers to pointer, with embedded pointers to other pointers contained in window handles that embed pointers...  you get the picture, it is an absolute mess.  And all because the base class does not have a WindProc, but instead I have to rely on a single WindProc to handle the entire application.  This is a horrible way to do things.

Here is my thoughts on these differences between the way GTK works now, and how Win32 native and Delphi do things.

First my interpretation of the way things work.

In Windows, the Hwnd handle for a control is associated with two things of importance when it is created.  First is the WindowProc.  Any time Windows needs to notify an object of something, it calls the WindowProc associated with that HWnd handle.  The second important item set when HWnd is created is the Parent HWnd.  This allows Windows to automatically clean up children when the parent is destroyed, amongst other things.  What this boils down to is that all Win32 events are handled through a single callback procedure, WindProc.

GTK, on the other hand, doesn't use a single callback procedure like WindProc to perform its various functions.  Instead, it has a single callback function for each and every event or message.  This means that there is no need to have a huge Case construct to send the individual messages to the appropriate code, nor does GTK need to map every piece of data it needs to send into one common format (like Windows' wParam and lParam).  Instead, each event can pass whatever data is appropriate for that event in a format relative to that event.

Now, when an event happens in Windows, a WM_xxxx message is sent to the WindProc, and WindProc cases this message to see if the event is one it should handle, or pass on to the default window handler.

GTK on the otherhand, checks to see if a callback has been assigned, and if so calls the appropriate handler directly.  So instead of having to add a case item to WindProc, all you have to do is set a callback function address.  And unlike Windows, where you must override the WindProc to change the behavior of a control beyond the VCL's intentions, with GTK you can simply change the callback address (preserving and calling the original if needed).

So, how to we bring these totally different approaches to a common method suitable for lazarus.

One, we could limit GTK to the way Windows does things (d&rfc).  This would mean setting a generic callback for each and every callback type internal to Interfaces.pp.  This would take each message, wrap it into a standard common format, and then call the owners WindProc, where is would be broken back down into its original parts, cased, and then call the appropriate handlers if any.  Everyone will agree that this is pretty wasteful, but I hope you can see where it would make programming lazarus very much like programming Delphi, and would allow reuse of a large amount of existing code. 

Another approach would be to make Windows look like GTK.  This approach is what I have been trying unsucessfully to do for three weeks now, with little progress.  The problem here is the lack of one to one callbacks in Windows.  Everything has to go throught WindProc, and especially troubling is the fact that any attempt at emulating the GTK way of doing things requires some way to store the addresses of the callbacks.  The only good way I have found so far is to use SetProp and GetProp to store a handle to the object, and then use properties of the object that are useless in GTK, or co-opt their function (such as FComponent) to a different use.  I am sure these differences in the internals would drive the first end user to peer under the hood crazy!

The thing that is killing Win32 native work right now is not having a unique WindProc for each windowed control.  If that were the case, then there would be a much smaller case, since then only the messages that applied to that control would be present in that case statement.  All others fall out the else.

But, while putting a WindProc into TComponent or TWinControl wouldn't break GTK (No call to CreateWindow, no Hwnd, therefore WindProc is never called) it would confuse any application developer who was expecting a consistent method of overriding or extending the behavior of a control.  

What I am getting at is,  say we have a TEdit control.  This TEdit has no facility for having items dragged and dropped onto it.  Under Windows, you would intercept the message handler, check for a WM_DROP (whatever, memory bad) message, if it was found, act on it, otherwise pass control to the default handler.  In GTK, you would assign a callback.   How does the application developer write code to do this that maintains platform independence?  With the "make GTK look like Windows" approach, it looks like he just replaces checking for WM_xxx messages with checking for LM_xxx messages.  How to make it the same process for "make Windows look like GTK" I haven't a clue.

It may be that I have everything all wrong here, or am missing some obvious solution.  If so, I wish someone would point it out to me, it's giving me a headache, and no lie, I have had dreams about this for weeks.  Dreaming code isn't my favorite, I prefer flying ;^)

Jeff.







More information about the Lazarus mailing list