メッセージとメッセージ キューについて

MS-DOS ベースのアプリケーションとは異なり、Windows ベースのアプリケーションはイベント ドリブンです。 入力を取得するために明示的な関数呼び出し (C ランタイム ライブラリ呼び出しなど) は行いません。 代わりに、システムが入力を渡すのを待ちます。

システムは、アプリケーションのすべての入力をアプリケーションのさまざまなウィンドウに渡します。 各ウィンドウには、ウィンドウ プロシージャと呼ばれる関数があり、ウィンドウに対する入力がある場合は常にシステムが呼び出します。 ウィンドウ プロシージャは入力を処理し、システムに制御を返します。 ウィンドウ プロシージャの詳細については、「 ウィンドウ プロシージャ」を参照してください。

最上位のウィンドウが数秒間以上メッセージへの応答を停止した場合、システムはウィンドウが応答していないと見なします。 この場合、システムはウィンドウを非表示にし、同じ Z オーダー、位置、サイズ、およびビジュアル属性を持つゴースト ウィンドウに置き換えます。 これにより、ユーザーはそれを移動したり、サイズを変更したり、アプリケーションを閉じることもできます。 ただし、アプリケーションが実際に応答していないため、使用できるアクションはこれらだけです。 デバッガー モードの場合、システムはゴースト ウィンドウを生成しません。

このセクションでは、次のトピックについて説明します。

Windows メッセージ

システムは 、メッセージの形式でウィンドウ プロシージャに入力を渡します。 メッセージは、システムとアプリケーションの両方によって生成されます。 ユーザーが入力、マウスの移動、スクロール バーなどのコントロールのクリックなど、各入力イベントでメッセージを生成します。 また、アプリケーションがシステム フォント リソースのプールを変更したり、ウィンドウのサイズを変更したりしたときなど、アプリケーションによって発生したシステムの変更に応じてメッセージも生成されます。 アプリケーションは、タスクを実行したり、他のアプリケーションのウィンドウと通信したりするために、独自のウィンドウを指示するメッセージを生成できます。

システムは、ウィンドウ ハンドル、メッセージ識別子、およびメッセージ パラメーターと呼ばれる 2 つの値の 4 つのパラメーターのセットを使用して、 ウィンドウ プロシージャにメッセージを送信します。 ウィンドウ ハンドルは、メッセージの対象となるウィンドウを識別します。 システムはそれを使用して、メッセージを受け取るウィンドウ・プロシージャーを判別します。

メッセージ識別子は、メッセージの目的を識別する名前付き定数です。 ウィンドウ プロシージャは、メッセージを受信すると、メッセージ識別子を使用してメッセージの処理方法を決定します。 たとえば、メッセージ識別子 WM_PAINT は、ウィンドウのクライアント領域が変更され、再描画する必要があることをウィンドウ プロシージャに通知します。

メッセージ パラメーターは、メッセージの処理中にウィンドウ プロシージャによって使用されるデータまたはデータの場所を指定します。 メッセージ パラメーターの意味と値は、メッセージによって異なります。 メッセージ パラメーターには、整数、パックされたビット フラグ、追加データを含む構造体へのポインターなどを含めることができます。 メッセージがメッセージ パラメーターを使用しない場合、通常は NULL に設定されます。 ウィンドウ プロシージャでは、メッセージ識別子をチェックして、メッセージ パラメーターの解釈方法を決定する必要があります。

メッセージ型

このセクションでは、次の 2 種類のメッセージについて説明します。

System-Defined メッセージ

システムは、アプリケーションと通信するときに システム定義メッセージ を送信またはポストします。 これらのメッセージを使用して、アプリケーションの操作を制御し、アプリケーションが処理するための入力やその他の情報を提供します。 アプリケーションは、システム定義メッセージを送信またはポストすることもできます。 アプリケーションでは通常、これらのメッセージを使用して、事前登録されたウィンドウ クラスを使用して作成されたコントロール ウィンドウの操作を制御します。

各システム定義メッセージには、メッセージの目的を示す一意のメッセージ識別子と、対応するシンボリック定数 (ソフトウェア開発キット (SDK) ヘッダー ファイルで定義) があります。 たとえば、 WM_PAINT 定数は、ウィンドウがその内容を描画することを要求します。

