Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 1999-08

[RE: [Re: wndproc]]

6 messages · 4 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Markku Niskanen
to Samuel Liddicott: yes Depends on what you mean. HWND is not Win32 specific. It looks like it because of…
you wrote
but if it is presented as an integer no-one will mess about without. I also think that 16 bit windows handles were near pointers.

You are correct to some point. Charles Petzold's classic "Programming Windows" tells us:

--- clip ---
Here's one way Windows deals with moveable segments: You've seen how Windows and your programs use numbers called "handles". In many cases, the handles are really near pointers. Windows maintains a segment called BURGERMASTER (no kidding) that contains a master handle-to-memory table. The handle points to a small area of memory within BURGERMASTER that contains the segment address of the item that the handle references. When Windows moves the segment that contains the item, it can adjust the address in BURGERMASTER without invalidating the handle. BURGERMASTER is itself a moveable segment.
--- clip ---

So handles are really just a table of pointers that make it possible to manage the memory. Some of the segments are 'moveable', some in addition 'discardable' and some are 'fixed'. Well, this applies to Windows 2.0 and possibly some further versions as well, the book is dated 1988 :-)

Markku

Reply by email

Markku Niskanen
to Samuel Liddicott: yes Depends on what you mean. HWND is not Win32 specific. It looks like it because of…
you wrote
The reason delphi works like this is because they extended the windows abstraction even further so it can be used in what I am calling the GTK way (with seperate handlers - much nicer than wndproc WHEN you've got the choice) as well as via the windows way.

I cannot but agree. I have used a remarkable piece of software called Clarion for Windows for several years and cannot but love the extra abstraction that makes ordinary Windows application development
so much faster and the applications easier to maintain. Clarion goes much further in the abstraction which has lots of pros and just a few cons.

After writing a few pieces of software using plain MSC both Clarion and Delphi are like Ferraris.

I've downloaded but not examined yet how WxWindows people have overcome this problem. I know the library works in GTK and in Windows, at least.

Markku

Reply by email

Samuel Liddicott
to Jeff Wormsley: Something of a dirty hack, and certainly the only way to do certain things. This is very…
Show quoted text 8 lines
-----Original Message----- From: Jeff Wormsley Sent: 20 August 1999 08:14 PM To: Subject: Re: [RE: [Re: [lazarus] wndproc]] On 8/20/99, at 6:52 PM, Michal Bukovjan wrote:

...

Show quoted text 13 lines
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.

make that LARGE ammounts

Show quoted text 12 lines
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!

And of course make OS/2 look like GTK. We don't want to bind too strongly to any widget manager; and supporting both wndproc AND message handlers (dispatch is quick) is the only way to support both - and Delphi ALREADY supports it! Hooray!

Show quoted text 5 lines
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.

Jeff; I am fighting to have createwnd put back in and CreateParams still used. It will work fine for GTK and fine for windows if we do it that way. It will also be a first experimental stab at being able to claim that lazarus works supporting two entirely different widget sets. What I mean is you will be able to use native windows controls as you want, but use them the natives delphi:windows way.

Abstractly speaking CreateWnd is "MakeTheWidget" and CreateParams is "GetTheWidgetImplementationValues" - two functions which have place with win32 and GTK. The names are unfortunate for GTK users until there refer to widgets as WND's and then they are fine.

But, while putting a WindProc into TComponent or TWinControl wouldn't break GTK (No call to CreateWindow, no Hwnd, therefore WindProc is never called)

Except I want to change all this with GTK

it would confuse any application developer who was expecting a consistent method of overriding or extending the behavior of a control.

Thats true.

Show quoted text 14 lines
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.

You are right, and I am with you on this. I got to know the VCL inside out when I wrote the form designer, and a wndproc is absolutely essential in a) making the FCL be similar enough to VCL to be useful b) is a very good idea anyway - as you say being able to intercept messages before the message handlers is sometimes the only way to do things.

I suggested that a control have a (secret non-delphi) property call FSkipWndproc which is false by default.
The GTK handlers could then skip wndproc if this was set to true. That way the GTK-ites can imagine that they will set this to TRUE everywhere and we can imagine that we will leave it as FALSE everywhere and then we don't need to agree! For sure our code will always work with it turned on and so will theirs. If programs seem slow they can try turning it off and see if it goes much faster (it won't because if there are THAT MANY messages going round that the usually-mostly empty wndproc makes a difference then there are a LOT of messages going round - and messages don't go round for no reason at all they go round because some other action is going on and also taking up a lot of time).

