« WMリーダーの構造 | メイン | 続々・アラートウィンドウへフォーカスを移さない »

2005年10月19日

mixi Alert 開発日誌:: 続・アラートウィンドウへフォーカスを移さない

    

前回の対処方法(以下のソース参照)でもフォーカスが移動してしまう時がある。

Visible = true;
SetWindowPos( Handle, HWND_TOPMOST, 0, 0, 0, 0,  SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOSENDCHANGING );

移動しない時もあるのだが、いつ移動していつ移動しないのかはなぞ。
C++ BuilderでVCLを使っている以上避けられない問題なのだろうか?
と言う事で、VCLのソースを追ってみた。
でも、Object Pascal…… 変数の宣言で型が後に来るのと、if-thenやbegin-endさえ理解していれば、ある程度勘で読めるはず。

見たところ……
TCustomForm::CMShowingChangedで、表示に切り替わった時にShowWindowがコールされている。
TCustomForm::CMShowingChangedは、TWinControl::UpdateShowingが、メッセージを投げることで呼ばれる。
TWinControl::UpdateShowingは、TWinControl.UpdateControlStateで呼ばれる。
TWinControl.UpdateControlStateは、TWinControl::CMVisibleChangedで呼ばれる。
TWinControl.UpdateControlStateは、TControl::SetVisibleで値がセットされた時に呼ばれる。
TControl::SetVisibleは、Visibleプロパティに値が設定される時に呼ばれる。

実際には途中でいろいろと判定があるが、このような流れでShowWindowがコールされるようだ。

で、すぐに思いつく対処方法はーー
1. 上述の処理を自前で実装して、ShowWindowのところをSetWindowPosにする。
2. GetForegroundWindowで事前にフォーカスのあるウィンドウのハンドルを取得しておいて、自分を表示した後にSetForegroundWindowをコールして元に戻す。
ぐらい。
1. はコードを追った感じだとかなり大変。
でも、CMShowingChangedをオーバーライドすれば…… と思ったけど、privateだった。
そうだ、そうじゃなくてWndProcをオーバーライドしてCM_SHOWINGCHANGEDメッセージへの応答を書き換えれば比較的少ないコード量で対処できそう。
2. の方法に傾きかけていたけど、トリッキーなので避けたいなぁと思っていた。

が、すぐに問題は表出する。
Object Pascalがわからない。
TCustomForm::CMShowingChangedは、100行以上ある大きい関数。
そのほとんどすべてをC++に書き換えたいわけだが、raiseとかInclude()がよくわからない。
Object Pascalを勉強してもいいが……
方法2を使うことにしよう。
これであれば何があっても問答無用でフォーカスを元に戻せる。
ただ、他に機能拡張している途中なので実装はまた今度。
バージョン管理はしているので、ブランチさせてもいいが、マージが面倒。
結構長い間放置していたので、少し先になってもいいだろう。



投稿者 Takenori : 2005年10月19日 08:37




comments powered by Disqus
Total : Today : Yesterday : なかのひと