シンボリック定数は、システム定義メッセージが属するカテゴリーを指定します。 定数のプレフィックスは、メッセージを解釈して処理できるウィンドウの種類を識別します。 プレフィックスと関連するメッセージ カテゴリを次に示します。

Prefix メッセージ カテゴリ ドキュメント
ABMABN アプリケーション デスクトップ ツール バー シェル メッセージと通知
ACMACN アニメーション コントロール アニメーション コントロール メッセージアニメーション コントロール通知
BCMBCNBM、BN Button コントロール ボタン コントロール メッセージボタン コントロール通知
CBCBN ComboBox コントロール ComboBox コントロール メッセージComboBox コントロール通知
CBEMCBEN ComboBoxEx コントロール ComboBoxEx メッセージComboBoxEx 通知
Ccm 一般的なコントロール メッセージの制御
CDM [共通] ダイアログ ボックス [共通] ダイアログ ボックス のメッセージ
Dfm 既定のコンテキスト メニュー シェル メッセージと通知
DL リスト ボックスをドラッグする リスト ボックスの通知をドラッグする
DM 既定のプッシュ ボタン コントロール ダイアログ ボックス メッセージ
DTMDTN 日付と時刻の選択コントロール 日付と時刻の選択メッセージ日付と時刻の選択の通知
EMEN 編集コントロール コントロール メッセージの編集コントロール通知の編集リッチ エディット メッセージリッチ エディット通知
HDMHDN ヘッダー コントロール ヘッダー コントロール メッセージヘッダー コントロール通知
HKM ホット キー コントロール ホット キー制御メッセージ
IPMIPN IP アドレス コントロール IP アドレス メッセージIP アドレス通知
LBLBN リスト ボックス コントロール リスト ボックス メッセージリスト ボックス通知
LM SysLink コントロール SysLink コントロール メッセージ
LVMLVN リスト ビュー コントロール リスト ビュー メッセージリスト ビュー通知
MCMMCN 月の予定表コントロール 月の予定表のメッセージ月の予定表の通知
PBM (PBM) 進行状況バー 進行状況バーのメッセージ
PGMPGN ポケットベル コントロール ポケットベル コントロール メッセージポケットベル コントロール通知
PSMPSN プロパティ シート プロパティ シートのメッセージプロパティ シートの通知
RBRBN Rebar コントロール Rebar コントロール メッセージRebar コントロール通知
SBSBN ステータス バー ウィンドウ ステータス バーのメッセージステータス バーの通知
Sbm スクロール バー コントロール スクロール バーメッセージ
Smc シェル メニュー シェル メッセージと通知
STMSTN 静的コントロール 静的コントロール メッセージ静的コントロール通知
TBTBN ツール バー ツール バー コントロール メッセージツール バー コントロール通知
TBMTRBN トラックバー コントロール トラックバーコントロールメッセージトラックバーコントロール通知
TCMTCN タブ コントロール タブ コントロール メッセージタブ コントロール通知
TDMTDN [タスク] ダイアログ タスク ダイアログ メッセージタスク ダイアログ通知
TTMTTN ツールヒント コントロール ヒント コントロール メッセージヒント コントロール通知
TVMTVN ツリー ビュー コントロール ツリー ビュー メッセージツリー ビュー通知
UDMUDN アップダウン コントロール アップダウン メッセージアップダウン通知
Wm 全般
クリップボード メッセージ
クリップボード通知
[共通] ダイアログ ボックスの通知
カーソル通知
データ コピー メッセージ
デスクトップ ウィンドウ マネージャーメッセージ
メッセージのデバイス管理
ダイアログ ボックスの通知
動的データ交換メッセージ
動的データ交換通知
フック通知
キーボード アクセラレータ メッセージ
キーボード アクセラレータの通知
キーボード入力メッセージ
キーボード入力通知
メニュー通知
マウス入力通知
複数のドキュメント インターフェイス メッセージ
生入力通知
スクロール バーの通知
タイマー通知
ウィンドウ メッセージ
ウィンドウ通知

