问与答 Delphi:什么是Application.Handle?

john · 2020-02-22 16:00:05 · 热度: 170

Application是什么?

  • 它从何而来?
  • 为什么存在?
  • 最重要的是:为什么所有表单都将其作为其父窗口句柄?

Delphi帮助说:

TApplication.Handle

提供对窗口句柄的访问   的主要形式(窗口)   应用。

Application

描述

调用Windows API时使用Handle   需要父窗口的功能   处理。 例如,一个DLL   显示其自己的顶级弹出窗口   Windows需要一个父窗口来   在其窗口中显示其窗口   应用。 使用Handle属性   使此类窗户成为   应用程序,以便它们   最小化,还原,启用和   与应用程序禁用。

如果我专注于“应用程序主要形式的窗口句柄”一词,而我将其表示为应用程序主要形式的窗口句柄,那么我可以进行比较:

  • “应用程序主要形式的窗口句柄”,其中
  • Application.OnActivateApplication的窗把手

但是它们不一样:

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

那么Application是什么?

  • 它从何而来?
  • 它是什么Windows®窗口句柄?
  • 如果它是ApplicationApplication.OnActivate的Windows®窗口句柄,那么为什么不匹配?
  • 如果不是ApplicationApplication.OnActivate的窗把手,那是什么?
  • 更重要的是:为什么它是每种形式的最终父母?
  • 最重要的是:如果我尝试让表单成为非父代无主(为什么它可以出现在TaskBar上),或者尝试使用诸如ProgressDialog之类的东西,为什么一切都会变得一团糟?

我真正要问的是:使Application.Handle存在的设计原理是什么? 如果我能理解原因,那么应该变得显而易见。


通过二十个问题的游戏来更新理解:

在谈到通过使窗口的所有者Application使窗口出现在任务栏上的解决方案时,彼得·比尔在2000年说:

这可能会导致以下形式的模态形式出现问题:   次要形式。

如果用户在进行模态操作时离开了应用程序   形式,然后回到显示它的形式,模态形式可能   隐藏在表格下方。 通过确保可以解决此问题   情态形式是父母的[原文; 他的意思是拥有]显示它的形式(使用   Application以上)

但这对于标准来说是不可能的   Application单元中的对话框和例外,需要付出更多努力才能   让他们正常工作(基本处理Application.OnActivate,   通过GetLastActivePopup寻找应用程序的父代形式形式   并通过SetWindowPos将它们带到Z顺序的顶部)。

  • 为什么模态形式最终会滞后于其他形式?
  • 哪种机制通常将模式形式带到前端,为什么它在这里不起作用?
  • Windows®负责显示堆叠的窗口。 Windows®没有显示正确的窗口是怎么回事?

他还谈到了通过添加Application扩展样式来使用新的Windows扩展样式,该样式强制将窗口显示在任务栏上(当使常规窗口不拥有它时,是不切实际的或不受欢迎的)。

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

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

但随后他告诫:

如果您在另一个应用程序处于运行状态时单击辅助表单任务栏按钮   激活后,仍将所有申请表置于最前面。 如果你   不想有选择

