TApplication.Handle
是什么?
- 它从哪里来?
- 它为什么存在?
- 最重要的是:为什么所有的窗体都将其作为父窗口句柄?
Delphi 帮助文件中说:
如果我专注于“应用程序主窗体的窗口句柄”这个词组,我理解为“应用程序主窗体的窗口句柄”,那么我可以进行比较: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.
- “应用程序主窗体的窗口句柄”,与 -
Application
的 MainForm
的窗口句柄但是它们并不相同。
Application.MainForm.Handle: 11473728
Application.Handle: 11079574
那么Application.Handle
是什么?
- 它来自哪里?
- 它是哪个Windows®窗口句柄?
- 如果它确实是
Application
的MainForm
的Windows®窗口句柄,则为什么它们不匹配? - 如果它不是
Application
的MainForm
的窗口句柄,则它是什么? - 更重要的是:为什么它是每个窗体的最终
父级所有者? - 最重要的问题:如果我尝试让一个窗体成为
未拥有未拥有(以便它可以出现在任务栏上),或者尝试使用类似IProgressDialog的东西,为什么一切都会出错?
我真正想问的是:是什么设计理念使得Application.Handle
存在?如果我能理解为什么,那么如何做应该就变得很明显了。
通过二十个问题来理解:
当谈到通过将其所有者设置为null
来使窗口出现在任务栏上的解决方案时,Peter Below在2000年说:
这可能会导致从次要窗体显示的模态窗体出现问题。
如果用户在模态窗体弹出时切换到其他应用程序,然后再切回来,模态窗体可能会隐藏在主窗体下面。可以通过确保模态窗体是父窗体(sic;他想说的是所有者)(使用
params.WndParent
如上所述)来处理此问题。但这对于来自
Dialogs
单元的标准对话框和异常不可行,需要更多的努力来使它们正常工作(基本上是处理Application.OnActivate
,查找通过GetLastActivePopup
与Application
拥有关系的模态窗体,并通过SetWindowPos
将其置于Z轴的顶部)。
- 为什么模态窗体会被卡在其他窗体后面?
- 通常是什么机制将模态窗体带到最前面,为什么这里不起作用?
- 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
时,是谁将所有窗体置于前台。 是Application在这样做吗? 为什么它要这样做?与其这样做,难道它不应该不这样做吗? 不这样做的缺点是什么? 我看到这样做的缺点(系统菜单无法正常工作,任务栏按钮缩略图不准确,Windows® shell无法最小化窗口)。
在另一篇涉及Application
的文章中,Mike Edenfield说父窗口会向其他窗口发送最小化、最大化和还原消息:
这将为您的窗体添加任务栏按钮,但还有一些其他细节需要处理。 最明显的是,您的窗体仍然接收到发送到父窗体(应用程序的主窗体)的最小化/最大化。 为了避免这种情况,您可以安装WM_SYSCOMMAND的消息处理程序,方法是添加一行,例如:
我的Windows®窗口的最小化/最大化/还原消息为什么不会发送到我的窗口?这是因为发送给窗口的消息由Windows®发送给窗口的所有者吗?在这种情况下,Delphi应用程序中的所有窗体都归
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.
Application
所有?那么将所有者设置为空是否意味着:procedure TForm2.CreateParams(var Params: TCreateParams);
begin
inherited;
Params.WndParent := 0; //NULL
end;
我需要移除Application
及其窗口句柄,以免干扰我的表单,这样Windows系统就可以再次发送最小化/最大化/还原消息给我了。
也许我们应该比较一下“普通”Windows应用程序的做法和Borland最初设计Delphi应用程序的做法——特别是涉及到Application
对象和它的主循环的部分。
Application
对象解决了什么问题?- 后来的Delphi版本中做出了哪些改变以避免这些问题?
- 后来的Delphi版本的更改是否带来了其他问题,而最初的Application设计则试图解决这些问题?
- 那些更新的应用程序如何在没有Application干扰的情况下正常运行?
显然,Borland意识到了他们最初设计的缺陷。他们最初的设计是什么,解决了什么问题,有什么缺陷,重新设计后又如何解决这个问题呢?
Create(AOwner: TComponent
) 被释放时自动释放它们有关。而“Parent”(或“WndParent”)则涉及到可视控件之间的父子关系。那么为什么每个窗体都有Application
作为 Owner 呢?因为Application.CreateForm(TMyForm, MyForm)
使用自身作为 owner 创建窗体。至于父句柄为什么是 'Application.Handle',请参见TCustomForm.CreateParams
。 - R. Hoek