一般的なウィンドウ メッセージは、マウスとキーボード入力のメッセージ、メニューとダイアログ ボックスの入力、ウィンドウの作成と管理、動的データ交換 (DDE) など、さまざまな情報と要求に対応します。

メッセージのApplication-Defined

アプリケーションは、独自のウィンドウで使用したり、他のプロセスのウィンドウと通信したりするためのメッセージを作成できます。 アプリケーションが独自のメッセージを作成する場合は、メッセージを受け取るウィンドウ プロシージャがメッセージを解釈し、適切な処理を提供する必要があります。

メッセージ識別子の値は次のように使用されます。

  • システムは、システム定義メッセージの0x03FF (WM_USER - 1) を介して 0x0000 範囲内のメッセージ ID 値を予約します。 アプリケーションでは、プライベート メッセージにこれらの値を使用できません。
  • 0x0400範囲の値 ( WM_USERの値) から0x7FFFは、プライベート ウィンドウ クラスのメッセージ識別子に使用できます。
  • アプリケーションがバージョン 4.0 とマークされている場合は、プライベート メッセージの0xBFFF 0x8000 (WM_APP) の範囲内でメッセージ識別子の値を使用できます。
  • システムは、アプリケーションが RegisterWindowMessage 関数を呼び出してメッセージを登録するときに、0xFFFF 0xC000範囲内のメッセージ識別子を返します。 この関数によって返されるメッセージ識別子は、システム全体で一意であることが保証されます。 この関数を使用すると、他のアプリケーションが異なる目的で同じメッセージ識別子を使用する場合に発生する可能性がある競合を防ぐことができます。

メッセージのルーティング

システムは、メッセージをウィンドウ プロシージャにルーティングする 2 つの方法を使用します。メッセージをメッセージ キューと呼ばれる先入れ先出し キュー、メッセージを一時的に格納するシステム定義のメモリ オブジェクト、およびウィンドウ プロシージャにメッセージを直接送信します。

メッセージ キューにポストされるメッセージは、 キューに登録されたメッセージと呼ばれます。 これらは主に、WM_MOUSEMOVE、WM_LBUTTONDOWN、WM_KEYDOWNWM_CHARメッセージなど、マウスまたはキーボードを介して入力されたユーザー入力の結果です。 キューに入れられたその他のメッセージには、タイマー、ペイント、終了メッセージ ( WM_TIMERWM_PAINTおよびWM_QUIT) が含まれます。 ウィンドウ プロシージャに直接送信される他のほとんどのメッセージは、 非キューメッセージと呼ばれます。

キューに入ったメッセージ

システムは、一度に任意の数のウィンドウを表示できます。 マウスとキーボードの入力を適切なウィンドウにルーティングするために、システムはメッセージ キューを使用します。

システムは、GUI スレッドごとに 1 つのシステム メッセージ キューと 1 つのスレッド固有メッセージ キューを保持します。 GUI 以外のスレッドのメッセージ キューを作成するオーバーヘッドを回避するために、すべてのスレッドが最初にメッセージ キューなしで作成されます。 システムは、スレッドが特定のユーザー関数の 1 つを最初に呼び出す場合にのみ、スレッド固有のメッセージ キューを作成します。GUI 関数呼び出しは行われません。その結果、メッセージ キューが作成されます。

ユーザーがマウスを移動したり、マウス ボタンをクリックしたり、キーボードの種類をクリックしたりするたびに、マウスまたはキーボードのデバイス ドライバーによって入力がメッセージに変換され、システム メッセージ キューに配置されます。 システムは、一度に 1 つずつメッセージをシステム メッセージ キューから削除し、メッセージを調べて宛先ウィンドウを特定し、宛先ウィンドウを作成したスレッドのメッセージ キューにメッセージをポストします。 スレッドのメッセージ キューは、スレッドによって作成されたウィンドウのすべてのマウス メッセージとキーボード メッセージを受け取ります。 スレッドはキューからメッセージを削除し、処理のために適切なウィンドウ プロシージャに送信するようにシステムに指示します。