表单所有者仍为Application时,谁将所有表单都放在最前面。应用程序是否在这样做? 为什么这样做呢? 与其这样做,不应该不这样做吗? 不这样做的不利之处是什么? 我看到这样做的缺点(系统菜单无法正常工作,任务栏按钮缩略图不正确,Windows®Shell无法最小化窗口。


在另一篇有关Application的文章中,Mike Edenfield说父窗口发送了其他窗口的最小化,最大化和还原消息:

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

Application

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

如何最小化/最大化/还原Windows®窗口的消息不会进入我的窗口? 这是因为Windows®将发给窗口的消息发送给了窗口的所有者吗? 在这种情况下,Delphi应用程序中的所有表单都归Application所有吗? 这是否不意味着使所有者为空:

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

会删除Application及其窗口句柄,以免干扰我的表单,而Windows应该再次向我发送我的最小化/最大化/还原消息?


也许如果我们现在比较和对比一个“正常的” Windows应用程序做事,以及Borland最初设计Delphi应用程序做事的方式-关于这个Application对象及其主循环。

  • Application对象解决了什么解决方案?
  • 后来的Delphi版本进行了哪些更改,以使这些相同的问题不存在?
  • 后来的Delphi版本中的更改是否没有引入其他问题,以至于最初的应用程序设计很难解决?
  • 在应用程序不干扰它们的情况下,这些较新的应用程序仍将如何运行?

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

猜你喜欢:
共收到 3 条回复
eli #1 · 2020-02-22 16:00:06

应用程序窗口的原因有一段肮脏的历史。 在开发Delphi 1时,我们知道我们想为IDE使用“ SDI”(遍布整个桌面的窗口)ui模型。 我们还知道Windows在那个模型上很糟糕(现在仍然如此)。 但是,我们还注意到,当时的Visual Basic使用了该模型,并且看起来运行良好。 经过进一步检查,我们发现VB对所有其他可见窗口使用了一个特殊的“隐藏”停车窗口,该窗口用作“所有者”(Windows有时会模糊父级和所有者的概念,但区别类似于VCL)。 。

这就是我们解决“问题”的方式,在该问题中,包含主菜单的窗口很少聚焦,因此无法处理File菜单的Alt-F。 通过使用此中央停车窗口作为中介,我们可以更轻松地跟踪消息并将消息路由到适当的窗口。

这种安排还解决了另一个问题,即通常多个顶层窗口是完全独立的。 通过使应用程序处理所有这些窗口的“所有者”,它们将共同发挥作用。 例如,您可能已经注意到,当您选择任何一个应用程序窗口时,所有应用程序窗口都移到最前面并相对于彼此保持其z顺序。 这也将使应用程序最小化并还原为功能分组。

这是使用此模型的结果。 我们本来可以手动完成所有这些工作以保持工作状态的顺畅,但是设计理念是不重新发明Windows,而是在可能的地方利用它。 这就是为什么TButton或TEdit分别实际上是Windows“用户”按钮和EDIT窗口类和样式的原因。

随着Windows的发展,“ SDI”模型开始失宠。 实际上,Windows本身开始对这种应用程序样式变得“敌视”。 从Windows Vista开始到7,用户外壳程序似乎无法与使用停车窗口的应用程序很好地配合。 因此,我们着手在VCL中进行一些调整,以消除停车窗口并将其功能移至主要形式。 这带来了几个“鸡与蛋”问题,因此我们需要在应用程序初始化中尽早使停车窗口可用,以便其他窗口可以“附加”到它,但是主窗体本身可能无法尽快构建。 为了使TApplication能够正常工作,TApplication必须跳了几圈,并且有一些细微的极端情况引起了问题,但是大多数问题已经解决了。 但是,对于任何向前移动的应用程序,它将使用较旧的停车窗口模型保留。

chester #2 · 2020-02-22 16:00:07

所有VCL应用程序都有一个名为“应用程序”的“隐藏”顶级窗口。 这是在应用程序启动时自动创建的。 除其他外,它是VCL的主要Windows消息处理程序-因此是Application.ProcessMessages。

隐藏应用程序顶级窗口确实会引起一些奇怪的事情,特别是任务栏中显示的系统菜单不完整,以及Vista中不正确的指尖窗口。 更高版本的Delphi纠正了此问题。

但是,并非所有Windows都必须将其作为父级,Windows往往会更好地工作。但是,使用Application.CreateForm创建的任何表单都将其作为父表单,并且也将由Application对象拥有。 由于它们是拥有的,一旦释放了应用程序,它们将被释放。 这发生在Forms.DoneApplication的幕后

adonis #3 · 2020-02-22 16:00:08

通过查看forms.pas中的源代码(Delphi 2009),他们似乎在win32 GUI应用程序中创建了一个“主”窗口,以允许调用

  • TApplication.Minimize
  • TApplication.Restore
  • 等等

看来,传递到forms.pas的消息会适当地转发到MainForm(如果存在)。 如果尚未创建主窗口,这将允许应用程序响应最小化。 通过修改项目源,可以创建不带主窗口的delphi应用。

在这种情况下,即使您尚未创建主窗口,该forms.pas方法仍然可以使用。 不知道我是否掌握了所有目的,但是我没有时间阅读所有TApplication代码。

根据您的问题:

  • 它从何而来? 它是在forms.pas中创建的窗口的句柄

  • 它是什么窗户把手? 每个gui delphi应用程序都需要作为TApplication抽象的一部分的假窗口

  • 是应用程序主窗体的Windows句柄吗?

  • 如果它不是应用程序主窗体的句柄,那是什么? 往上看

  • 更重要的是:为什么它是每种形式的最终父母? 假设您是其最终父对象是正确的,那么我认为是这样,因为这样可以轻松地在您的应用程序中查找所有表单(枚举此“主”表单的子表单)。

  • 最重要的是:如果我尝试使表单成为非父表单,为什么一切都会变得混乱,我认为这是因为隐藏的“主”表单正在获取系统消息,该消息应传递给其子级和/或主窗体,但找不到 无父母形式。

无论如何,这就是我的看法。 您可以通过查看forms.pas中的TApplication声明和代码来了解更多信息。我所看到的最重要的是,它是一种方便的抽象。

最好的祝福,

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册