Delphi:什么是Application.Handle?

Ian*_*oyd 48 delphi delphi-5 design-rationale

什么是TApplication.Handle

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

德尔福帮助说:

TApplication.Handle

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

property Handle: HWND;
Run Code Online (Sandbox Code Playgroud)

描述

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

如果我专注于" 应用程序主窗体的窗口句柄 "这个词,我认为它是指应用程序主窗体的窗口句柄,那么我可以比较:

  • "应用程序主窗体的窗口句柄",用
  • 窗户把手MainFormApplication

但他们不一样:

Application.MainForm.Handle: 11473728
Application.Handle: 11079574
Run Code Online (Sandbox Code Playgroud)

那是什么Application.Handle

  • 它从何而来?
  • Windows®窗口处理的是什么?
  • 如果的的的Windows®窗口句柄ApplicationMainForm,那么他们为什么不匹配?
  • 如果它不是Application 's 的窗口句柄MainForm,那么它是什么?
  • 更重要的是:为什么它是每种形式的最终父母所有者?
  • 最重要的是:如果我试图让一个表格无主义(因此我可以出现在TaskBar上),或者尝试使用像IProgressDialog这样的东西,为什么一切都变得混乱

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


通过20个问题的游戏更新理解:

在谈到通过让它的主人在任务栏上出现一个窗口的解决方案时null,Peter Below在2000年说:

这可能会导致从次要形式显示的模态形式出现一些问题.

如果用户在模态表单启动时从应用程序切换,然后返回到显示它的表单,则模式表单可能隐藏在表单下方.可以通过确保模态形式是父级来处理这个问题[原文如此; 他的意思是拥有]到表明它的形式(使用 params.WndParent如上)

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

  • 为什么模态形式最终会落后于其他形式?
  • 什么机制通常会将模态形式带到前面,为什么它在这里不起作用?
  • Windows®负责显示堆叠的窗口.Windows®没有显示正确的窗口出了什么问题?

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

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

   Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW; 
end; 
Run Code Online (Sandbox Code Playgroud)

但他警告说:

如果您在另一个应用程序处于活动状态时单击辅助表单任务栏按钮,则仍会将所有应用程序表单放在前面.如果您不希望有选项