So....

as you say, we need wndproc.

The gtk-ites could pretend it is merely for intecepting messages before the handlers in a platform independant way. I hope the name wndproc won't bother them too much (they could pretend it is to make the hordes of converting delphi-ites feel at home).

Sam

Reply by email

Jeff Wormsley
to Michal Bukovjan: might is the We are interested (as I understand it) in the possibility to have Lazarus for
Michal Bukovjan wrote 5 lines
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.

Reply by email

Michal Bukovjan
"Samuel Liddicott" wrote 10 lines
> I am not sure about the single WndProc either. This approach > certainly slows > things down, and I find the GTK (multiple signals) way more versatile. > I think we will have to decide if we want > 1) Lazarus to be Delphi compatible to the point that it is bound > to Windows. I don't know what you mean "bound to windows". How about "can be bound to windows"? But the only reason I'm interested in Lazarus is because it

might

compile Delphi source code with little change. The claim on the web site

is

that we are porting Delphi to linux because Borland won't. We even have

the

penguin wearing the Delphi wig. If we are only interested in superficial compatability, why even bother with that?

We are interested (as I understand it) in the possibility to have Lazarus for both Win32 and Linux, and use any arbitrary widget for visuals.

This means that we should avoid all Win32 stuff in core components like TComponent, TControl, TWinControl, and the basic set of controls, so that it is possible to write an application (using standard components) once and compile under Win32 and Linux without no code change.

I say SHOULD, but if neccessary, we may opt to insert some Win32 specific code and let it become dummy under anything else.

There was a discussion on that topic recently, including whether we should use IFDEFs and such, which resulted in those gtkint.pp, win32int.pp units and all this stuff.

So I think the possibility to use existing Delphi components descendants that work and use Win32 specific stuff (i.e. Windows messages) will be, ..er.., somewhat limited to Windows, and useless under Linux.

While this may be valid from Windows point of view (the application will not be portable, author decides), if such thing would be found in core components, that would handicap other widget platforms. And the other way around, we could certainly use some GTK specific stuff in core components, the other, including Win32 users, would be handicapped instead. Not speaking about Motif/Lesstif, Qt, or whatever.

Stop. I am not a moron :-) I am not the one who decides about this in the end, anyway (that is the core component maintainer). That is just my point of view. And since you seem to know the Win32 widgets stuff well, it may be inevitable to have some Win32 support integrated after all, if you say so, be it by IFDEFs. IMHO, that is the solution Sibyl chose, as I looked into their code.

> 2) Leave out some Delphi solutions which had to be created/were suited

for

Show quoted text 5 lines
> Windows, and supply our own, more versatile ones (be their > Delphi-incompatible). Ho ho. Don't forget we want to bind to more GUI's that GTK. OS/2 is also very win-like with a wndproc. We get speed OR flexibility.

Ok, ok :-)

Show quoted text 7 lines
> Again, remember that Delphi is VERY designed for > Windows, and if we want Lazarus for as much platforms as possible, we > definitely will need to abandon some Delphi approaches. If we want Lazarus for as much platforms as possible, we definitely do not need to rule out platform approaches.

??? What do you mean ?

Show quoted text 9 lines
> The shiny example of the 2) is Handle, which is rarely found > anywhere beyond > Windows, and since Windows get COMized, not even there in the future (my > guess). The handle is "some" reference to the "real" object that is managed by the bound GTK. This is going to be used with whatever gui we bind to. OK, handle isn't the best name UNDER GTK but its a better name under some

others

(like Win or OS2).

Yes. But while it is an integer under Win32 (32-bit), it is meant to be a pointer under GTK (which happens to be 32-bit on IA32). Then, I am not sure about 64bit platforms. (The compiler might take care about that, though).

Show quoted text 8 lines
The only reason for thinking a .wndproc slows things down is if you think what's in the wndproc isn't needed - and yes its faster if you do less. Wndprocs *are* a) A primary place to intercept and *modify* ALL messages to a component before the dispatch b) A place to intercept messages whose message number is not known at

design

time There are a lot of *components* out there that rely on this mechanism! Honest! Few applications use it, but MANY components do.

You are absolutely right on this one. Still I claim that the HUGE case statement is NOT effective. In my opinion, it is not the best approach, although it is usable.

It is true that many components DO use it, as they have no other choice under Windows, anyway (or do they?).

