「バックグラウンド・スレッドから上げたモーダル・ダイアログがモーダルにならない理由」などを理解できるようにする。†Windowsプログラムは、エントリポイント(プログラムの開始)である(1)WinMain?と、Windowsから呼び出されて渡されたメッセージを処理する(2)ウインドウプロシ-ジャ(通常WinProc?と書く)から成り立つ。(1)WinMain?の中は、(A)ウインドウクラスの登録(B)ウィンドウの作成(C)ウインドウの表示(D)メッセージループの4つのパートから成り立つ。メッセージ用のキュー。ウィンドウ・システム(WindowsのGUI)の根幹をなすメカニズム。†Windowsメッセージキューは、1つのスレッドが1つだけ保持できる。ウィンドウを作成したスレッドには、Windowsメッセージキューが与えられる。スレッドからメッセージ系のAPIを使用した場合も、Windowsメッセージキューが与えられる。この際、システムは、THREADINFO構造体を作成してスレッドに割り当てる。THREADINFO構造体はWindowsメッセージキューに関する情報を持っている。†Windowsメッセージキューは、複数のウィンドウ間で共有される。通常、1つのプロセスは、1つのUIスレッドで、複数(全て)のウィンドウを処理する。このため、通常、1プロセス、1UIスレッド、1Windowsメッセージキューになる。画面間の通信をスレッドセーフに実装する必要があり実装し難くなる。後述のWin32APIを使用する。PostMessage()メッセージ・ループにキューイングする。SendMessage()ウィンドウ・プロシージャ(WndProc?)を直接呼び出す。†プロセス間通信スレッド間通信COMのSTA(呼び出しの直列化)などでも利用される。構造体をDispatchMessage?関数でウィンドウ・プロシージャに渡す。†.NETで言う、FormもControlも全てがウィンドウ(hwnd:ウィンドウハンドルを持つ)。基本的な情報が登録されている。RegisterClassEx?で登録する。登録し、CreateWindowEXで、ウィンドウを作る。来る(これについては後述)。†あらかじめ登録されている既定のウィンドウクラスとしては"BUTTON""COMBOBOX""EDIT""LISTBOX""MDICLIENT""RichEdit?""RICHEDIT_CLASS""SCROLLBAR""STATIC"がある(.NETで言う、Control的なもの)。下記のRegisterClassEx?関数を使用せずに作成可能。hwnd,...)する。†VC++のダイアログエディタで、ダイアログリソースを作ってCreateDialog?する。来る(これについては後述)。†イベントハンドラみたいなもの。以下のように、イベントハンドラを実装する。親ウィンドウクラスに対してSendMessageでWM_Commandを送るようになっている。WM_COMMAND:等を使用して追加する。元あったWndProc?を呼ばなければ、そのイベントの処理を置き換え。元のWndProc?を呼ぶことで、WndProc?のチェインに割って入る。この既定のWndProc?を置き換えることで、イベントの挙動(≠イベント・ハンドラ、ボタン押下時にボタンが凹む等)をカスタマイズすることが可能である。(Windows)http://msdn.microsoft.com/ja-jp/library/windows/desktop/ms633576.aspxウィンドウクラスの属性を表します。関数http://msdn.microsoft.com/ja-jp/library/cc410996.aspxウィンドウクラスを登録します。関数http://msdn.microsoft.com/ja-jp/library/cc410713.aspxメモリ上にウィンドウを生成します。関数http://msdn.microsoft.com/ja-jp/library/cc411211.aspxウィンドウを表示します。関数http://msdn.microsoft.com/ja-jp/library/cc428780.aspxウィンドウを更新します。†PostMessageはメッセージ・ループにキューイングする。つのメッセージをポストします。対応するスレッドがメッセージを処理するのを待たずに制御を返します。つのメッセージをポストします。この関数は、スレッドがメッセージを処理するのを待たず、即座に制御を返します。メッセージをメッセージキューにポストする。†SendMessageはウィンドウ・プロシージャ(WndProc?)を直接呼び出す。複数のウィンドウへ、指定されたメッセージを送信します。指定されたウィンドウのウィンドウプロシージャを呼び出します。ウィンドウプロシージャがメッセージを処理し終わった後で、制御を返します。基本的には、サブルーチン的にイベント実装を処理するためのもの。スレッド跨ぎか否かで動作が大きく異なる。スレッド跨ぎでない場合、サブルーチン的にイベント実装を処理スレッド跨ぎの場合、送信・応答メッセージキューを使用する(同期呼出の実現)。処理の優先度は、PostMessageより高い。以下は、SendMessageの同期呼出ハングの問題を回避するための関数(送信側)。タイムアウト機能付きバージョン。同一スレッドからの場合はタイムアウト地を無視する。Callback機能付き非同期版(即座に制御を返す)オーバーラップウィンドウにメッセージをブロードキャストできる。関数http://msdn.microsoft.com/ja-jp/library/cc411012.aspxPostMessageに近いが、以下の点がPostMessageと異なる。PostMessageよりも優先度が高い(先にキューから取り出される)。スレッド跨ぎでない場合、SendMessage的に動作する。以下は、SendMessageの同期呼出ハングの問題を回避するための関数(受信側)。関数http://msdn.microsoft.com/ja-jp/library/cc411016.aspxSendMessage送信側の応答メッセージキューに結果をポストし、制御を返す。スレッド跨ぎでない場合、何もしない(falseを返す)。関数http://msdn.microsoft.com/ja-jp/library/cc364787.aspxスレッド跨ぎでない場合、falseを返す。スレッド跨ぎの場合、trueを返す。構造体http://msdn.microsoft.com/ja-jp/library/vstudio/900ks98t.aspxメッセージのデータを表します。関数とは異なり、メッセージキューにメッセージがなかった場合、メッセージがポストされるのを待たずに制御を返す。構造体をウィンドウ・プロシージャに渡す。関数http://msdn.microsoft.com/ja-jp/library/cc364868.aspxウィンドウへ送信されたメッセージを処理する、アプリケーション定義のコールバック関数です。関数http://msdn.microsoft.com/ja-jp/library/cc410753.aspx既定のウィンドウプロシージャを呼び出して、既定の処理を提供します。この関数は、すべてのメッセージが処理されることを保証します。メッセージウィンドウプロシージャはその全てのメッセージに対応できなければならないため。メッセージをメッセージキューにポストする。queue:仮想入力キュー)/(THREADINFO構造体内)RITが接続するVIQのスレッドを識別するマウスポインタ:マウスカーソルの下のウィンドウのスレッドキーストローク:フォアグラウンド・ウィンドウのスレッドその他、Alt+Tabなどの特殊キー・シーケンスを処理する。関数http://msdn.microsoft.com/ja-jp/library/cc411074.aspxWM_SETFOCUSVIQの切り替えはできない。通常、RITに接続されているときだけ呼び出す。スレッド1がRITに接続しているときにスレッド2が自身のウィンドにSetFocus?を呼び出すと2つのフォーカス矩形が現れ問題。関数http://msdn.microsoft.com/ja-jp/library/cc364641.aspxローカル入力状態からフォーカスを持つウィンドウのHWNDを返す。関数http://msdn.microsoft.com/ja-jp/library/cc411014.aspxウィンドウをアクティブにする。RITに接続するVIQの切り替えはできない。通常、RITに接続されているときだけ呼び出す。関数http://msdn.microsoft.com/ja-jp/library/cc410861.aspxローカル入力状態からアクティブなウィンドウのHWNDを返す。関数http://msdn.microsoft.com/ja-jp/library/cc410618.aspxHWND_TOPを指定しSetWindowPos?を呼び出す(RITに接続するVIQを変更可能)。関数http://msdn.microsoft.com/ja-jp/library/cc411206.aspxウィンドウをアクティブにしてサイズ、位置、Zオーダを変更(RITに接続するVIQを変更可能)。関数http://msdn.microsoft.com/ja-jp/library/cc364732.aspxフォアグラウンド・ウィンドウのHWNDを返す。受け取っていない場合にのみ成功するように機能を追加した。失敗の際は、タスクバーをフラッシュさせる。関数http://msdn.microsoft.com/ja-jp/library/cc430255.aspx指定したプロセスのスレッドがSetForgroundWindow?を呼び出すことを許可する。関数http://msdn.microsoft.com/ja-jp/library/cc410898.aspx他のSetForgroundWindow?呼出をロックする(Windowsスタートメニューなどで使用されている)。関数http://msdn.microsoft.com/ja-jp/library/cc364676.aspx最後のキー入力を返す。入力フォーカスを持ったウィンドウを持ってる必要はない。関数http://msdn.microsoft.com/ja-jp/library/cc364583.aspxキーが押されているか?前回の呼び出し以降にキーが押されたか?を返す。入力フォーカスを持ったウィンドウを持ていること。関数http://msdn.microsoft.com/ja-jp/library/cc410663.aspxマウス・カーソルの範囲を指定する(非同期的なアクティブ化イベントで中止)。関数http://msdn.microsoft.com/ja-jp/library/cc411051.aspxマウス・カーソルがウィンドウの範囲内にあるかどうかに関わり無く、すべてのマウス入力を受け取る。つのウィンドウだけがマウスをキャプチャできる。通常はマウスのボタン押下後に呼び出す。関数http://msdn.microsoft.com/ja-jp/library/cc410990.aspx上記のマウスのキャプチャを停止する。関数http://msdn.microsoft.com/ja-jp/library/cc429027.aspx複数のスレッドに複数のVIQとローカル入力状態を共有させる。応答メッセージキューウェイクフラグについては自分のものを使い続ける。このAPIはシステムの強度を損なう可能性がある。用途としてはジャーナルの記録・再生フックをインストールした場合。API関数で自分のフォームを前面に出します。その後もう一度AttachThreadInputAPI関数でデタッチして解除すれば可能です。Windowsの仕様に反しますが。†UIオートメーションの裏側。現行はどっちを使用しているんでしょうか?答えは、GetMessege?のフックらしい。AttachThreadInput?でSetWindowLongPtr?を使用して別プロセスのウィンドウをサブクラス化できるか?と言うとこれは当然できない。これは、呼び出し元のWndProc?のアドレスが呼び出し先のプロセスで有効でないから。これを可能にする方法がある。「DLL注入」と「APIフック」である。インジェクションhttp://keicode.com/windows/win08.phpレジストリエントリを使用してDLLを注入する。問題としては汎用性がない点が挙げられる。DLLを注入してSetWindowLongPtr?を実行する。別プロセスのウィンドウにGetMsgProc?フックプロシージャをインストールしてメッセージを監視する。GetMsgProc?フックプロシージャは、前述のDLL注入のDLL中に実装しておく。†フックタイプにはWH_GETMESSAGEを指定する。メッセージキューへポストされたメッセージを監視する1個のフックプロシージャをインストール。フックは、メッセージ系を処理するものが多数である。その他、シェル、デバッガ、CBT用途のフックなどがある。関数ポインタには、GetMsgProc?フックプロシージャを指定する。詳細については、GetMsgProc?フックプロシージャの説明を参照。関数がアプリケーションのメッセージキューからメッセージを取得するときに、必ずこの関数を呼び出す。システムは、取得したメッセージを目的のウィンドウプロシージャへ渡す前に、そのメッセージをこのフックプロシージャに渡す。同じ位置でなければ、システムが自動的に呼出先プロセスの関数アドレスを算出する。これにより、「呼出先プロセス」でSetWindowLongPtr?を実行できる。(ただし本来の用途とは異なる。.etcまた、フックチェーンを実装することもできる。Spyを使用すると、ウィンドウのメッセージの分析が可能。イベントの順番を確認する。欲しいイベントのメッセージが来ているか?調べる。当該イベントではどのようなメッセージが来るのか?調べる。SetCapture?により別のマウスイベントが来てしまっていないか?確認する。SendMessage/PostMessageどちらで送られてきているか?確認する。当該ウィンドウのウィンドウ名を確認する。ウィンドウクラス名を確認する。ウィンドウ位置、大きさを確認する。値が変わっているかを確認する。