Delphi: What is Application.Handle?
Asked Answered
M

3

52

What is TApplication.Handle?

  • Where does it come from?
  • Why does it exist?
  • And most importantly: why do all forms have it as their parent window handle?

The Delphi help says:

TApplication.Handle

Provides access to the window handle of the main form (window) of the application.

property Handle: HWND;

Description

Use Handle when calling Windows API functions that require a parent window handle. For example, a DLL that displays its own top-level pop-up windows needs a parent window to display its windows in the application. Using the Handle property makes such windows part of the application, so that they are minimized, restored, enabled and disabled with the application.

If I focus on the words "the window handle of the main form of the application", and I take that to mean the window handle of the main form of the application, then I can compare:

  • "the window handle of the main form of the application", with
  • the window handle of the MainForm of the Application

but they are not the same:

Application.MainForm.Handle: 11473728
Application.Handle: 11079574

So what is Application.Handle?

  • Where does it come from?
  • What Windows® window handle is it?
  • If it is the Windows® window handle of the Application's MainForm, then why don't they match?
  • If it's not the window handle of the Application's MainForm, then what is it?
  • More importantly: Why is it the ultimate parent owner of every form?
  • And most important: Why does everything go haywire if i try to have a form be unparented unowned (so i it can appear on the TaskBar), or try to use something like IProgressDialog?

Really what I'm asking is: What is the design rationale that makes Application.Handle exist? If I can understand the why, the how should become obvious.


Understanding through a game of twenty questions:

In talking about the solution of making a window appear on the taskbar by making its owner null, Peter Below in 2000 said:

This can cause some problems with modal forms shown from secondary forms.

If the user switches away from the app while a modal form is up, and then back to the form that showed it, the modal form may hide beneath the form. It is possible to deal with this by making sure the modal form is parented [sic; he meant owned] to the form that showed it (using params.WndParent as above)

But this is not possible with the standard dialogs from the Dialogs unit and exceptions, which need more effort to get them to work right (basically handling Application.OnActivate, looking for modal forms parented to Application via GetLastActivePopup and bringing them to the top of the Z-order via SetWindowPos).

  • Why does a modal form end up stuck behind other forms?
  • What mechanism normally brings a modal form to the front, and why is it not functional here?
  • Windows® is responsible for showing windows stacked. What has gone wrong that Windows® isn't showing the right windows?

He also talked about using the new Windows extended style that forces a window to appear on the taskbar (when the normal rules of making it un-owned is insufficient, impractical, or undesirable), by adding the WS_EX_APPWINDOW extended style:

procedure TForm2.CreateParams(var Params: TCreateParams); 
begin 
   inherited CreateParams( params ); 

   Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW; 
end; 

But then he cautions:

If you click on a secondary forms taskbar button while another app is active this will still bring all the applications forms to front. If you do not want that there is option

