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

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

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

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

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

Windows メッセージ

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

システムは、ウィンドウ ハンドル、メッセージ識別子、およびメッセージ パラメーター と呼ばれる 2 つの値の 4 つのパラメーターのセットを使用して、ウィンドウ プロシージャにメッセージ を送信します。 ウィンドウ ハンドルは 、メッセージの目的のウィンドウを識別します。 システムは、メッセージを受信するウィンドウ プロシージャを決定するために使用します。

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

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

メッセージ型

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

System-Defined メッセージ

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

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

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

Prefix メッセージ カテゴリ ドキュメント
ABM と ABN アプリケーション デスクトップ ツール バー シェルのメッセージと通知
ACMACN アニメーション コントロール アニメーション コントロール メッセージとアニメーション コントロール通知
BCM、BCN、BM、およびBN Button コントロール ボタン コントロールのメッセージボタン コントロールの通知
CBCBN ComboBox コントロール ComboBox コントロール メッセージと ComboBox コントロール通知
CBEMCBEN ComboBoxEx コントロール ComboBoxEx メッセージComboBoxEx 通知
Ccm 一般的な制御 メッセージの制御
CDM [共通] ダイアログ ボックス ダイアログ ボックスの共通メッセージ
Dfm 既定のコンテキスト メニュー シェルのメッセージと通知
DL リスト ボックスをドラッグする リスト ボックスの通知をドラッグする
DM 既定のプッシュ ボタン コントロール ダイアログ ボックスのメッセージ
DTMDTN 日付と時刻の選択コントロール 日付と時刻の選択メッセージと日付と時刻の選択通知
EMEN 編集コントロール コントロールメッセージの編集コントロール通知の編集リッチエディットメッセージリッチエディット通知
Hdm および hdm ヘッダーコントロール ヘッダーコントロールメッセージヘッダーコントロールの通知
HKM ホットキーコントロール ホットキー制御メッセージ
IPM および ipn IP アドレス コントロール Ip アドレスのメッセージIp アドレスの通知
LBLBN リスト ボックス コントロール リストボックスのメッセージリストボックスの通知
LM SysLink コントロール SysLink 制御メッセージ
LVMLVN リストビューコントロール リストビューのメッセージリストビューの通知
Mcmmcn 月間予定表コントロール 月間予定表のメッセージ月の予定表の通知
PBM (PBM) 進行状況バー 進行状況バーのメッセージ
PGM および pgn ページャーコントロール ページャーコントロールメッセージページャーコントロールの通知
PSM および psn プロパティシート プロパティシートのメッセージプロパティシートの通知
RBrbn Rebar コントロール Rebar コントロールのメッセージRebar コントロールの通知
SBSBN ステータスバーウィンドウ ステータスバーのメッセージステータスバーの通知
SBM スクロール バー コントロール スクロールバーのメッセージ
SMC シェルメニュー シェルのメッセージと通知
STMstn スタティックコントロール 静的コントロールメッセージ静的コントロール通知
TBTBN ツール バー ツールバーコントロールのメッセージツールバーコントロールの通知
TbmTRBN Trackbar コントロール Trackbar コントロールのメッセージTrackbar コントロールの通知
TCMtcn タブ コントロール タブコントロールメッセージタブコントロールの通知
Tdmtdm タスクダイアログ タスクダイアログのメッセージタスクダイアログの通知
TtmTTN ツールヒントコントロール ツールヒントコントロールメッセージツールヒントコントロールの通知
TvmTVN ツリービューコントロール ツリービューのメッセージツリービューの通知
UdmUDN アップダウンコントロール アップダウンメッセージアップダウン通知
WM 全般
クリップボードメッセージ
クリップボードの通知
共通ダイアログボックス通知
カーソル通知
データコピーメッセージ
デスクトップウィンドウマネージャーメッセージ
[
デバイス管理メッセージ
[] ダイアログボックスの通知](/windows/desktop/dlgbox/dialog-box-notifications)
動的データ交換メッセージ
動的データ交換通知
フック
の通知
-
キーボード
入力通知
の通知
-
警告
マウス入力
通知
複数ドキュメントインターフェイスメッセージ
-
未加工入力
通知
スクロールバー通知
-
タイマー通知
ウィンドウメッセージ
ウィンドウ通知

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

