[delphi-users:5093] Application.MainForm.Handleが0になってしまう件について

109 views
Skip to first unread message

Mr.HS

unread,
Jan 23, 2019, 7:42:51 AM1/23/19
to delphi...@freeml.com
斎藤です。

連続の質問で大変申し訳ございませんが、よろしくお願いいたします。

DelphiXE5で作成したアプリにおいて、FormShowイベントでApplication.MainForm.Handle
を参照すると、0が返ってくる場合があります。

具体的には、

TAppFrm01 = class(TBaseForm)
   ・
   ・

procedure TAppFrm01.FormShow(Sender: TObject)
begin
inherited;
  ・
  ・
end;

procedure TBaseForm.FormShow(Sender: TObject)
begin
if Application.MainForm.Handle = Self.Handle then
別Exe起動(ShellExecute) // メインフォーム表示時のみ別Exeを起動する
end

ここの、Application.MainForm.Handle がなぜかゼロになってしまいます。
(Self.Handleは何かしらの値が入っている)

今までにわかっていること。

・同じ構成のアプリがいくつかあるのですが、この現象が発生するアプリと発生しないアプリ
 があります。
・発生するアプリと発生しないアプリで、ステップ実行して違いを探ってみましたが、違い
 を見つけることができませんでした。
・発生しないアプリでは、期待した動作が実現できています
  (Application.MainForm.Handle と Self.Handle が同じ値である)
・if Application.MainForm.Handle=0 や if Application.MainForm = nil のようなこと
 を記述するとAccessViolationで落ちます。

前回のスレッドでの質問のように、私が何か思い込みをしていて、気づかないだけなのかもしれ
ませんが、皆様のお知恵を拝借したく、よろしくお願いいたします。

斎藤 浩樹 / Hiroki-Saito


MLホームページ: https://www.freeml.com/delphi-users

----------------------------------------------------------------------
Powered by freeml -- https://www.freeml.com/ --
------------------------------------------------------[freeml byGMO]--

あなたの街のチラシがいつでも無料で見放題!
チラシをクリックしてチラシが拡大されたらポイントゲット♪
まずはかんたん登録♪ -ポイントタウン-
https://www.pointtown.com/ptu/rd.cgi?cid=8912
----------------------------------------------------------------------

Mr.XRAY

unread,
Jan 25, 2019, 12:57:28 AM1/25/19
to delphi...@freeml.com
こんにちは,Mr.XRAY です.
[delphi-users:5093] Application.MainForm.Handleが0になってしまう件につ
いて へのレスです.

>procedure TBaseForm.FormShow(Sender: TObject)
>begin
>if Application.MainForm.Handle = Self.Handle then
>別Exe起動(ShellExecute) // メインフォーム表示時のみ別Exeを起動する
>end
>
>ここの、Application.MainForm.Handle がなぜかゼロになってしまいます。

と書いていますが,

>・if Application.MainForm.Handle=0 や if Application.MainForm = nil のようなこと
> を記述するとAccessViolationで落ちます。

と書いています.では,どうやって 0 であることを確認したのでしょうか ?
=0 で例外が発生するのでは確認できないような気がしますが ?

if Application.MainForm.Handle
と書いてある行を削除すると例外は発生しないのでしょうか ?

Mr.HS

unread,
Jan 25, 2019, 4:33:00 AM1/25/19
to delphi...@freeml.com
こんばんわ。斎藤です

レスありがとうございます。

仰ることはもっともなので、再度確認しました。

結果、Application.MainForm.Handle がゼロではなく、Application.MainFormHandle
がゼロでした。
混乱させて申し訳ございませんでした。

確認は、ブレークポイントで止めて、ツールチップで表示させました。
Application.MainForm.Handle も同様にツールチップで確認しましたがAccessViolation でした。

> if Application.MainForm.Handle
> と書いてある行を削除すると例外は発生しないのでしょうか ?

削除すると例外は発生しません。

尚、FormShowでの参照をコメントアウトし、FormDestroyでApplication.MainFormHandle
を確認すると値が入っていました。