Who is bringing all the forms to the front when the form's owner is still Application.Handle. Is Application doing this? Why is it doing this? Rather than doing this, shouldn't it not be doing this? What is the downside of not doing this; I see the downside of doing it (system menu's don't work property, taskbar button thumbnails are inaccurate, Windows® shell cannot minimize windows.


In another post dealing with the Application, Mike Edenfield says that the parent window sends other window's their minimize, maximize and restore messages:

This will add the taskbar button for your form, but there are a few other minor details to handle. Most obviously, your form still receives minimize/maximize that get sent to the parent form (the main form of the application). In order to avoid this, you can install a message handler for WM_SYSCOMMAND by adding a line such as:

procedure WMSysCommand(var Msg: TMessage); WM_SYSCOMMAND; 

procedure TParentForm.WMSysCommand(var Msg: TMessage); 
begin 
   if Msg.wParam = SC_MINIMIZE then 
   begin 
      // Send child windows message, don't 
      // send to windows with a taskbar button. 
   end; 
end; 

Note that this handler goes in the PARENT form of the one you want to behave independently of > the rest of the application, so as to avoid passing on the minimize message. You can add similar > code for SC_MAXIMIZE, SC_RESTORE, etc.

How is it that minimize/maximize/restore messages for my Windows® windows are not going to my window? Is this because messages destined for a window are sent, by Windows® to the window's owner? And in this case all the forms in a Delphi application are "owned" by Application? Does that not mean that making the owner null:

procedure TForm2.CreateParams(var Params: TCreateParams);
begin
   inherited;
   Params.WndParent := 0; //NULL
end;

will remove Application and it's window Handle from interfering with my form, and Windows should once again send me my minimize/maximize/restore messages?


Perhaps if we compared and contrasted now a "normal" Windows application does things, with how Borland initially designed Delphi applications to do things - with respect to this Application object and it's main loop.

  • what solution was the Application object solving?
  • What change was made with later versions of Delphi so that these same issues don't exist?
  • Did the change in later versions of Delphi not introduce other problems, that the initial Application design tried so hard to solve?
  • How can those newer applications still function without Application interfering with them?

Obviously Borland realized the flaw in their initial design. What was their initial design, what problem was it solving, what is the flaw, what was the re-design, and how does it solve the problem?

Muire answered 5/2, 2010 at 3:16 Comment(4)
I think you'll be interested to learn about these two tricks: yoy.be/item.asp?i89 yoy.be/item.asp?i87Buttermilk
@Stinh Sanders: i've seen those, they don't solve the issues. Also, never, never, never pass GetDesktopWindow as the owner of a window, as those, and other posts, on the subject suggest. Doing so used to cause Windows to freeze. It was such a problem that Microsoft patched CreateWindow, so anyone passing GetDesktopWindow as the owner is changed to use NULL instead. And if i could edit that post on yoy.com, i would.Muire
In Tokyo, Application.Handle is zero!Franciscofranciska
The 'Owner' of a Form is something independent of the 'Parent' of a Form (But can be the same). The Owner has to do with the way Delphi links TComponent based objects to each other so they are automatically freed when the 'Owner' (see Create(AOwner: TComponent) is freed. The 'Parent' (or 'WndParent') has to do with the visual parent/child relation of visual controls. So why does every form have Application as Owner, because Application.CreateForm(TMyForm, MyForm) creates the form using itself as owner. And for the parent handle being 'Application.Handle', see TCustomForm.CreateParams.Siftings
E
60

The reason for the application window has a bit of a sordid history. When developing Delphi 1, we knew we wanted to use "SDI" (windows scattered all over the desktop) ui model for the IDE. We also knew that Windows sucked (and still does) at that model. However we also noticed that Visual Basic at that time employed that model and it seemed to work well. Upon further examination, we found that VB used a special "hidden" parking window which was used as the "owner" (Windows blurs the notion of parent and owner at times, but the distinction is similar to VCL) for all the other visible windows.

This is how we solved the "problem" where the windows containing the main menu was rarely ever focused so processing Alt-F for the File menu simply wouldn't work. By using this central parking window as an intermediary, we could more easily keep track of and route messages to the appropriate windows.

This arrangement also solved another issue where normally multiple top level windows were entirely independent. By making the application handle the "owner" of all these windows, they would all behave in concert. For instance, you may have noticed that when you select any of the application windows, all the application windows move to the front and retain their z-order relative to each other. This would also make the application minimize and restore as a functional grouping.

That is a consequence of using this model. We could have manually done all this work to keep things straight, but the design philosophy was to not re-invent Windows, but to leverage it where we could. That is also why a TButton or a TEdit is really a Windows "User" BUTTON and EDIT window class and style, respectively.

As Windows evolved, that "SDI" model began to fall out of favor. In fact Windows itself began to become "hostile" to that style of application. Starting with Windows Vista and continuing to 7, the user shell doesn't seem to work well with an application using a parking window. So, we set out to shuffle things around in VCL to eliminate the parking window and move its function into the main form. This presented several "chicken and egg" problems whereby we need to have the parking window available early enough in the application initialization so that other windows can "attach" to it, but the main form itself may not be constructed soon enough. TApplication has to jump through a few hoops to get this to work, and there have been a few subtle edge cases that have caused issue, but most of the problems have been worked out. However, for any application you move forward, it will remain using the older parking window model.

Execrable answered 5/2, 2010 at 17:55 Comment(2)
+1 for admitting it was sordid. And the Windows XP hacks added to the Microsoft window management layer were part of the death-knell of this system, as the dreaded Z-Order bugs when you ran Delphi 7 apps on XP, began to crop up.Graces
You explanation in not 100% clear. I understand that in the end (new Delphi versions) the hidden form is not created anymore. I guess this is why the Application.Handle is now zero. Right?Franciscofranciska
U
12

All VCL apps have a "hidden" top level window called Application. This is created automatically on application startup. Amongst other things it is the main windows message handler for VCL - hence Application.ProcessMessages.

Having the apps top level window hidden does cause some strange things, noticeably the incomplete system menu that shows in the task bar, and incorrect thumb nail windows in Vista. Later versions of Delphi correct this.

However, not all windows must have it as a parent, Windows just tends to work better if it is. However, any form created with Application.CreateForm will have it as the parent, and it will also be owned by the Application object. As they are owned, they will be freed once Application is freed. This happen behind the scenes in Forms.DoneApplication

Untimely answered 5/2, 2010 at 4:1 Comment(9)
The top level forms of your application do not have their Parent property set to the Application window! Only the Owner is set to the Application object. Just to clarify: Application.ProcessMessages handles messages for ALL windows in the main thread (all VCL windows), it is in effect a step in a normal message processing loop found in all Windows GUI applications.Smriti
@Ritsaert Hornstra: What handle do top level forms of my application have as their Parent? Also note that any forms i create do have Application.Handle as their parent.Muire
So this is probably why saphua.com/minime/minime.aspx doesn't work properly with my delphi (7) apps. +1 for that nugget of information.Cornelius
@Ian Boid: The top level windows have no Parent - they have Owner confusingly named Parent (I mean WndParent field in TForm.CreateParams argument, not VCL Owner or Parent Control). You probably using old Delphi version if your top-level forms have Application.Handle as an Owner (in Windows' sense of term Owner).Malachi
@Serge: Depends on your definition of old; Delphi 5. What is the owner of windows with no parent in later versions of Delphi?Muire
@Ian: I am using Delphi 2009 and I see that the default form owner is Application.MainForm.Handle. When I show a form and click on the main form, the form remains above the main form (in z-order). I believe it was different before.Malachi
@Serg: We should be clear here. What do you mean by the "default form". i know that the first form that happens to get created through a call to Application.CreateForm in the project file become's the MainForm as far as the application object is concerned, and that form is assigned to Application.MainForm. What are you referring to when you say your "default form"?Muire
I don't meant "default form", I meant "default form owner", i.e. not changed by the overriden CreateParam method. I believe that with previous Delphi versions (can't check it now) I could freely change the z-order of main form and other forms, now I can't do it - main form always remaines behind.Malachi
@Ian - D5 is 11 years old - I had a version in 1999 (fixed some Y2k problems with D3)Untimely
I
9

From looking at the source in forms.pas (Delphi 2009), it appears that they create a "master" window in win32 GUI apps to allow calls to

  • TApplication.Minimize
  • TApplication.Restore
  • etc

It appears that messages passed to the Application.Handle are forwarded as appropriate to the MainForm, if it exists. This would allow the app to respond to minimize, etc if the main window has not been created. By modifying the project source you can create a Delphi app without a main window.

In this case, the TApplication methods will still work, even if you haven't created a main window. Not sure if I'm grasping all of the purposes, but I don't have time to go through all of the TApplication code.

Per your questions:

  • Where does it come from? It is the handle of a window created in TApplication.Create

  • What windows handle is it? a fake window that every GUI Delphi app requires as part of the TApplication abstraction

  • Is it the windows handle of the application's main form No

  • If its not the handle of application's main form then what is it? See above

  • more importantly: why is it the ultimate parent of every form? assuming you're right that its the ultimate parent, i assume that it is so because it makes it easy to find all of forms in your application (enumerating the children of this "master" form).

  • and most important: why does everything go haywire if i try to have a form be unparented I think because the hidden "master" form is getting system messages that it should pass on to its children and/or the main form, but can't find the unparented form.

Anyway, that's my take on it. You can probably learn more by looking at the TApplication declaration and code in forms.pas. The bottom line from what i see is it is a convenient abstraction.

Inenarrable answered 5/2, 2010 at 4:1 Comment(3)
In Delphi 2007, the VCL changed to default to not having a hidden window, but you can choose the old way too if that helps. The hidden window stopped Windows 7 preview from working properly.Keegan
@mj2008: do you have a link for more information regarding this? I'm currently updating a project from C++ Builder 2006 -> C++ Builder 2009, and I believe I'm seeing my Application->Handle ptr as NULL. Is this the case now in Builder 2009? And if so, would using MainForm->Handle be a good substitute?Fitch
@Rob The Delphi control for this is Application.MainFormOnTaskbar but I don't know if it applies for you. Typically an upgraded app doesn't have this changed.Keegan

© 2022 - 2024 — McMap. All rights reserved.