Show quoted text 8 lines
We need support from existing Delphi components to make Lazarus more useful quickly. We don't want much (if any) work involved in porting over components. If you like, let each component have a flag which says whether or not wndproc can be skipped. The GTK callback handler could check this flag and only call wndproc if it is not set.

Hmm, that could be a viable solution :-)

Show quoted text 12 lines
But the fact is, wndproc ONLY slows things down to any degree if there is a lot in it - in which case it is obviously important; OR because there are a lot of messages going round - in which case the computer must be quite busy doing something so quite naturally the user expects it to take much more time than the wndproc overhead is going to add. Trust me, we NEED .wndproc - HEY the delphi form designer "requires" .wndproc so it can intercept the paint messages to the form and paint the grid. The ability to intercept the wndproc of another component is also VERY COMMONLY USED. So we can't even presume that the primary .wndproc for a control is control.wndproc - but we can implement this later.

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 !

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.

Have fun,

Michal Bukovjan

____________________________________________________________________ Get your own FREE, personal Netscape WebMail account today at http://webmail.netscape.com.

Reply by email

Samuel Liddicott
to Michal Bukovjan
Show quoted text 9 lines
-----Original Message----- From: Michal Bukovjan Sent: 20 August 1999 07:53 PM To: Subject: Re: [RE: [Re: [lazarus] wndproc]] We are interested (as I understand it) in the possibility to have Lazarus for both Win32 and Linux, and use any arbitrary widget for visuals.

yes

Show quoted text 5 lines
This means that we should avoid all Win32 stuff in core components like TComponent, TControl, TWinControl, and the basic set of controls, so that it is possible to write an application (using standard components) once and compile under Win32 and Linux without no code change.

Depends on what you mean. HWND is not Win32 specific. It looks like it because of its name but it is actually a generic handle to the widget via the widget-manager. Wndproc looks win32 specific because of the name, but it is not. It is really a generic virtual message interceptor, the *only* NON_PLATFORM_SPECIFIC way to intercept messages before they hit the handlers. We could call it "PreviewHandler" instead of wndproc, but lets keep the same name for compatability. So YES, lets avoid where possible win32 specifics, but we need to decide on what are actually win32 specific and what are actually very useful non-specific members with win32 sounding names that we need to keep.

I say SHOULD, but if neccessary, we may opt to insert some Win32 specific code and let it become dummy under anything else.

In the end CreateParams will have a different implementation with win32 that GTK but this is the ONLY difference that needs to exist in the FCL with regards to instantiating a widget via the widget-manager.

Show quoted text 5 lines
There was a discussion on that topic recently, including whether we should use IFDEFs and such, which resulted in those gtkint.pp, win32int.pp units and all this stuff.

I had thought of this. Another way is to have a global WidgetManager object that can be called upon to doo widget-manager specific stuff.

The differing CreateParams implementations for the default controls could exist either way, although it would result in high-coupling to the widget-manager as more fancy controls are invented; same problem for includes as newer controls are implemented.

$IFDEF is really the only way although a $IFDEF could be $IFDEF}{$INCLUDE

Also if I get my way regarding CreateWnd in most cases (apart from the default control set) no developer will need widget-specific code at all it will be hidden in the FCL and so yes; and I think you are right, IFDEF's are the way to go.

So I think the possibility to use existing Delphi components descendants that work and use Win32 specific stuff (i.e. Windows messages) will be, ..er.., somewhat limited to Windows, and useless under Linux.

I hope that even under linux, if a component moves, a WM_MOVERESIZE or something message will be sent.

Show quoted text 11 lines
While this may be valid from Windows point of view (the application will not be portable, author decides), if such thing would be found in core components, that would handicap other widget platforms. And the other way around, we could certainly use some GTK specific stuff in core components, the other, including Win32 users, would be handicapped instead. Not speaking about Motif/Lesstif, Qt, or whatever.

I pale with horror. You just said to start with that: "We are interested (as I understand it) in the possibility to have Lazarus for both Win32 and Linux, and use any arbitrary widget for visuals."

and then

"This means that we should avoid all Win32 stuff in core components"

woah!

Stop. I am not a moron :-)

Well, no!

I am not the one who decides about this in the end, anyway (that is the core component maintainer).

Hmmm surely they implement, but the group decides?

Show quoted text 7 lines
That is just my point of view. And since you seem to know the Win32 widgets stuff well, it may be inevitable to have some Win32 support integrated after all, if you say so, be it by IFDEFs. IMHO, that is the solution Sibyl chose, as I looked into their code.

