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

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

问题描述

什么是TApplication.Handle?

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

Delphi 帮助说明:

The Delphi help says:

TApplication.Handle

提供对窗口句柄的访问主窗体(窗口)的申请.

Provides access to the window handle of the main form (window) of the application.

property Handle: HWND;

说明

调用Windows API时使用句柄需要父窗口的函数处理.例如,一个 DLL显示自己的顶级弹出窗口windows需要一个父窗口将其窗口显示在应用.使用 Handle 属性使这样的窗户成为应用程序,以便它们最小化、恢复、启用和应用程序禁用.

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.

如果我关注应用程序主窗体的窗口句柄",我认为它是应用程序主窗体的窗口句柄em>,然后我可以比较:

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:

  • 应用程序主窗体的窗口句柄",用
  • ApplicationMainForm的窗口句柄
  • "the window handle of the main form of the application", with
  • the window handle of the MainForm of the Application

但它们不一样:

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

那么什么是Application.Handle?

  • 它来自哪里?
  • 什么 Windows®是窗口句柄吗?
  • 如果Windows®ApplicationMainForm的窗口句柄,那为什么不匹配呢?
  • 如果它不是ApplicationMainForm的窗口句柄,那它是什么?
  • 更重要的是:为什么它是每个表单的最终所有者?
  • 最重要的是:如果我尝试让一个表单成为 unparented 无主(这样它可以出现在任务栏上),或者尝试使用诸如 IProgressDialog 之类的东西,为什么一切都会变得混乱?
  • 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 owner of every form?
  • And most important: Why does everything go haywire if i try to have a form be unparented unowned (so i it can appear on the TaskBar), or try to use something like IProgressDialog?

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

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:

在讨论通过将窗口所有者设为 null 来使窗口出现在任务栏上的解决方案时,Peter 下面在 2000 年说:

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.

如果用户在模态模式下离开应用程序窗体向上,然后回到显示它的窗体,模态窗体可能隐藏在表格下方.可以通过确保来解决这个问题模态形式是父级的 [原文如此;他的意思是拥有]显示它的形式(使用params.WndParent 同上)

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 [sic; he meant owned] to the form that showed it (using params.WndParent as above)

但这在标准中是不可能的Dialogs 单元和 exceptions 中的对话框,需要更多的努力让它们正常工作(基本上处理 Application.OnActivate,通过 GetLastActivePopup 寻找以 Application 为父级的模态表单并通过 SetWindowPos 将它们带到 Z 顺序的顶部).

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).

  • 为什么模态表单最终会卡在其他表单之后?
  • 什么机制通常将模态表单带到前面,为什么它在这里不起作用?
  • 视窗®负责显示窗口堆叠.Windows出了什么问题?没有显示正确的窗口?
  • 他还谈到了使用新的 Windows 扩展样式,通过添加 WS_EX_APPWINDOW 扩展样式:

    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; 
    

    但是他警告说:

    如果您在另一个应用程序运行时单击辅助表单任务栏按钮active 这仍然会将所有申请表放在前面.如果你不希望有选项

    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

    当表单的所有者仍然是 Application.Handle 时,谁将所有的表单带到前面.应用程序 是否在执行此操作?为什么要这样做?与其这样做,难道不应该这样做吗?这样做的缺点是什么?我看到了这样做的缺点(系统菜单不能正常工作,任务栏按钮缩略图不准确,Windows® shell 无法最小化窗口.

    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.

    在另一篇关于 Application 的帖子中,Mike Edenfield说父窗口向其他窗口发送它们的最小化、最大化和恢复消息:

    In another post dealing with the Application, Mike Edenfield says that the parent window sends other window's their minimize, maximize and restore messages:

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

    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; 
    

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

    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.

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

    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;
    

    将删除 Application 和它的窗口句柄,以免干扰我的表单,Windows 应该再次向 me 发送我的 mimimize/maximize/restore 消息?

    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?

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

    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.

    • Application 对象求解是什么解决方案?
    • 在更高版本的 Delphi 中进行了哪些更改,以便不存在这些相同的问题?
    • Delphi 后续版本中的更改是否没有引入初始应用程序设计如此努力解决的其他问题?
    • 那些较新的应用程序如何在不干扰它们的情况下仍能正常运行?
    • 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?

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

    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?

    推荐答案

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

    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.

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

    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.

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

    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.

    这是使用此模型的结果.我们本可以手动完成所有这些工作以保持一切正常,但设计理念不是重新发明 Windows,而是尽可能地利用它.这也是为什么 TButton 或 TEdit 分别真正是 Windows用户"按钮和 EDIT 窗口类和样式的原因.

    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.

    随着 Windows 的发展,SDI"模型开始失宠.事实上,Windows 本身开始变得​​敌视"这种应用程序风格.从 Windows Vista 开始并继续到 7,用户外壳似乎不适用于使用停车窗口的应用程序.因此,我们开始在 VCL 中进行调整,以消除停车窗口并将其功能移至主窗体中.这提出了几个鸡与蛋"问题,即我们需要在应用程序初始化时足够早地使停车窗口可用,以便其他窗口可以附加"到它,但主窗体本身可能不会很快构建.TApplication 必须跳过几个环节才能使其正常工作,并且有一些微妙的边缘情况导致了问题,但大多数问题都已解决.但是,对于您向前推进的任何应用程序,它将继续使用旧的停车窗模型.

    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天全站免登陆