是什么TApplication.Handle
?
- 它从何而来?
- 它为什么存在?
- 最重要的是:为什么所有表单都将其作为父窗口句柄?
德尔福帮助说:
TApplication.Handle
提供对应用程序主窗体(窗口)的窗口句柄的访问。
property Handle: HWND;
描述
在调用需要父窗口句柄的 Windows API 函数时使用句柄。例如,显示其自己的顶级弹出窗口的 DLL 需要一个父窗口来在应用程序中显示其窗口。使用 Handle 属性使此类窗口成为应用程序的一部分,以便它们与应用程序一起最小化、恢复、启用和禁用。
如果我专注于“应用程序主窗体的窗口句柄”一词,并且我认为它是指应用程序主窗体的窗口句柄,那么我可以比较:
- “应用程序主窗体的窗口句柄”,带有
MainForm
的窗口句柄Application
但它们不一样:
Application.MainForm.Handle: 11473728
Application.Handle: 11079574
那么是什么Application.Handle
?
- 它从何而来?
- 它是什么 Windows® 窗口句柄?
- 如果是
Application
's的 Windows® 窗口句柄MainForm
,那么它们为什么不匹配? - 如果不是
Application
's的窗口句柄MainForm
,那是什么? - 更重要的是:为什么它是每个表单的最终
父所有者? 最重要的是:如果我尝试让表单成为无父无主的表单(因此它可以出现在任务栏上),或者尝试使用IProgressDialog之类的东西,为什么一切都会变得混乱?
我真正要问的是:使Application.Handle存在的设计原理是什么?如果我能理解为什么,那么应该如何变得显而易见。
通过二十个问题的游戏更新理解:
在谈到通过设置其所有者使窗口出现在任务栏上的解决方案时null
,彼得·弗莱德在 2000 年说:
这可能会导致从辅助形式显示的模态形式出现一些问题。
如果用户在模态表单打开时从应用程序切换,然后返回显示它的表单,则模态表单可能会隐藏在表单下方。可以通过确保模态表单是父级来解决这个问题[原文如此;他的意思是拥有] 以显示它的形式(
params.WndParent
如上使用)
Dialogs
但这对于来自单元和异常的标准对话框是不可能的,这需要更多的努力才能让它们正常工作(基本上处理Application.OnActivate
,寻找以Application via为父级的模态表单GetLastActivePopup
并将它们带到 Z-order via 的顶部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;
但随后他警告说:
如果您在另一个应用程序处于活动状态时单击辅助表单任务栏按钮,这仍会将所有应用程序表单置于前面。如果你不希望有选项
当表单的所有者静止时,谁将所有表单带到最前面Application.Handle
。应用程序是这样做的吗?为什么要这样做?与其这样做,不应该这样做吗?不这样做有什么缺点?我看到了这样做的缺点(系统菜单无法正常工作,任务栏按钮缩略图不准确,Windows® shell 无法最小化窗口。
在另一篇处理 . 的帖子中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;
请注意,此处理程序以您希望独立于应用程序其余部分的行为的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 意识到了他们最初设计中的缺陷。他们最初的设计是什么,它解决了什么问题,缺陷是什么,重新设计是什么,它是如何解决问题的?