WM_PAINT メッセージ、WM_TIMER メッセージ、およびWM_QUIT メッセージを除き、システムは常にメッセージ キューの末尾にメッセージを投稿します。 これにより、ウィンドウが適切な最初の入力、先出し (FIFO) シーケンスで入力メッセージを受け取ります。 ただし、WM_PAINT メッセージ、WM_TIMER メッセージ、およびWM_QUIT メッセージはキューに保持され、キューに他のメッセージが含まれない場合にのみウィンドウ プロシージャに転送されます。 さらに、同じウィンドウ の複数のWM_PAINT メッセージが 1 つの WM_PAINT メッセージに結合され、クライアント領域のすべての無効な部分が 1 つの領域に統合されます。 WM_PAINTメッセージを組み合わせると、ウィンドウがクライアント領域の内容を再描画する必要がある回数が減ります。

システムは、 MSG 構造体を入力してメッセージ キューにコピーすることで、メッセージをスレッドのメッセージ キューにポストします。 MSG の情報には、メッセージの対象となるウィンドウのハンドル、メッセージ識別子、2 つのメッセージ パラメーター、メッセージが投稿された時刻、およびマウス カーソル位置が含まれます。 スレッドは、 PostMessage 関数または PostThreadMessage 関数を使用して、メッセージを独自のメッセージ キューまたは別のスレッドのキューに投稿できます。

アプリケーションは 、GetMessage 関数を使用してキューからメッセージを削除できます。 キューからメッセージを削除せずにメッセージを調べるには、アプリケーションで PeekMessage 関数を使用できます。 この関数は 、メッセージ に関する情報を MSG に入力します。

キューからメッセージを削除した後、アプリケーションは DispatchMessage 関数を使用して、処理のためにメッセージをウィンドウ プロシージャに送信するようにシステムに指示できます。 DispatchMessage は、GetMessage または PeekMessage 関数の以前の呼び出しによって入力された MSG へのポインター受け取ります。 DispatchMessage は 、ウィンドウ ハンドル、メッセージ識別子、および 2 つのメッセージ パラメーターをウィンドウ プロシージャに渡しますが、メッセージが投稿された時刻やマウス カーソル位置は渡されません。 アプリケーションは、メッセージの処理中に GetMessageTime 関数と GetMessagePos 関数を呼び出すことによって、この情報を取得できます。

スレッドは WaitMessage 関数を使用して、メッセージ キューにメッセージがない場合に他のスレッドに制御を提供できます。 関数はスレッドを中断し、新しいメッセージがスレッドのメッセージ キューに配置されるまでは返されません。

SetMessageExtraInfo 関数を呼び出して、値を現在のスレッドのメッセージ キューに関連付けることができます。 次に 、GetMessageExtraInfo 関数を呼び出して、 GetMessage または PeekMessage 関数によって取得された最後のメッセージに関連付けられた値を取得します。

キューに入れされていないメッセージ

キューに登録されていないメッセージは、システム メッセージ キューとスレッド メッセージ キューをバイパスして、宛先ウィンドウ プロシージャに直ちに送信されます。 システムは通常、キューに入れされていないメッセージを送信して、そのメッセージに影響を与えるイベントのウィンドウに通知します。 たとえば、ユーザーが新しいアプリケーション ウィンドウをアクティブ化すると、WM_ACTIVATE、WM_SETFOCUSWM_SETCURSORなどの一連のメッセージがウィンドウに送信されます。 これらのメッセージは、ウィンドウがアクティブ化されていること、キーボード入力がウィンドウに送信されていること、およびマウス カーソルがウィンドウの境界線内で移動されたことを通知します。 キューに入れられなかったメッセージは、アプリケーションが特定のシステム関数を呼び出したときにも発生する可能性があります。 たとえば、システムは、アプリケーションが SetWindowPos 関数を使用してウィンドウを移動した後に、WM_WINDOWPOSCHANGED メッセージを送信します。

キューに入れないメッセージを送信する関数には、 BroadcastSystemMessageBroadcastSystemMessageExSendMessageSendMessageTimeoutSendNotifyMessage があります。

メッセージ処理

アプリケーションは、スレッドのメッセージ キューにポストされたメッセージを削除して処理する必要があります。 シングルスレッド アプリケーションでは、通常、WinMain 関数のメッセージ ループを使用して、処理のために適切なウィンドウ プロシージャにメッセージを削除して送信します。 複数のスレッドを持つアプリケーションでは、ウィンドウを作成する各スレッドにメッセージ ループを含めることができます。 次のセクションでは、メッセージ ループのしくみと、ウィンドウ プロシージャの役割について説明します。