The win32 model is actually more abstracted than the GTK model; if we follow the windows/delhi there is no danger of shutting ourselves in. The deception is that the names of the win32 abstractions are not abstract names but names specific to the impementation of the abstraction. But whats in a name? We can certainly live with it.

The mere fact that GTK does not need all of win32 model is evidence of its abstraction. The fact that a windows delphi implementation and many many components cannot be implemented with the GTK model is evidence of it lack of abstraction. This is an example of our first difficulty in runnig lazarus with a non-GTK widget set. If we want widget-choice we had better go for abstraction.

The reason delphi works like this is because they extended the windows abstraction even further so it can be used in what I am calling the GTK way (with seperate handlers - much nicer than wndproc WHEN you've got the choice) as well as via the windows way.

> > 2) Leave out some Delphi solutions which had to be created/were suited for > > Windows, and supply our own, more versatile ones (be their > > Delphi-incompatible).

Where you say windows, also say "OS/2" + other hitherto unexamined widget sets.

Show quoted text 9 lines
> > Again, remember that Delphi is VERY designed for > > Windows, and if we want Lazarus for as much platforms as possible, we > > definitely will need to abandon some Delphi approaches. > > If we want Lazarus for as much platforms as possible, we definitely do not > need to rule out platform approaches. ??? What do you mean ?

That we don't want to remove things just because windows uses them. That doesn't make them win32 specific. That we don't want to become GTK specific.

Show quoted text 17 lines
> > The shiny example of the 2) is Handle, which is rarely found > > anywhere beyond > > Windows, and since Windows get COMized, not even there in the future (my > > guess). > > The handle is "some" reference to the "real" object that is managed by the > bound GTK. This is going to be used with whatever gui we bind to. OK, > handle isn't the best name UNDER GTK but its a better name under some others > (like Win or OS2). Yes. But while it is an integer under Win32 (32-bit), it is meant to be a pointer under GTK (which happens to be 32-bit on IA32). Then, I am not sure about 64bit platforms. (The compiler might take care about that, though).

The fact that it is a pointer in GTK should be kept "secret". Are you really sure it is an integer in win32. I think it is actually a pointer, but if it is presented as an integer no-one will mess about without. I also think that 16 bit windows handles were near pointers.

Show quoted text 7 lines
> The only reason for thinking a .wndproc slows things down is if you think > what's in the wndproc isn't needed - and yes its faster if you do less. > You are absolutely right on this one. Still I claim that the HUGE case statement is NOT effective. In my opinion, it is not the best approach, although it is usable.

You are also right, but with Delphi applications, the Case statement is not huge simply because of the nice event handlers.

It is true that many components DO use it, as they have no other choice under Windows, anyway (or do they?).

You are right, in many cases there is no choice (except even worse filthy hacks that really are win32 specific)

[BTW Once I did some self-modifying code that changed the virtual method table at runtime to intercept something I needed!. *cough* but thats Borlands fault! I'm not proud of it]
[What I am proud of is modifying the sysutils at runtime to intercept the GetDate GetTime, Now (etc) calls to work round a winNT 16bit bug where the calendar didn't run at the same rate as the clock!!! True! The date wrapped round before the lock did, and the calendar got further and further out!) (My unit meant you could leave your program as-is, merely by linking with the unit would fix the problem)

Show quoted text 6 lines
> If you like, let each component have a flag which says whether or not > wndproc can be skipped. The GTK callback handler could check this flag and > only call wndproc if it is not set. Hmm, that could be a viable solution :-)

It would delay the decision anyway!

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.

true

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 !

There will be a wndproc. The form designer intercepts nicely:

procedure TControl.WndProc(var Message: TMessage);
var
  Form: TForm;
begin
  if csDesigning in ComponentState then
  begin
    Form := GetParentForm(Self);
    if (Form  nil) and (Form.Designer  nil) and
      Form.Designer.IsDesignMsg(Self, Message) then Exit;
  end;

Nice, eh? Yep a slowdown, but only at design time.

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.

Well, as I keep saying, only the name is os-specific (well, it applys to OS/2 as well), the abstract concept is a sound one, that may also be needed by future widget managers, but is certainly needed now as a pre-message handler interceptor.

In fact the whole wndproc dispatch system is really a direct implementation of an object-class system in straight C.
Intercepting wndprocs is the way to override methods within this system. And this system is a neat way of marrying object pascal to any object system used by any widget set.

Sam

Reply by email