Win32 イベント駆動型プログラミングは内部的にどのように実装されていますか?
-
12-09-2019 - |
質問
Win32 C++ アプリケーションでは、キューからメッセージをフェッチし、変換してディスパッチするメッセージ ループを開始します。最終的に、各メッセージは WndProc に到達し、そこで関連するイベントが処理されます。
その部分は理解しています。私が理解できないのは、一連の出来事の間のことです。具体的には:
- さまざまな種類の OS 割り込みハンドラーが、前述の「メッセージ キュー」にメッセージを配置する必要がありますが、このキューはプロセス アドレス空間内のどこに存在するのでしょうか?どのようにして割り込みハンドラー コードにさらされるのでしょうか?
- メッセージを「翻訳」するとはどういう意味ですか?何宛の電話ですか
TranslateMessage()
本当にそうなの? - によって発送されると、
DispatchMessage()
, 、私の WndProc に到達する前に、メッセージはどのような場所を通過しますか (つまり、OSはそれをどうするのですか?)
誰か上記の答えを知っている人がいたら、親切に私の好奇心を満たしてください。ありがとう。
解決
OSは、(例えば、割り込みまたは他のソースからの)イベントを置くメッセージ・キューを維持します。その後、(例えば、それがフォーカスを持たないウィンドウに重要なメッセージを送信しません)メッセージに応じて、すべてのウィンドウにそのキューからメッセージを送信します。
アプリケーションがメッセージを処理するための独自のキューを持つことができます。必要に応じて(場合にのみ、これらのキューは、要求の上を作成しています)。
メッセージを翻訳すると、「実際の」イベントではありませんメッセージを作成するために使用されます。例えば、WM_CONTEXTMENUメッセージは、マウスの右クリック、またはコンテキストメニューキーのいずれかから「翻訳」され、またはシフト-F10を。 WM_CHARはWM_KEYDOWNメッセージから翻訳されます。そしてもちろん、他の多くのメッセージがそのように「翻訳」されます。
メッセージは、それを受けるべきすべてのウィンドウに投稿されています。 OSはウィンドウがそのメッセージを受信すべきか否かのメッセージの種類に応じて決定します。ほとんどのメッセージは、それが、ウィンドウによって処理されるまでのシステム、すなわちによって、メッセージが別のウィンドウに投稿さ得ることはありませんを待っています。これは、ブロードキャストメッセージのために大きなインパクトを持っている:そのメッセージを処理するときに一つのウィンドウが戻らない場合は、キューが<のhref = "http://blogs.msdn.com/oldnewthing/archive/2005/03/10/392118です.aspxの」REL = "nofollowをnoreferrer">ブロックされと他のウィンドウはもうメッセージを受信しません。
他のヒント
それはあなたのメッセージが送信され、それが処理されますどのようにどのように依存します。
あなたはSendMessage関数を呼び出すと、ターゲットウィンドウが現在のスレッドによって所有されている場合、、、呼び出しがウィンドウのメッセージキューをバイパスし、ウィンドウマネージャは、直接ターゲットウィンドウ上のWindowProcを呼び出します。ターゲットウィンドウが別のスレッドによって所有されている場合は、ウィンドウマネージャが効果的のPostMessageを呼び出し、ウィンドウPROCからターゲットウィンドウ戻るまで、ウィンドウメッセージをポンプます。
あなたはのPostMessage、ウィンドウマネージャのマーシャルメッセージパラメータを呼び出し、ターゲットウィンドウのメッセージキューに対応するオブジェクトを挿入します。それは次のGetMessageを呼び出すと、メッセージがメッセージキューから削除されます。
ウィンドウマネージャは、入力装置(キーボード及び/又はマウス)からの生の入力イベントを登録し、それはそれらの入力イベントのためのメッセージを生成します。その後、(それがウィンドウのメッセージキューにすでにあるものをメッセージに依存するため、入力イベントの処理が複雑である)必要に応じて、キューにそれらのメッセージを挿入します。
ステファンはTranslateMessageがちょうどアクセラレータキーを変換し、示されているように - 例えば、それは、メッセージをWM_COMMANDするキーシーケンスを変換する
OSの割り込みハンドラの異なる種類が言った「メッセージキュー」にメッセージを配置する必要がありますが、どこのプロセスのアドレス空間内で、このキューが存在するのでしょうか?それはどのように割り込みハンドラのコードにさらされている?
のWindowsは、スレッドに関連付けられています。ウィンドウで各スレッドは、プロセスのアドレス空間内のスレッドのキューを持っています。 OSは、ハードウェア生成されたイベントのために、独自のアドレス空間での内部キューを持っています。 (ウィンドウにフォーカスが例えば、)イベント、および他の状態情報の詳細を使用して、OSが適切なスレッドキューに置かれるメッセージにハードウェアイベントを変換します。
投稿されたメッセージは、ターゲットウィンドウのためのスレッドキューに直接配置されます。
送信されるメッセージは、通常、(キューをバイパスして)直接処理されます。
詳細は毛深い得ます。たとえば、スレッドキューは、メッセージのリスト以上のもの - 彼らはまた、いくつかの状態情報を維持します。 (WM_PAINTのような)一部のメッセージは、実際にキューイングされていますが、キューを照会し、それが空の場合に、追加の状態情報から合成されていません。他のスレッドが所有するウィンドウに送信されたメッセージは、実際には、受信機のキューにポストされているのではなく、直接処理されているが、システムは、通常のブロッキングがビューの呼び出し側の視点から送るようにそれが表示されます。 (円形の元のスレッドに送り返すため)、これはデッドロックを引き起こす可能性があればはしゃぎが続く。
ジェフリー・リヒターの本は、血みどろの詳細の多くを(すべて?)持っています。私の版が古い(アドバンストWindowsの場合)です。現行版では、C / C ++ を介して、のWindowsと呼ばれているようです。
OSは、メッセージストリームを作るために多くの仕事は、呼び出し側に合理的(かつ比較的簡単な)が表示されない。
それはメッセージを「翻訳」とはどういうこと? TranslateMessage()の呼び出しが実際に何をしますか?
これは、仮想キーメッセージを監視して、それがキーダウン/キーアップの組み合わせを認識したとき、それは文字のメッセージを追加します。あなたが呼び出していない場合は TranslateMessage に、あなたはWM_CHARのような文字メッセージを受信しません。
私はそれが(それらを掲示は対照的に)返す前に直接、文字メッセージを送る疑い。私がチェックしたことがありませんが、私はWM_CHARメッセージがちょうどWM_KEYUP前に到着することを思い出しているようだ。
(OSはそれで何をするのか、すなわち)?私のWndProcに到達する前にすることにより、メッセージのスイングを何すべての場所DispatchMessageを()、によって派遣されると、
DispatchMessageをターゲットウィンドウのWndProcメソッドにメッセージを渡します。道に沿って、それはいくつかのフックは、(それに干渉する可能性と)メッセージを見る機会を得ることができます。
最後の設問に対処するために、派遣メッセージがあなたのWindowProcに行きます(WH_CALLWNDPROC)
これについては完全に肯定的ではありませんが、私の推測では次のようになります。
キューは、Win32 API 呼び出しでアクセスするシステム オブジェクトです。プロセスのアドレス空間にはまったくありません。したがって、割り込みハンドラーは (おそらくカーネルの HAL (ハードウェア抽象化レイヤー) を介して) これにアクセスできます。
Win16 では、この呼び出しにより、より大きなメッセージのさまざまなサブパートが取得され、それらが 1 つの全体にマッシュされます。したがって、TranslateMessage は、対応する WM_KEYDOWN WM_KEYUP シーケンスを見つけたときに、WM_KEYPRESS を追加します。また、内部設定とメッセージのタイムスタンプに基づいて、さまざまなボタン クリック メッセージをダブルクリック メッセージに変換します。Win32 でもこれが行われるかどうかはわかりません。
DispatchMessage は、おそらく Windows メッセージ フックが処理される場所です。したがって、ウィンドウにフックがある場合は、ここで呼び出されるか、GetMessage が呼び出されたときに呼び出されます。よくわからない。それ以外では、DispatchMessage はウィンドウに関連付けられた WndProc アドレスを検索して呼び出すだけです。他にやるべきことはあまりありません。
それが役立つことを願っています。