メッセージ ループ

単純なメッセージ ループは、GetMessage、TranslateMessage、DispatchMessage の 3 つの関数それぞれに対する 1 つの関数呼び出しで構成されます。 エラーが発生した場合、 GetMessage は –1 を返すので、特別なテストが必要であることに注意してください。

MSG msg;
BOOL bRet;

while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{ 
    if (bRet == -1)
    {
        // handle the error and possibly exit
    }
    else
    {
        TranslateMessage(&msg); 
        DispatchMessage(&msg); 
    }
}

GetMessage 関数は、キューからメッセージを取得し、MSG 型の構造体にコピーします WM_QUIT メッセージが発生しない限り、0 以外の値を返します。その場合は FALSE を返し、ループを終了します。 シングル スレッド アプリケーションでは、多くの場合、メッセージ ループを終了することが、アプリケーションを閉じる最初の手順です。 アプリケーションは、PostQuitMessage 関数を使用して独自のループを終了できます。通常は、アプリケーションのメイン ウィンドウのウィンドウ プロシージャのWM_DESTROY メッセージに応答します。

GetMessage の 2 番目のパラメーターとしてウィンドウ ハンドルを指定した場合、指定されたウィンドウのメッセージのみがキューから取得されます。 GetMessage では、キュー内のメッセージをフィルター処理して、指定した範囲内にあるメッセージのみを取得することもできます。 メッセージのフィルター処理の詳細については、「 メッセージのフィルター処理」を参照してください。

スレッドがキーボードから文字入力を受け取る場合は、スレッドのメッセージ ループに TranslateMessage を含める必要があります。 ユーザーがキーを押すたびに、仮想キー メッセージ (WM_KEYDOWN および WM_KEYUP) が生成されます。 仮想キー メッセージには、押されたキーを識別する仮想キー コードが含まれていますが、その文字値は識別しません。 この値を取得するには、メッセージ ループに TranslateMessage が含まれている必要があります。これにより、仮想キー メッセージが文字メッセージ (WM_CHAR) に変換され、アプリケーション メッセージ キューに戻されます。 その後、メッセージ ループの後続の反復時に文字メッセージを削除し、ウィンドウ プロシージャにディスパッチできます。

DispatchMessage 関数は、MSG 構造体で指定されたウィンドウ ハンドルに関連付けられているウィンドウ プロシージャにメッセージを送信します。 ウィンドウ ハンドルが HWND_TOPMOST場合、 DispatchMessage は システム内のすべての最上位ウィンドウのウィンドウ プロシージャにメッセージを送信します。 ウィンドウ ハンドルが NULL の場合、 DispatchMessage はメッセージに対して何も行いません。

アプリケーションのメイン スレッドは、アプリケーションを初期化し、少なくとも 1 つのウィンドウを作成した後、メッセージ ループを開始します。 メッセージ ループが開始されると、スレッドのメッセージ キューからメッセージが引き続き取得され、適切なウィンドウにディスパッチされます。 メッセージ ループは 、GetMessage 関数がメッセージ キューから WM_QUIT メッセージを削除すると終了します。

アプリケーションに多数のウィンドウが含まれている場合でも、メッセージ キューに必要なメッセージ ループは 1 つだけです。 DispatchMessage は 常にメッセージを適切なウィンドウにディスパッチします。これは、キュー内の各メッセージが、メッセージが属するウィンドウのハンドルを含む MSG 構造体であるためです。

メッセージ ループは、さまざまな方法で変更できます。 たとえば、キューからメッセージをウィンドウにディスパッチせずに取得できます。 これは、ウィンドウを指定しないメッセージを投稿するアプリケーションに役立ちます。 また、 GetMessage に特定のメッセージを検索するように指示し、他のメッセージをキューに残すこともできます。 これは、メッセージ キューの通常の FIFO 順序を一時的にバイパスする必要がある場合に便利です。

