web-dev-qa-db-ja.com

Delphi:Application.Handleとは何ですか?

TApplication.Handleとは何ですか?

  • それはどこから来たのですか?
  • なぜそれが存在するのですか?
  • そして最も重要なこと:なぜすべてのフォームが親ウィンドウハンドルとしてそれを持っているのですか?

Delphiヘルプは言う:

TApplication.Handle

アプリケーションのメインフォーム(ウィンドウ)のウィンドウハンドルへのアクセスを提供します。

property Handle: HWND;

説明

親ウィンドウハンドルを必要とするWindows API関数を呼び出すときにHandleを使用します。たとえば、独自のトップレベルのポップアップウィンドウを表示するDLLは、アプリケーションでウィンドウを表示するために親ウィンドウを必要とします。Handleプロパティを使用すると、そのようなウィンドウがアプリケーションの一部になるため、アプリケーションで最小化、復元、有効化、無効化されること。

アプリケーションのメインフォームのウィンドウハンドル」という単語に焦点を当て、それをメインのウィンドウハンドルと解釈するとアプリケーションの形式、それから私は比較することができます:

  • 「アプリケーションのメインフォームのウィンドウハンドル」で、
  • MainFormApplicationのウィンドウハンドル

しかし、それらは同じではありません:

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

では、Application.Handleとは何でしょうか。

  • それはどこから来たのですか?
  • どのWindows®ウィンドウハンドルですか?
  • それがisである場合、ApplicationMainFormのWindows®ウィンドウハンドルは一致しないのはなぜですか?
  • ApplicationMainFormのウィンドウハンドルがではない場合、それは何ですか?
  • さらに重要なこと:なぜそれが究極なのか  すべてのフォームの所有者ですか?
  • そして最も重要なのは、フォームを作成しようとするとなぜすべてがうまくいかないのですか? 親なし 所有されていない(タスクバーに表示できるようにする)か、IProgressDialogのようなものを使用しようとしますか?

本当に私が求めているのは:Application.Handleを存在させる設計の根拠は何ですか?その理由が理解できれば、どうやって明らかになるでしょう。


更新20の質問のゲームを通して理解:

オーナーをnullにすることでウィンドウをタスクバーに表示する解決策について話すとき、 2000年のピーター・ビロウは言った

これにより、セカンダリフォームから表示されるモーダルフォームで問題が発生する可能性があります。

モーダルフォームが表示されているときにユーザーがアプリから離れ、それを表示したフォームに戻ると、モーダルフォームがフォームの下に隠れている場合があります。モーダルフォームの親を確実に作成することで、これに対処できます[シック;彼は所有することを意味しました]それを示したフォームに(上記のようにparams.WndParentを使用して)

しかし、これはDialogsユニットの標準ダイアログとexceptionsでは不可能です。基本的にApplication.OnActivateを処理し、GetLastActivePopupを介してApplicationを親とするモーダルフォームを探し、それらを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; 

しかしそれから彼は警告します:

別のアプリがアクティブなときにセカンダリフォームのタスクバーボタンをクリックすると、すべてのアプリケーションフォームが前面に表示されます。オプションがあることを望まない場合