当表格的所有者还在时,谁将所有表格带到前面Application.Handle.申请是这样做的吗?它为什么这样做?而不是这样做,不应该也不会做这个?这样做的缺点是什么; 我看到这样做的缺点(系统菜单不能正常工作,任务栏按钮缩略图不准确,Windows®外壳无法最小化窗口.


在处理该问题的另一篇文章中Application,Mike Edenfield说父窗口发送其他窗口的最小化,最大化和恢复消息:

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

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; 
Run Code Online (Sandbox Code Playgroud)

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

如何最小化/最大化/恢复Windows®窗口的消息不会进入我的窗口?这是因为发往窗口的邮件是由Windows®发送给窗口的所有者的吗?在这种情况下,Delphi应用程序中的所有表单都是"拥有"的Application?这不意味着让所有者为null:

procedure TForm2.CreateParams(var Params: TCreateParams);
begin
   inherited;
   Params.WndParent := 0; //NULL
end;
Run Code Online (Sandbox Code Playgroud)

将删除Application它的窗口处理干扰我的表单,Windows应该再次发送给我的mimimize/maximize/restore消息?


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

  • 解决Application对象的解决方案是什么?
  • 使用更高版本的Delphi进行了哪些更改,以便不存在这些相同的问题?
  • Delphi的后续版本中的更改是否没有引入其他问题,因为初始应用程序设计试图如此难以解决?
  • 如果没有应用程序干扰它们,这些较新的应用程序如何运行?

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

All*_*uer 50

应用程序窗口的原因有点肮脏的历史.在开发Delphi 1时,我们知道我们想要为IDE使用"SDI"(遍布桌面的窗口)ui模型.我们也知道Windows在该模型上吸引(并且仍然存在).但是我们也注意到当时的Visual Basic使用了该模型,它似乎运行良好.经过进一步检查,我们发现VB使用了一个特殊的"隐藏"停车窗口,用作所有其他可见窗口的"所有者"(Windows模糊了父级和所有者的概念,但区别类似于VCL) .

这就是我们解决"问题"的方法,其中包含主菜单的窗口很少聚焦,因此处理文件菜单的Alt-F根本不起作用.通过使用这个中央停车窗口作为中介,我们可以更容易地跟踪消息并将消息路由到适当的窗口.

这种安排还解决了通常多个顶级窗口完全独立的另一个问题.通过使应用程序处理所有这些窗口的"所有者",它们都会表现得很好.例如,您可能已经注意到,当您选择任何应用程序窗口时,所有应用程序窗口都会移到前面并保持相对于彼此的z顺序.这也可以使应用程序最小化并恢复为功能分组.

这是使用此模型的结果.我们可以手动完成所有这些工作以保持正确,但设计理念是不重新发明Windows,而是尽可能地利用它.这也是为什么一个TButton或TEDIT是真的一个Windows"用户"按钮,编辑窗口类和风格,分别.

随着Windows的发展,"SDI"模式开始失宠.事实上,Windows本身开始变得对这种应用程序"充满敌意".从Windows Vista开始并继续到7,用户shell似乎无法与使用停车窗口的应用程序一起使用.因此,我们开始在VCL中改变现状,以消除停车窗口并将其功能转移到主窗体中.这提出了几个"鸡和鸡蛋"问题,我们需要在应用程序初始化中尽早提供停车窗口,以便其他窗口可以"附加"到它,但主窗体本身可能不会很快构建.TApplication必须通过几个环节来实现这一点,并且有一些微妙的边缘情况引起了问题,但大多数问题已经解决了.但是,对于您前进的任何应用程序,它将继续使用旧的停车窗口模型.


Ger*_*oll 12

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

隐藏应用程序顶级窗口会导致一些奇怪的事情,显然是任务栏中显示的不完整的系统菜单,以及Vista中不正确的缩略图窗口.更高版本的Delphi纠正了这一点.

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

  • 应用程序的顶级表单没有将其Parent属性设置为Application窗口!仅将所有者设置为Application对象.只是为了澄清:Application.ProcessMessages处理主线程(所有VCL窗口)中所有窗口的消息,它实际上是在所有Windows GUI应用程序中找到的正常消息处理循环中的一个步骤. (3认同)

Don*_*son 8

通过查看forms.pas(Delphi 2009)中的源代码,看起来他们在win32 gui应用程序中创建了一个"主"窗口,允许调用

  • TApplication.Minimize
  • TApplication.Restore
  • 等等

看来传递给它的消息将Application.Handle被适当地转发给MainForm(如果存在).如果尚未创建主窗口,这将允许应用程序响应最小化等.通过修改项目源,您可以创建一个没有主窗口的delphi应用程序.

在这种情况下,TApplication即使您尚未创建主窗口,这些方法仍然有效.不确定我是否掌握了所有目的,但我没有时间完成所有的TApplication代码.

根据你的问题:

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

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

  • 它是应用程序的主要形式 No 的窗口句柄

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

  • 更重要的是:为什么它是每种形式的最终父母?假设你是最终的父母,我认为它是这样的,因为它可以很容易地找到你的应用程序中的所有表单(枚举这个"主"形式的孩子).

  • 最重要的是:为什么一切都变得混乱,如果我试图让一个表格无表情我认为因为隐藏的"主"表单正在获取它应该传递给它的子节点和/或主表单的系统消息,但是找不到无表格的形式.

无论如何,这是我的看法.您可以通过查看TApplication声明和代码来了解更多信息forms.pas.从我看到的底线是它是一个方便的抽象.

最好的祝福,

  • 在Delphi 2007中,VCL更改为默认没有隐藏窗口,但如果有帮助,您也可以选择旧方法.隐藏窗口使Windows 7预览无法正常工作. (2认同)