アクセラレータ キーを使用するアプリケーションは、キーボード メッセージをコマンド メッセージに変換できる必要があります。 これを行うには、アプリケーションのメッセージ ループに TranslateAccelerator 関数の呼び出しを含める必要があります。 アクセラレータ キーの詳細については、「 キーボード アクセラレータ」を参照してください。

スレッドがモードレス ダイアログ ボックスを使用する場合、ダイアログ ボックスがキーボード入力を受け取ることができるように、メッセージ ループに IsDialogMessage 関数を含める必要があります。

Window プロシージャ

ウィンドウ プロシージャは、ウィンドウに送信されたすべてのメッセージを受信して処理する関数です。 すべてのウィンドウ クラスにはウィンドウ プロシージャがあり、そのクラスで作成されたすべてのウィンドウでは、同じウィンドウ プロシージャを使用してメッセージに応答します。

システムは、メッセージ データを引数としてプロシージャに渡すことによって、ウィンドウ プロシージャにメッセージを送信します。 その後、ウィンドウ プロシージャはメッセージに対して適切なアクションを実行します。メッセージ識別子がチェックされ、メッセージの処理中に、メッセージ パラメーターで指定された情報が使用されます。

通常、ウィンドウ プロシージャはメッセージを無視しません。 メッセージを処理しない場合は、既定の処理のためにメッセージをシステムに送り返す必要があります。 ウィンドウ プロシージャは、既定のアクションを実行し、メッセージの結果を返す DefWindowProc 関数を呼び出すことによってこれを行います。 その後、ウィンドウ プロシージャは、この値を独自のメッセージ結果として返す必要があります。 ほとんどのウィンドウ プロシージャでは、少数のメッセージのみを処理し、 DefWindowProc を呼び出して他のメッセージをシステムに渡します。

ウィンドウ プロシージャは同じクラスに属するすべてのウィンドウで共有されるため、複数の異なるウィンドウのメッセージを処理できます。 メッセージの影響を受ける特定のウィンドウを識別するために、ウィンドウ プロシージャは、メッセージと共に渡されたウィンドウ ハンドルを調べることができます。 ウィンドウ プロシージャの詳細については、「 ウィンドウ プロシージャ」を参照してください。

メッセージのフィルター処理

アプリケーションでは、 GetMessage または PeekMessage 関数を使用してメッセージ フィルターを指定することで、メッセージ キューから取得する特定のメッセージを選択できます (他のメッセージは無視されます)。 フィルターは、メッセージ識別子の範囲 (最初と最後の識別子で指定)、ウィンドウ ハンドル、またはその両方です。 GetMessagePeekMessage では 、メッセージ フィルターを使用して、キューから取得するメッセージを選択します。 メッセージ フィルター処理は、アプリケーションがメッセージ キューを検索して、後でキューに到着したメッセージを検索する必要がある場合に便利です。 また、アプリケーションが投稿されたメッセージを処理する前に入力 (ハードウェア) メッセージを処理する必要がある場合にも役立ちます。

WM_KEYFIRST定数とWM_KEYLAST定数をフィルター値として使用して、すべてのキーボード メッセージを取得できます。WM_MOUSEFIRST定数とWM_MOUSELAST定数を使用して、すべてのマウス メッセージを取得できます。

メッセージをフィルター処理するアプリケーションでは、メッセージ フィルターを満たすメッセージを投稿できるようにする必要があります。 たとえば、アプリケーションがキーボード入力を受け取らないウィンドウで WM_CHAR メッセージをフィルター処理した場合、 GetMessage 関数は返しません。 これにより、アプリケーションが実質的に "ハング" します。

メッセージの投稿と送信

どのアプリケーションでも、メッセージを投稿および送信できます。 システムと同様に、アプリケーションはメッセージをメッセージ キューにコピーしてメッセージを投稿し、メッセージ データを引数としてウィンドウ プロシージャに渡すことによってメッセージを送信します。 メッセージを投稿するために、アプリケーションは PostMessage 関数を使用します。 アプリケーションは、 SendMessageBroadcastSystemMessageSendMessageCallbackSendMessageTimeoutSendNotifyMessage、または SendDlgItemMessage 関数を呼び出すことによってメッセージを送信できます。

メッセージの投稿

