Delphi:什么是Application.Handle? [英] Delphi: What is Application.Handle?

查看:205
本文介绍了Delphi:什么是Application.Handle?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

什么是 TApplication.Handle




  • 它来自哪里?

  • 为什么它存在?

  • 最重要的是:为什么所有表单都有父窗口句柄?



Delphi帮助说:


TApplication.Handle



提供对
应用程序的主窗体(窗口)窗口句柄
的访问。

 属性句柄:HWND; 

说明



在调用需要父窗口
句柄的Windows API
函数时使用句柄。例如,
显示自己的顶级弹出式
窗口的DLL需要一个父窗口
才能在
应用程序中显示其窗口。使用Handle属性
将这样的窗口作为
应用程序的一部分,以便它们被
最小化,恢复,启用,并且
禁用应用程序。


如果我专注于应用程序主窗体的窗口句柄,我认为这意味着应用程序的主窗体的窗口句柄,然后我可以比较:




  • 主窗口句柄应用程序的形式,其中

  • 应用程序 MainForm 的窗口句柄$ c>



但它们不一样:

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

那么什么是 Application.Handle




  • 它来自哪里?

  • 什么Windows®窗口句柄是吗?

  • 如果,Windows® 应用程序的窗口句柄 MainForm ,那么为什么不匹配?

  • 如果 应用程序 MainForm 的窗口句柄,那么它是什么?

  • 更重要的是:为什么每个表单都是最终的父母?

  • 最重要的是:为什么一切都会变成haywire我试图让一个表单被忽略(所以我可以出现在TaskBar上),或尝试使用像IProgressDialog这样的东西。



真的我在问的是:使Application.Handle存在的设计理由是什么?如果我能理解为什么,应该如何变得明显。






更新二十个问题的游戏:



在谈论通过使其所有者 null ,彼得在2000年以下说


这可能会导致从
辅助表单中显示的模态表单出现一些问题。



