47


20

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

「TApplication.Handle」とは何ですか?

  • それはどこから来たのですか?

  • なぜ存在するのですか?

  • そして最も重要なのは、なぜすべてのフォームが親ウィンドウとしてそれを持っているのか 扱う?

Delphiヘルプには次のように書かれています:

_ _ * TApplication.Handle *

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

property Handle: HWND;

説明

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

アプリケーションのメインフォームのウィンドウハンドル」という言葉に注目し、それを_アプリケーションのメインフォームのウィンドウハンドル_を意味するとすれば、比較できます。

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

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

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

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

では、「Application.Handle」とは何ですか?

  • それはどこから来たのですか?

  • Windows®ウィンドウハンドルとは何ですか?

  • 「アプリケーション」のWindows®ウィンドウハンドルである場合 「MainForm」、それではなぜ一致しないのですか?

  • Application`の MainForm`のウィンドウハンドルでない場合は、 それは何ですか?

  • さらに重要なのは、なぜそれが究極の[ラインスルー] *親*オーナーなのか あらゆる形態の?

  • そして最も重要なことは、私が…​ フォームは[line-through] * unparented * unowned(つまり、TaskBarに表示できるようにする)にするか、* IProgressDialog *のようなものを使用してみてください。

本当に私が求めているのは、* Application.Handle *を存在させる設計原理は何ですか? 理由を理解できれば、その方法が明らかになるはずです。

'' '' '

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

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

モーダルフォームの起動中にユーザーがアプリから切り替えて、それを表示したフォームに戻ると、モーダルフォームがフォームの下に隠れてしまう場合があります。 これに対処するには、モーダルフォームの親が[sic;彼はそれを示したフォームに所有されていることを意味しました]

しかし、これは、 Dialogs`ユニットの標準ダイアログと*例外*では不可能です。これらを正しく動作させるには、より多くの労力が必要です(基本的には、 Application.OnActivate`を処理し、 `Application * GetLastActivePopup`と、それらを `SetWindowPos`を介してZオーダーの一番上に移動します)。 _ _

  • モーダルフォームが他のフォームの後ろに詰まるのはなぜですか?

  • 通常、モーダルフォームを前面に表示するメカニズムとその理由 ここでは機能しませんか?

  • Windows®は、積み重ねられたウィンドウの表示を担当します。 何がなくなった Windows®が正しいウィンドウを表示していないのは間違っていますか?

また、「WS_EX_APPWINDOW」拡張スタイルを追加することにより、タスクバーにウィンドウを強制的に表示する新しいWindows拡張スタイルの使用についても説明しました(非所有にする通常のルールが不十分、非実用的、または望ましくない場合)。

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

   Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
end;

しかし、それから彼は注意します:

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

フォームの所有者がまだ「Application.Handle」であるときに、誰がすべてのフォームを前面に持ってくるか。 *アプリケーション*はこれを行っていますか? それはなぜこれをしているのですか? これを行うのではなく、これを行うべきではありませんか? これを「行わない」ことのマイナス面は何ですか? *それを*行う*の欠点があります(システムメニューが正しく機能しない、タスクバーボタンのサムネイルが不正確で、Windows®シェルがウィンドウを最小化できない

'' '' '

「アプリケーション」に関する別の投稿では、http://www.delphi3000.com/articles/article_723.asp?SK = [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アプリケーションのすべてのフォームは「アプリケーション」によって「所有」されますか? それは所有者をnullにすることを意味するものではありません:

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

は、 `Application`を削除し、そのウィンドウハンドルがフォームに干渉するのを防ぎます。Windowsは再び_me_ mymimize / maximize / restoreメッセージを送信する必要がありますか?

'' '' '

おそらく、現在の「通常の」Windowsアプリケーションと、ボーランドが最初に物事を行うためにDelphiアプリケーションを設計した方法とを比較対照すると、この「アプリケーション」オブジェクトとそのメインループに関してです。

  • 「アプリケーション」オブジェクトはどのような解決策でしたか?

  • これらが同じになるように、Delphiの以降のバージョンでどのような変更が行われたか 問題は存在しませんか?

  • Delphiの以降のバージョンでの変更は、他を導入しませんでした 問題、最初のアプリケーション設計が解決するために一生懸命努力したこと?

  • これらの新しいアプリケーションは、アプリケーションなしでもどのように機能しますか それらに干渉しますか?

明らかに、ボーランドは初期設計の欠陥を認識していました。 彼らの初期設計は何でしたか、それはどの問題を解決していましたか、何が欠陥で、何が再設計でしたか、そしてそれはどのように問題を解決しますか?

3 Answer


48


アプリケーションウィンドウの理由には、少し厄介な歴史があります。 Delphi 1を開発するとき、IDEに「SDI」(デスクトップ全体に散らばるウィンドウ)UIモデルを使用したいと思っていました。 また、Windowsがそのモデルを吸い込んだ(そして今でもしている)ことも知っていました。 ただし、その時点でVisual Basicがそのモデルを採用しており、うまく機能しているように思われました。 さらなる調査の結果、VBは他のすべての可視ウィンドウに対して「所有者」として使用される特別な「隠された」駐車ウィンドウを使用していることがわかりました(Windowsは親と所有者の概念を曖昧にしますが、区別はVCLに似ています) 。

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

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

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

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


12


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

アプリのトップレベルウィンドウを非表示にすると、奇妙なことが起こります。タスクバーに表示される不完全なシステムメニューや、Vistaの不適切なサムネイルウィンドウです。 Delphiの新しいバージョンではこれが修正されています。

ただし、すべてのウィンドウが親としてそれを持たなければならないわけではありません。Windowsがあれば、よりうまく動作する傾向があります。 ただし、Application.CreateFormを使用して作成されたフォームは親として作成され、Applicationオブジェクトによっても所有されます。 所有されているため、アプリケーションが解放されると解放されます。 これは、Forms.DoneApplicationの背後で発生します


8


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

  • TApplication.Minimize

  • TApplication.Restore

  • etc

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

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

あなたの質問ごと:

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

  • *どのウィンドウを処理しますか?*すべてのGUIデルファイアプリが使用する偽のウィンドウ TApplication抽象化の一部として必要

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

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

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

  • *そして最も重要なこと:私が フォームは親なし*隠された「マスター」フォームは、その子および/またはメインフォームに_should__渡すシステムメッセージを取得しているが、親なしのフォームが見つからないためだと思います。

とにかく、それは私の考えです。 Tformの宣言と `forms.pas`のコードを見れば、おそらくもっと学ぶことができます。 私が見るものの一番下の行は、それが便利な抽象化であるということです。

宜しくお願いします、

Don