よろしくお願いいたします。

斎藤 浩樹 / Hiroki-Saito


Mr.XRAY

unread,
Jan 25, 2019, 5:00:08 AM1/25/19
to delphi...@freeml.com
こんにちは,Mr.XRAY です.

>削除すると例外は発生しません。

でしたら,MainForm が生成されているかを確認するには

>if Application.MainForm.<> nil then

というようにしてみてください.
オブジェクトの生成を確認する方がいいと思います.
MainForm.Handle としてしまうと,MainForm が nil の時には
プロパティやメソッドにアクセスできません.
まずオブジェクトの存在を確認します.

Mr.XRAY

unread,
Jan 25, 2019, 5:13:05 AM1/25/19
to delphi...@freeml.com
こんにちは,Mr.XRAY です.

>if Application.MainForm.<> nil then
>
>というようにしてみてください.

Application.MainFormHandle を使用すると MainForm が nil の時に
0 を返してくれます.
0 というのは MainForm のウィンドウがないということです.念のため.

Mr.HS

unread,
Jan 25, 2019, 7:48:04 PM1/25/19
to delphi...@freeml.com
Mr.XRAY さん、こんにちは。

ご回答ありがとうございます。

> >if Application.MainForm.<> nil then
>
> というようにしてみてください.

試してみました。
このとおり記述するとコンパイルエラーになるので
if Application.MainForm <> nil then

で検証しました。

Access Violationも発生することなく判定することができました

ご教示いただきましたように

if Application.MainFormHandle = 0

でも、同様に判定することができました。

メインフォームは必ず存在すると決め付けて、存在を確認せずに、それのプロパティ
等にアクセスするという考え方が間違っていたことに気づきました。
これに限らず、使用前には存在を確認することを徹底するように考えを改めます。


最初に戻って、IDE上のプロジェクトオプションでメインフォームが指定されて
いるにもかかわらず、MainForm がnilになる場合があるのはなぜなのか、自分なりに
調査しました。

方法としてDelphiでは、最初に作成したフォームがメインフォームになるとのことから
Application.CreateForm を見てみました。

引数で指定されたフォームを作成した後、FMainForm(MainFormプロパティ)がnilの場合
作成したフォームのハンドルを取得後、FMainFormに代入しているところを見つけましたの
で、ここでプロパティの設定をしていることは確認できました。

ただ、Exe起動時に、FMainFormをnilに初期化している部分を見つけることができなかった
ので、何かゴミが入っていたりするとおかしくなるのか・・、であれば、特定のEXEだけ
MainFormがnilになってしまうのもおかしい話かな・・、等々考えており、まだ結論
に至っていません。

自分なりにもう少し探ってみて、何か分かったら、この場をお借りしてご報告したいと
思います。


先の質問共々、ご回答いただきましたこと、心より感謝申し上げます。

ありがとうございました。

斎藤 浩樹 / Hiroki-Saito

Mr.HS

unread,
Jan 25, 2019, 8:05:36 PM1/25/19
to delphi...@freeml.com
斎藤です。

記載が抜けておりました。

最初は Application.MainForm <> nil でもAccessViolationが発生していたと記載
しましたが、今回はなぜか発生しませんでした。

そこも併せて検証の上ご報告させていただきます。

質問しているにもかかわらず、情報が二転三転してしまい、申し訳ございません。

よろしくお願いいたします。

Mr.XRAY

unread,
Jan 26, 2019, 7:11:33 AM1/26/19
to delphi...@freeml.com
こんにちは,Mr.XRAY です.

テストプログラムを作成してみました.

[01_NonError_1] -- 例外が発生しないプログラム
[02_NonError_2] -- 例外が発生しないプログラム
[03_Error] -- 例外が発生するプログラム

[01_NonError_1] と [03_Error]フォルダ内の *.pas, * dfm ファイルは
全く同じです.
[01_NonError_2] フォルダ内の *.pas, * dfm ファイルは
unit1.pas を除いて [01_NonError_1] と同じです.

