画餅展覧会

2009 年 1 月 7 日

SetForegroundWindow(hwnd | 1)

カテゴリー: C++, JISかな入力パネル, KanaInput, Programming, Windows Mobile — jk78 @ 9:24 PM

不具合発見。KanaInputとChooseIMに共通のUI上の問題がある。再現方法は以下の通り。

  1. ChooseIMを立ち上げる。
  2. StartメニューからTodayを選ぶ。ChooseIMは隠れる。
  3. 再びChooseIMを実行する。1で実行中のChooseIMが現れる。
  4. この時点で、右上の[OK]ボタンが[×]になっており、キーボード入力を受け付けない。ダイアログの何処かをタップすることで[OK]ボタンが表示され、キー入力を受け付けるようになる。

KanaInputも同様である。コードを共有しているからね。回復のためにはタップが必要だ。ChooseIMはタッチパネルのない機種で使用することはないだろうけど、KanaInputをタッチパネルのない機種で使っていると、重篤な問題となる可能性がある。
話せば長くなるけれど、この二つのアプリケーションは、本来、ダイアログ・アプリケーションでありながら、実は、ダイアログの下に、表示されないフレーム・ウィンドウを持っている。なぜ、こんな構造になっているのかというと、ひとつには、Pocket PCでストレートなモーダル・ダイアログ・アプリケーションを動かすと、隠れてくれないのである。Today画面に切り替えてもToday画面の上に表示しつづけるので、Today画面が使えなくなる。でも、なぜかフレーム・ウィンドウが表示するモーダル・ダイアログは隠れてくれる。ので、隠れるために、フレーム・ウィンドウを持たせている。

ふたつには、アプリケーションが多重起動した時の処理である。前に立ち上げたインスタンスが実行中にふたつ目のインスタンスが実行を開始したら、以前のインスタンスを検出し、それをアクティブ化して、ふたつ目は終了する、という動作をしたい。でも、ダイアログ・ウィンドウだと、ウィンドウ・クラス名が不明なので、FindWindow()に難がある。そのために、独自のフレーム・ウィンドウを持たせて、FindWindow()を確実にしている。

さて、この、アプリケーション多重起動時に、フレーム・ウィンドウをFindWindow()して、SetForegroundWindow()してやると、なんと、表示中のモーダル・ダイアログではなく、フレーム・ウィンドウにフォーカスがあたってしまうのである。ダイアログ表示中の[OK]ボタンではなく、[×]ボタンが表示されているのが、フレーム・ウィンドウにフォーカスがあたっていることを示している。マウス・クリックがあると、本来のモーダル・ダイアログのフォーカスが復活する。この症状、デスクトップWindowsでも、そのまま再現する。

やれやれ、困ったな、何か良い解決法はないものかと探していたら、WTL 7.1のATL/WTL AppWizardが吐き出すコード(「Allow only one instance of app」ON)に、次のようなものを見つけてしまった。

// Set the previous instance as the foreground window
// The "| 0x1" in the code below activates the correct owned window
// of the previous instance's main window according to the SmartPhone 2003
// wizard generated code.
if(0 != SetForegroundWindow(reinterpret_cast<HWND>(reinterpret_cast<ULONG>(hwnd) | 0x1)))
{
// S_FALSE indicates that another instance was activated, so this instance should terminate.
return S_FALSE;
}

なんと、このコードを実行すると、SetForegroundWindow()が、然るべきモーダル・ダイアログをアクティベートしてくれる。hwnd | 1 だって。笑っちゃいました。当然この方法は、デスクトップWindowsでは使えない。上のコメントを見ると、OSの隠し機能は、Microsoft社内でさえ文書化されていないのだなあということが分かる。(追記:MSDNでコードサンプルを見つけました)
まあ、この機能を利用するとして、しかし、アプリケーションがアクティベートされるのは、自アプリケーションの重ね実行だけではない。私の環境でいくつかのパターンを試してみた。

  • 「メモリ」コントロールパネルの「実行中のプログラム」→ OK。ダイアログにフォーカスが当たる。
  • YTaskMgr → OK。ダイアログにフォーカスが当たる。
  • TranCreative Magic Button → OK。ダイアログにフォーカスが当たる。
  • FdcSoft Task Manager v3.1 → NG。フレーム・ウィンドウにフォーカスが当たる。

ううむ。やはりフレーム・ウィンドウにフォーカスが当てられた場合の対策もしておいたほうがよさそう。WM_ACTIVATEでダイアログにフォーカスを当てなおせばいいだろう。

で、KanaInputとChooseIMは改版が必要になりました。まあ、ひまを見てやります。

コメントはまだありません »

コメントはまだありません。

このコメント欄の RSS フィード トラックバック URL

コメントをどうぞ

Powered by WordPress