EternalWindows
メッセージ管理 / 応答メッセージキュー

別プロセス(スレッド)によって作成されたウインドウに対してSendMessageを実行した場合、 この関数が制御を返すのは、その別プロセスによってメッセージが処理されてからになることを前節では説明しました。 今回は、このSendMessageが制御を返すタイミングについて、もう少し深く見ていきたいと思います。 まず、受信側がメッセージの処理を終えると、メッセージの戻り値が送信側の応答メッセージキューに格納されます。 SendMessageが制御を返すタイミングは正にこの時であり、 SendMessageの戻り値は受信側が返した戻り値になります。

上記の要点は、SendMessageが制御を返すタイミングというのが、 応答メッセージキューにメッセージが格納されたときであるという点です。 つまり、メッセージの処理を終えてウインドウプロシージャから制御を返さなくても、 SendMessageの呼び出し側スレッドの応答メッセージキューに戻り値を格納さえすれば、 SendMessageは制御を返すわけです。 応答メッセージキューに戻り値を格納するには、ReplyMessageを呼び出します。

BOOL ReplyMessage(
  LRESULT lResult
);

lResultは、メッセージの戻り値を指定します。 この値は、送信側スレッドの応答メッセージキューに格納されることになります。

メッセージの受信側がReplyMessageを呼び出す設計になっていれば、 送信側が呼び出すSendMessageは直ぐに制御が返ることになります。 次に受信側の処理の例を示します。

case WM_APP:
	ReplyMessage(0);
	// 5秒ほど掛かる処理を行う
	return 0;

このメッセージの処理は5秒ほど掛かることになっており、 SendMessageが制御を返すタイミングも本来ならばこれに比例するところです。 しかし、具体的な処理に入る前にReplyMessageを呼び出すことによって、 SendMessageは処理が終わるのを待たずして制御を返すことになります。 ReplyMessageはいわば、メッセージを受信したことを送信側に伝える合図のようなものです。

アプリケーションによっては、外部からウインドウプロシージャに送られてきたメッセージが、 どのような関数で送信されたのかを特定したい場合があるかもしれません。 このような場合は、InSendMessageExを呼び出します。

DWORD InSendMessageEx(
  LPVOID lpReserved
);

lpReservedは、予約されているためNULLを指定します。 戻り値は、次に示す定数の1つ以上の値になります。

定数 意味
ISMEX_NOSEND これが単一で返った場合は、メッセージが送信されていないことを意味する。
ISMEX_SEND メッセージがSendMessageかSendMessageTimeoutで送信されたことを意味する。 ISMEX_REPLIEDが同時に格納されていない場合は、送信側スレッドの処理がブロックされている。
ISMEX_CALLBACK メッセージがSendMessageCallbackで送信されたことを意味する。
ISMEX_NOTIFY メッセージがSendNotifyMessageで送信されたことを意味する。
ISMEX_REPLIED ウインドウプロシージャがメッセージの処理を終えたことを意味する。

次に、InSendMessageExを呼び出す例を示します。

case WM_APP: {
	DWORD dwResult;

	dwResult = InSendMessageEx(NULL);
	if (dwResult != ISMEX_NOSEND && !(dwResult & ISMEX_NOTIFY))
		ReplyMessage(0);
	// 5秒ほど掛かる処理を行う
	return 0;
}

InSendMessageExの戻り値がISMEX_NOSENDではなく、 さらにISMEX_NOTIFYが含まれていない場合は、ReplyMessageを呼び出します。 送信側がSendMessageTimeoutを使用している場合は、ReplyMessageによって制御を返させることができますし、 SendMessageCallbackを使用している場合は、コールバック関数を呼び出せるようにできます。 SendNotifyMessageは、送信メッセージキューにメッセージを格納して直ちに制御を返しますから、 応答メッセージを返す意味はありません。


戻る