スレッドの文章ではどういう手順で何をどうしているのか分かりませんので,
テストプログラムはあくまでも私の勝手な推測で作成しています.
動作確認は Windows 7 U64(SP1) + Delphi XE5(UP2) Pro VCL-32 です.

[テストプログラムのダウンロード]
http://mrxray.on.coocan.jp/Delphi/zip/DelphiML_5093.zip

Mr.HS

unread,
Jan 26, 2019, 10:21:13 AM1/26/19
to delphi...@freeml.com
Mr.XRAY さん、こんばんわ。

斎藤です。

テストプログラムまで作成いただき、本当にありがとうございます。

又、言葉不足で大変申し訳ございません。

やりたいことは、システム専用の操作ガイドプログラム(EXE、Delphi製)があ
ります。
この操作ガイドプログラムは二重起動防止処理を入れてあります。

システム内のプログラムをメニューから起動させたとき、起動されたEXE内で
自身のメインフォームが表示されるタイミングで操作ガイドプログラムを起動さ
せることをやっています。
その際、表示されるフォームがメインフォームかどうかの判定をMainForm.Handle
で行っていますが、起動されたEXEによって、操作ガイドが起動されたりされなかった
りしましたので、原因を探っていたところ、MainForm.Handleがnilになっているため
に操作ガイドが起動しないことが判明しました。

ともかく、いただいたテストプログラムをダウンロードさせていただき、自分なりに
動作確認をして見ます。

来週初めになると思いますが、結果をご報告させていただきます。

よろしくお願いいたします。

斎藤 浩樹 / Hiroki-Saito


Mr.HS

unread,
Feb 1, 2019, 6:45:43 AM2/1/19
to delphi...@freeml.com
こんばんわ 斎藤です。

返信が大変遅くなり、申し訳ございません。

あれから、頂いたサンプルと、自分で作成したものを何度も動作させてみて分かった
ことを報告させていただきます。

Delphi10.2でも、同じ現象が発生し、ステップ実行でApplication.CreateForm内を
トレースしてみました。

動作順序として

Application.CreateForm関数内

  Instance.Create(Self);
       |
    FormCreateイベントプロシージャ
       |
    FormShowイベントプロシージャ
       |
  TForm(Instance).HandleNeeded;
  FMainForm := TForm(Instance);

の順で動作しているようでした。

この動作では、FormShowイベント中ではまだMainFormプロパティが設定されていないので
期待する動作ができないものと認識しました。

私はFormCreateイベントが発生した後、Application.RunメソッドでFormShowイ
ベントが発生すると思い込んでいましたし、今までこのような組み方で別に問題が発生
していませんでした
(アプリ終了時にフォームの位置をIniファイル等に記録しておき、アプリ起動時に復元
 させる処理 でのメインフォーム判定で問題が発生しなかったという意味です)
ので、なぜこのようになったのかはわかりません。
 (事実、同じ継承フォームを使用し、同じコーディングでも、うまく取得で
  きているアプリもあります。)

FormShowイベントプロシージャは、CM_SHOWINGCHANGED メッセージにて起動されるようなの
ですが、そのメッセージをポストしている箇所の特定には至っていませんので、なんとも
言えませんが、現状ここまで分かりました。

ただ、トレース実行なので、実際のEXEを実行させたときと何か差があるのかもしれません。

今は、FormShowイベントの代わりにどのタイミングで処理を行うかを検討中です。

この動作や検証結果でなにかお気づきの点などありましたら、大変恐縮ですがご意見等頂戴
できれば幸いです。

以上、ありがとうございました。

斎藤 浩樹 / Hiroki-Saito


MLホームページ: https://www.freeml.com/delphi-users

----------------------------------------------------------------------
【完全版】インターネット回線のおすすめ6社まとめ!これでもう迷わない!
https://ad.atown.jp/adserver/cp?sid=8646d&did=6d1b&emid=&u1=
Reply all
Reply to author
Forward
0 new messages