如果用户在模式
表单处于启动状态时切换到应用程序,然后返回到显示该表单的模式,则模式窗体可能为
隐藏在表单下面。可以通过确定
来解决这个问题,模式形式是显示给它的表单(使用
`params.WndParent``如上)



但是,使用对话框单元和异常的标准
对话框是不可能的,这需要更多的努力
让他们正常工作(基本上处理 Application.OnActivate
寻找通过 GetLastActivePopup
,并通过 SetWindowPos 将它们带到Z顺序的顶部。





  • 为什么模式形式最终陷入其他形式?

  • 什么机制通常会带来一种模式的形式,为什么它不起作用?

  • Windows®负责显示窗口堆叠。 Windows®出了什么问题没有显示正确的窗口?



他还谈到使用新的Windows扩展样式,强制窗口出现在任务栏上(当正常规则使其不拥有不足,不切实际或不合需要)时,通过添加 WS_EX_APPWINDOW 扩展样式:

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

Params.ExStyle:= Params.ExStyle或WS_EX_APPWINDOW;
结束

但是他提醒:


如果您单击辅助表单任务栏按钮,而另一个应用程序是
活动,这仍然会将所有应用程序表单放在前面。如果你的
不想要那个选项


当表单的所有者是仍然 Application.Handle 。这是否是应用程序?为什么这样做?而不是这样做,不应该这样做吗?这不是的缺点是什么?我看到做的的缺点(系统菜单不工作,任务栏按钮缩略图不正确,Windows® shell无法最小化窗口。






在处理应用程序的另一篇文章中, Mike Edenfield说,父窗口发送其他窗口的最小化,最大化和恢复消息


这将为您的表单添加任务栏按钮,但
句柄还有一些其他细节,最明显的是,您的表单仍然收到最小化/最大化,将其发送到父
表单(应用程序的主要形式)为了避免这种情况,您可以通过添加以下行来为WM_SYSCOMMAND安装消息
handler:

 程序WMSysCommand(var Msg:TMessage); WM_SYSCOMMAND; 

程序TParentForm.WMSysCommand(var Msg :TMessage);
begin
如果Msg.wParam = SC_MINIMIZE然后
begin
//发送子窗口消息,不要
//使用任务栏按钮发送到Windows。
结束
结束

请注意,此处理程序位于您想要的 PARENT 形式以独立于>其余的应用程序,以避免传递最小化的消息。您可以为SC_MAXIMIZE,SC_RESTORE等添加类似的代码。


如何最小化/最大化/恢复我的Windows®的消息?窗户不会去我的窗户?这是因为通过Windows®发送发往窗口的消息到窗户的主人?在这种情况下,Delphi应用程序中的所有表单都由应用程序拥有?这不意味着让所有者无效:

  procedure TForm2.CreateParams(var Params:TCreateParams); 
开始
继承;
Params.WndParent:= 0; // NULL
end;

将删除应用程序,它的窗口句柄干扰我的表单,Windows应该再次发送我的imimize / maxim / restore信息?






也许如果我们比较和对比现在,一个正常的Windows应用程序会做的事情,Borland如何最初设计Delphi应用程序来做事情 - 关于这个应用程序对象和它是主循环。




  • 应用程序解决方案有什么解决方案?

  • 以后版本的Delphi发生了什么变化,因此这些问题不存在?

  • Delphi的更新版本的更改不会引入其他问题,即初始应用程序设计如此难以解决?

  • 应用程序仍然功能没有应用程序干扰他们?



显然,Borland在初始设计中意识到了缺陷。他们的初始设计是什么,解决什么问题,有什么缺陷,重新设计是什么,如何解决问题?

解决方案

应用程序窗口的原因有一点肮脏的历史。在开发Delphi 1时,我们知道我们想要使用SDI(窗口分散在桌面上)的ui型号为IDE。我们也知道Windows在这种模式下吸了(但仍然)。但是我们也注意到Visual Basic当时使用了这个模型,它似乎运行良好。进一步检查后,我们发现VB使用了一个特殊的隐藏停车窗口,被用作所有者(Windows将所有其他可视窗口的Windows模糊了父母和拥有者的概念,但是区别类似于VCL) 。



这是我们如何解决包含主菜单的窗口很少被重点关注的问题,所以处理文件菜单的Alt-F根本不会工作。通过使用这个中央停车窗作为中介,我们可以更容易地跟踪和路由信息到适当的窗口。



这种安排还解决了另一个问题,通常是多个顶部级别的窗口是完全独立的。通过使应用程序处理所有这些窗口的所有者,它们将全部展现在一起。例如,您可能已经注意到,当您选择应用程序窗口中的任何 时,应用程序窗口移动到前端并保持相对于z的顺序。这也将使应用程序作为功能分组最小化和还原。



这是使用此模型的结果。我们可以手动完成所有这些工作,使事情保持直线,但是设计理念是不要重新创建Windows,而是尽可能地利用它。这也是为什么TButton或TEdit真的一个Windows用户BUTTON和EDIT窗口类和样式。



作为Windows演变而来,SDI模式开始脱颖而出。实际上Windows本身就开始变成敌意的那种风格的应用。从Windows Vista开始,继续使用7,使用停车窗口的应用程序的用户外壳似乎不能正常工作。所以,我们开始在VCL中洗牌,消除停车窗口并将其功能移动到主窗体中。这提出了几个鸡和鸡蛋问题,我们需要在应用程序初始化中提供足够早的停车窗口,以便其他窗口可以附加到其中,但主窗体本身可能不会很快建成。应用程序必须跳过几个环以使其工作,并且已经有一些微妙的边缘案例引起了问题,但大多数问题已经解决了。但是,对于您向前移动的任何应用程序,它将保持使用较旧的停车窗口模型。


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 of every form?
  • And most important: Why does everything go haywire if i try to have a form be unparented (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.


Update 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 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 propertly, 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 independantly 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 mimimize/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 inital 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?

解决方案

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.

这篇关于Delphi:什么是Application.Handle?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