Application-Defined メッセージ

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

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

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

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

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

メッセージキューに送信されるメッセージは、 キューに置か れたメッセージと呼ばれます。 これらは主に、 wm _ MOUSEMOVEwm _ lbuttondownwm _ KEYDOWNwm _ CHAR メッセージなど、マウスまたはキーボードを使用して入力したユーザー入力の結果です。 その他のキューに置かれたメッセージには、タイマー、ペイント、終了メッセージ ( wm _ タイマーWm _ ペイント、および wm _ quit) が含まれます。 ウィンドウプロシージャに直接送信されるその他のほとんどのメッセージは、 キューに登録 されていないメッセージと呼ばれます。

キューに置かれたメッセージ

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

システムは、各 GUI スレッドに対して1つのシステムメッセージキューと1つのスレッド固有のメッセージキューを保持します。 非 GUI スレッドのメッセージキューを作成するオーバーヘッドを回避するために、メッセージキューを使用せずに、すべてのスレッドが最初に作成されます。 スレッドが特定のユーザー関数の1つに最初に呼び出しを行った場合にのみ、スレッド固有のメッセージキューが作成されます。GUI 関数の呼び出しによって、メッセージキューが作成されることはありません。

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

Wm _ ペイントメッセージ、 wm _ タイマーメッセージ、および wm _ QUITメッセージを除き、システムは常にメッセージキューの最後にメッセージをポストします。 これにより、ウィンドウが入力メッセージを適切な先入れ先出し (FIFO) シーケンスで確実に受信できるようになります。 ただし、 wm _ ペイント メッセージ、 wm _ タイマー メッセージ、および wm _ 終了 メッセージはキューに保持され、キューに他のメッセージが含まれていない場合にのみ、ウィンドウプロシージャに転送されます。 また、同じウィンドウに対して複数の wm _ ペイント メッセージが1つの wm _ ペイント メッセージに結合され、クライアント領域のすべての無効な部分が1つの領域に統合されます。 WM _ ペイント メッセージを組み合わせると、ウィンドウがクライアント領域のコンテンツを再描画する回数が減少します。

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

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

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

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

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

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

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

キューに登録されていないメッセージを送信する関数には、 BroadcastSystemMessageBroadcastSystemMessageExSendMessageSendmessagetimeout、および sendmessagetimeoutがあります。

メッセージの処理

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

メッセージループ

単純なメッセージループは、 GetMessageTranslateMessageDispatchMessageという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 _ KEYDOWNwm _ KEYUP) が生成されます。 仮想キーメッセージには、押されたキーを識別する仮想キーコードが含まれていますが、その文字値は使用されません。 この値を取得するには、メッセージループに TranslateMessage が含まれている必要があります。これにより、仮想キーメッセージが文字メッセージ (WM _ CHAR) に変換され、アプリケーションメッセージキューに戻されます。 次に、メッセージループの後続のイテレーション時に文字メッセージを削除し、ウィンドウプロシージャにディスパッチできます。

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

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

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

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

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

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

ウィンドウプロシージャ

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

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

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

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

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

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

Wm _ keyfirst 定数および wm _ keyfirst 定数は、すべてのキーボードメッセージを取得するためのフィルター値として使用できます。すべてのマウスメッセージを取得するには、 wm _ mousefirst 定数と wm _ mouseselast 定数を使用できます。

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

メッセージの送信と送信

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

メッセージの送信

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

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

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

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

sending messages

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

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

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

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

メッセージのデッドロック

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

受信スレッドはコントロールを明示的に生成する必要がないことに注意してください。次の関数のいずれかを呼び出すと、スレッドによってコントロールが暗黙的に生成される可能性があります。

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

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

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

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

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

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

SendMessageSendMessageCallbackSendmessagetimeout、または sendmessagetimeout関数で HWND _ ブロードキャスト を指定することにより、すべてのトップレベルウィンドウにメッセージをブロードキャストすることもできます。

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

注意

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

クエリメッセージ

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

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