アプリケーションは通常、タスクを実行するように特定のウィンドウに通知するメッセージを投稿します。 PostMessage は メッセージの MSG 構造体を作成し、メッセージをメッセージ キューにコピーします。 アプリケーションのメッセージ ループは、最終的にメッセージを取得し、適切なウィンドウ プロシージャにディスパッチします。

アプリケーションは、ウィンドウを指定せずにメッセージを投稿できます。 アプリケーションが PostMessage を呼び出すときに NULL ウィンドウ ハンドルを提供する場合、メッセージは現在のスレッドに関連付けられているキューにポストされます。 ウィンドウ ハンドルが指定されていないため、アプリケーションはメッセージ ループでメッセージを処理する必要があります。 これは、特定のウィンドウではなく、アプリケーション全体に適用されるメッセージを作成する 1 つの方法です。

場合によっては、システム内のすべての最上位ウィンドウにメッセージを投稿することがあります。 アプリケーションは、PostMessage を呼び出し、hwnd パラメーターで HWND_TOPMOSTを指定することで、すべての最上位ウィンドウにメッセージを投稿できます。

一般的なプログラミング エラーは、 PostMessage 関数が常にメッセージを投稿することを想定することです。 これは、メッセージ キューがいっぱいの場合は当てはまらない。 アプリケーションは、PostMessage 関数の戻り値をチェックして、メッセージが投稿されているかどうかを判断し、投稿していない場合は再投稿する必要があります。

sending messages

通常、アプリケーションは、タスクを直ちに実行するようにウィンドウ プロシージャに通知するメッセージを送信します。 SendMessage 関数は、指定されたウィンドウに対応するウィンドウ プロシージャにメッセージを送信します。 この関数は、ウィンドウ プロシージャの処理が完了するまで待機し、メッセージの結果を返します。 親ウィンドウと子ウィンドウは、多くの場合、相互にメッセージを送信して通信します。 たとえば、編集コントロールを子ウィンドウとして持つ親ウィンドウでは、メッセージを送信してコントロールのテキストを設定できます。 コントロールは、親ウィンドウにメッセージを送り返すことによって、ユーザーが実行するテキストに対する変更を親ウィンドウに通知できます。

SendMessageCallback 関数は、指定されたウィンドウに対応するウィンドウ プロシージャにもメッセージを送信します。 ただし、この関数は直ちにを返します。 ウィンドウ プロシージャがメッセージを処理した後、システムは指定されたコールバック関数を呼び出します。 コールバック関数の詳細については、 SendAsyncProc 関数を参照してください。

場合によっては、システム内のすべての最上位ウィンドウにメッセージを送信することが必要になる場合があります。 たとえば、アプリケーションがシステム時刻を変更する場合は、WM_TIMECHANGE メッセージを送信して、その変更についてすべての最上位ウィンドウ 通知する必要があります。 アプリケーションは、SendMessage を呼び出し、hwnd パラメーターで HWND_TOPMOSTを指定することで、すべての最上位ウィンドウにメッセージを送信できます。 BroadcastSystemMessage 関数を呼び出し、lpdwRecipients パラメーターで BSM_APPLICATIONSを指定することで、すべてのアプリケーションにメッセージをブロードキャストすることもできます。

ウィンドウ プロシージャは 、InSendMessage 関数または InSendMessageEx 関数を使用して、別のスレッドから送信されたメッセージを処理しているかどうかを判断できます。 この機能は、メッセージ処理がメッセージの配信元に依存する場合に便利です。

メッセージ デッドロック

