2重起動したら、先に起動したプログラムをアクティブにする





Delphi6でどう作ればいいかです。
2重起動はMutexを作って確認します。

先に起動したプログラムのウィンドウハンドルをSetForegroundWindowすればいいのですが、
どうやって取得するかが問題になってきます。

FindWindow系を使うと簡単そうですが、間違いなくこれ、というものを検索するのは難しいです。
探しだしたウィンドウが間違っている可能性は簡単には否定できません。

そこで、RegisterWindowMessageで、自分のアプリ専用のメッセージIDを作り、
HWND_BROADCASTでPostMessageを使ってブロードキャストを行います。

先に起動したプログラムでは、自分のメッセージIDのメッセージが来たら、
自分でトップに移動するか、2回目に起動したプログラムにトップに移動させてもらうかです。


注)
と、その前に、DelphiのフォームはすべてTApplicationの持つウィンドウの子ウィンドウなので
HWND_BROADCASTでポストしたメッセージが届きません。

まずは自分の適当なフォームで、HookMainWindowを使い、Applicationウィンドウのメッセージを
フックしてやる必要があります。
HookMainWindowを使わず、SetWindowLongを使って横取りしようとすると、
DelphiのアプリケーションはすべてオブジェクトインスタンスというメモリをWndProcに割り当てていて
これを解放するときにまずいことになります。



//--------------------------------------------------------------------------
2023/5/29追記
Delphi6では確かにメインフォームはApplicationウインドウの子ウインドウでした。
そして、トップレベルウインドウでないのでブロードキャストメッセージは届きませんでした。
ところが、Delphi10では様子が違うようです。
Delphi10.4のフォームのCreateParamsのソースを見ても、アプリケーションのメインフォームの場合、
Application(TApplicationのインスタンス)のウインドウの子ウインドウではなく、
トップレベルウインドウになるようになっています。
ここに書いてある内容も、ある意味時代遅れの内容になってしまっていますね。
//--------------------------------------------------------------------------

話を注釈の前まで戻します。自分でトップに移動するのはあまりエレガントではありません。
アクティブでないプログラムが自分からアクティブになるのを
Windows(マイクロソフト)はあまり良いと思っていないようです。

そこで、2回目に起動したプログラムはおそらく最前面のウィンドウを持つ、アクティブなプロセスですから、
ブロードキャストのときに、自分のウィンドウハンドルをWParamにでも入れておいて、
そのWParamのハンドルに向かって元のプログラムは適当な(WM_USER + ??)メッセージをポストしてやればいいです。
そのときにウィンドウハンドルをまたWParamなどで渡します。

さて、どのウィンドウハンドルを渡してやればいいでしょう。
自分のハンドルを返すと、何かShowModalしていたときはまずいです。
ShowModal以外に、Dialogs.pasに記述されている、TOpenDialogなどのダイアログも
トップに来ている可能性があります。
最初、VCLのソースコードに手を加えて、トップのウィンドウハンドルを保存していましたが、
Delphi Professional以上でしかできない技ですし、配布したソースコードも動かなくなります。
結局、Application.HandleをSetForegroundWindowしてやれば、
すべてのウィンドウが正しくトップに来ることがわかりました。


ソースコードも無しに解説しましたので、ちょっとわかりにくいかな?

テキストばかりで見づらいですが・・・まあ、ここまでお読みいただいた方にはありがとうございました。



戻る
inserted by FC2 system