フォームの所有者がApplication.Handleであるときに、誰がすべてのフォームを前面に持っているか。 Applicationはこれを行っていますか?なぜこれを行うのですか?これを行うのではなく、しないでくださいこれをしていませんか? これをしないの欠点は何ですか? それをしていることのマイナス面を見る(システムメニューが正しく機能しない、タスクバーボタンのサムネイルが不正確、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; 

このハンドラは、[〜#〜] parent [〜#〜]の形式で、独立して動作したい>残りのアプリケーション。最小化メッセージを渡さないようにします。 SC_MAXIMIZE、SC_RESTOREなどの同様のコードを追加できます。

Windows®ウィンドウのメッセージを最小化/最大化/復元すると、ウィンドウに移動しないのはなぜですか?これは、Windows®からウィンドウの所有者に、ウィンドウ宛のメッセージが送信されるためですか?この場合、DelphiアプリケーションのすべてのフォームはApplicationによって「所有」されていますか?それは所有者をnullにすることを意味しません:

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

Applicationを削除し、ウィンドウハンドルがフォームに干渉しないようにします。Windowsは再びme私のmimimize/maximize/restoreメッセージを送信しますか?


おそらく、これを比較して対比すると、「通常の」Windowsアプリケーションは、Borlandが最初にDelphiアプリケーションを設計して、このApplicationオブジェクトとそのメインループに関して物事を行うように設計しました。

  • Applicationオブジェクトが解決したソリューションは何ですか?
  • Delphiの新しいバージョンでは、これらの同じ問題が存在しないようにどのような変更が加えられましたか?
  • Delphiの新しいバージョンでの変更は他の問題を引き起こしませんでしたか?最初のアプリケーションデザインが解決するために一生懸命に試みましたか?
  • アプリケーションがアプリケーションに干渉することなく、これらの新しいアプリケーションをどのように機能させることができますか?

明らかに、ボーランドは初期の設計に欠陥があることに気付きました。彼らの最初のデザインは何でしたか、それは何の問題を解決しましたか、欠陥は何ですか、再デザインは何でしたか、そしてそれはどのように問題を解決しましたか?

49
Ian Boyd

アプリケーションウィンドウの理由には、ちょっとひどい履歴があります。 Delphi 1を開発するとき、IDEに「SDI」(デスクトップ全体に散在するウィンドウ)のuiモデルを使用したいと考えていました。 Windowsがそのモデルに負けた(そして今でもそうである)ことも知っていました。しかし、当時のVisual Basicはそのモデルを採用しており、うまく機能しているようにも見えました。さらなる調査の結果、VBは「所有者」として使用される特別な「隠された」駐車ウィンドウを使用していることがわかりました(Windowsは時々親と所有者の概念をぼかしますが、違いは似ています)他のすべての表示ウィンドウのVCLに)。

これは、メインメニューを含むウィンドウがめったにフォーカスされなかったため、[ファイル]メニューのAlt-Fの処理が機能しないという「問題」を解決した方法です。この中央パーキングウィンドウを仲介として使用することにより、適切なウィンドウへのメッセージの追跡とルーティングをより簡単に行うことができます。

この配置により、通常は複数のトップレベルウィンドウが完全に独立しているという別の問題も解決されました。アプリケーションにこれらすべてのウィンドウの「所有者」を処理させることにより、それらはすべて協調して動作します。たとえば、アプリケーションウィンドウのanyを選択すると、allアプリケーションウィンドウが前面に移動し、互いのzオーダーが維持されることに気づいたかもしれません。これにより、アプリケーションが最小化され、機能グループとして復元されます。

これは、このモデルを使用した結果です。我々はcouldすべての作業を手動で行って物事を正直にしていますが、設計哲学はWindowsを再発明するのではなく、それを可能な限り活用することでした。これが、TButtonまたはTEditがreally Windowsの「ユーザー」ボタンおよび編集ウィンドウクラスとスタイルである理由でもあります。

Windowsが進化するにつれて、その「SDI」モデルは支持を失い始めました。実際、Windows自体がそのスタイルのアプリケーションに対して「敵対的」になり始めました。 Windows Vistaから7まで続くと、ユーザーShellはパーキングウィンドウを使用するアプリケーションではうまく機能しないようです。そこで、VCLで物事をシャッフルして、パーキングウィンドウを削除し、その機能をメインフォームに移動することにしました。これにより、いくつかの「鶏と卵」の問題が発生し、他のウィンドウが「アタッチ」できるように、アプリケーションの初期化の早い段階でパーキングウィンドウを利用できるようにする必要がありますが、メインフォーム自体はすぐに構築されない可能性があります。 TApplicationはこれを機能させるためにいくつかのフープを通過する必要があり、問題を引き起こしたいくつかの微妙なEdgeケースがありましたが、問題のほとんどは解決されています。ただし、先に進むアプリケーションについては、古いパーキングウィンドウモデルを使用したままになります。

49
Allen Bauer

すべてのVCLアプリには、アプリケーションと呼ばれる「非表示」のトップレベルウィンドウがあります。これは、アプリケーションの起動時に自動的に作成されます。とりわけ、それはVCLのメインウィンドウメッセージハンドラです-したがって、Application.ProcessMessagesです。

アプリの最上位ウィンドウを非表示にすると、奇妙なことが発生します。タスクバーに表示されるシステムメニューが不完全であったり、Vistaのサムネールウィンドウが正しく表示されないことがあります。 Delphiの新しいバージョンではこれを修正しています。

ただし、すべてのウィンドウが親として持っている必要はありません。もしそうであれば、Windowsはよりよく機能する傾向があります。ただし、Application.CreateFormで作成されたフォームは、それを親として持ち、Applicationオブジェクトによって所有されます。それらは所有されているため、アプリケーションが解放されると解放されます。これはForms.DoneApplicationの舞台裏で起こります

12
Gerry Coll

Forms.pas(Delphi 2009)でソースを見ると、Win32 GUIアプリで「マスター」ウィンドウを作成して、

  • TApplication.Minimize
  • TApplication.Restore

Application.Handleに渡されたメッセージは、存在する場合、MainFormに適切に転送されているようです。これにより、メインウィンドウが作成されていない場合、アプリは最小化などに応答できます。プロジェクトソースを変更することで、delphiアプリなしメインウィンドウを作成できます。

この場合、メインウィンドウを作成していなくても、TApplicationメソッドは機能します。すべての目的を把握しているかどうかはわかりませんが、すべてのTApplicationコードを確認する時間はありません。

あなたの質問ごとに:

  • どこから来るのですか?TApplication.Createで作成されたウィンドウのハンドルです

  • どのウィンドウで処理されますか? TApplication抽象化の一部としてすべてのGUI Delphiアプリに必要な偽のウィンドウ

  • アプリケーションのメインフォームのWindowsハンドルですかいいえ

  • アプリケーションのメインフォームのハンドルでない場合、それは何ですか?上記を参照

  • より重要なのは、なぜすべてのフォームの最終的な親なのか?あなたが正しいことがその最終的な親であると仮定すると、アプリケーション内のすべてのフォームを簡単に見つけられるようになるからです。 (この「マスター」フォームの子を列挙)。

  • そして最も重要なのは、フォームを親なしにしようとすると、なぜすべてがうまくいかないのか非表示の「マスター」フォームがシステムメッセージを受け取っているためだと思いますすべき渡すその子および/またはメインフォームに、しかし親のないフォームを見つけることができません。

とにかく、それは私の考えです。 TApplicationの宣言とforms.pasのコードを調べることで、詳細を確認できるでしょう。私が見るものからの結論は、それが便利な抽象化であるということです。

宜しくお願いします、

ドン

8
Don Dickinson