SendMessage 関数を呼び出して別のスレッドにメッセージを送信するスレッドは、メッセージを受信するウィンドウ プロシージャが戻るまで実行を続行できません。 メッセージの処理中に受信側のスレッドが制御を生成する場合、 SendMessage が返されるのを待機しているため、送信スレッドの実行を続行できません。 受信側のスレッドが送信側と同じキューに接続されている場合は、アプリケーションのデッドロックが発生する可能性があります。 (ジャーナル フックはスレッドを同じキューにアタッチします。

受信スレッドは明示的に制御を生成する必要はありません。次のいずれかの関数を呼び出すと、スレッドが暗黙的に制御を生成する可能性があります。

アプリケーションでデッドロックが発生する可能性を回避するには、 SendNotifyMessage 関数または SendMessageTimeout 関数の使用を検討してください。 それ以外の場合、ウィンドウ プロシージャは、受信したメッセージが InSendMessage または InSendMessageEx 関数を呼び出すことによって、別のスレッドによって送信されたかどうかを判断できます。 メッセージの処理中に前の一覧のいずれかの関数を呼び出す前に、ウィンドウ プロシージャは最初 に InSendMessage または InSendMessageEx を呼び出す必要があります。 この関数が TRUE を返す場合、スレッドが制御を生成する関数の前に、ウィンドウ プロシージャで ReplyMessage 関数を呼び出す必要があります。

メッセージのブロードキャスト

各メッセージは、メッセージ識別子と、 wParamlParam の 2 つのパラメーターで構成されます。 メッセージ識別子は、メッセージの目的を指定する一意の値です。 パラメーターはメッセージ固有の追加情報を提供しますが、 wParam パラメーターは通常、メッセージに関する詳細情報を提供する型値です。

メッセージ ブロードキャストは、単にシステム内の複数の受信者にメッセージを送信することです。 アプリケーションからメッセージをブロードキャストするには、 BroadcastSystemMessage 関数を使用して、メッセージの受信者を指定します。 個々の受信者を指定するのではなく、1 つ以上の種類の受信者を指定する必要があります。 これらの種類は、アプリケーション、インストール可能なドライバー、ネットワーク ドライバー、システム レベルのデバイス ドライバーです。 システムは、指定された各型のすべてのメンバーにブロードキャスト メッセージを送信します。

システムは通常、システム レベルのデバイス ドライバーまたは関連コンポーネント内で行われた変更に応じてメッセージをブロードキャストします。 ドライバーまたは関連コンポーネントは、変更を通知するために、アプリケーションやその他のコンポーネントにメッセージをブロードキャストします。 たとえば、ディスク ドライブを担当するコンポーネントは、フロッピー ディスク ドライブのデバイス ドライバーが、ユーザーがドライブにディスクを挿入したときなどのメディアの変更を検出するたびに、メッセージをブロードキャストします。

システムは、システム レベルのデバイス ドライバー、ネットワーク ドライバー、インストール可能なドライバー、アプリケーションの順に受信者にメッセージをブロードキャストします。 つまり、システム レベルのデバイス ドライバーが受信者として選択されている場合、常にメッセージに応答する最初の機会が得られます。 特定の受信者の種類では、他のドライバーの前に特定のメッセージを受信するドライバーは保証されません。 つまり、特定のドライバーを対象としたメッセージには、他のドライバーが意図せずに処理しないように、グローバルに一意のメッセージ識別子が必要です。

SendMessage、SendMessageCallbackSendMessageTimeout、または SendNotifyMessage 関数でHWND_BROADCASTを指定して、すべての最上位ウィンドウにメッセージをブロードキャストすることもできます。

アプリケーションは、最上位ウィンドウのウィンドウ プロシージャを通じてメッセージを受信します。 メッセージは子ウィンドウに送信されません。 サービスは、ウィンドウ プロシージャまたはそのサービス コントロール ハンドラーを介してメッセージを受信できます。

Note

システム レベルのデバイス ドライバーは、関連するシステム レベルの関数を使用してシステム メッセージをブロードキャストします。

メッセージのクエリ

独自のカスタム メッセージを作成し、それらを使用して、アプリケーションとシステム内の他のコンポーネント間のアクティビティを調整できます。 これは、独自のインストール可能なドライバーまたはシステム レベルのデバイス ドライバーを作成した場合に特に便利です。 カスタム メッセージは、ドライバーとドライバーを使用するアプリケーションとの間で情報を伝達できます。

特定のアクションを実行するアクセス許可を受信者にポーリングするには、 クエリ メッセージを使用します。 BroadcastSystemMessage を呼び出すときに dwFlags パラメーターにBSF_QUERY値を設定することで、独自のクエリ メッセージを生成できます。 クエリ メッセージの各受信者は、関数がメッセージを次の受信者に送信するために TRUE を 返す必要があります。 受信者が BROADCAST_QUERY_DENYを返した場合、ブロードキャストはすぐに終了し、関数は 0 を返します。