- ベストアンサー
PeekMessageとは?キューの扱いについて
- PeekMessageとは、キューに溜まったメッセージを取得するための関数です。
- PeekMessageを使用すると、キューに溜まったメッセージを取得し、それを後続の処理で利用することができます。
- また、PeekMessageの引数にPM_REMOVEを指定すると、取得したメッセージをキューから削除することができます。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
「キューからメッセージを取り出して消える」ってのが分かってないのでしょうか。 もしくは、PeekMessageやGetMessageが、引数のmsgを書き換えるというのが分からないのでしょうか。 基本的に、せっかくGetなりPeekなりでメッセージを取得しても、 TranslateMessage & DispatchMessageにそのデータを渡さなければ意味がありません。 [A]の前の時点でキューに、 メッセージ1 メッセージ2 メッセージ3 と格納されていたとして、PeekMessageでREMOVE成功した[B]の時点では、 メッセージ2 メッセージ3 になります。メッセージ1の情報はmsgに取り出された状態で、キューからはREMOVEされます。 そして、GetMessageに成功した[C]の時点では メッセージ3 になります。メッセージ2の情報はmsgに取り出された状態で、キューからはREMOVEされます。 そして、同時にその前まで[A]でmsgに格納していたメッセージ1の情報は、 GetMessageによって上書きされて失われます。既にキューにもありません。 メッセージ1は一度もTranslateMessage&DispatchMessageに渡されませんでした。 [C]に渡すのはあくまでGetMessageの引数であるmsg(=メッセージ2)であって、 メッセージ1ではありません。メッセージ1はTranslateもDispatchもされずに終わりました。 if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) // <- ここでmsgにメッセージ1を取得(キューから削除) [A] { if(!GetMessage(&msg,NULL,0,0)) // <- ここで、メッセージ1が格納されたmsgにメッセージ2を上書き [B] { return (int) msg.wParam; } if(msg.message==WM_QUIT) { return (int) msg.wParam; } TranslateMessage(&msg); // <- ここで渡しているmsgはメッセージ2 [C] DispatchMessage(&msg); } ゆえに、PeekMessageで取得したmsg(=メッセージ1)はTranslateMessage&DispatchMessageに渡ることがありません。
その他の回答 (2)
- MrBan
- ベストアンサー率53% (331/615)
メッセージキューの話で言えば、 ・GetMessage:成功すれば取り出したメッセージがキューから消えます。 ・PeekMessage(REMOVE):成功すれば取り出したメッセージがキューから消えます。 ・PeekMessage(NOREMOVE):メッセージはキューから消えません。 そして、キューからメッセージが消えた場合、そのメッセージは引数のmsgに入ってます。 (NOREMOVEでない限り、同じものを二回取り出すことはできません) > PeekMessageによってキューから取り出して > またGetMessageが待機してキューからまた取り直して > 前のpeekMessageによって取り出されたキューは消されてしまういうことでよろしいのでしょうか? REMOVEを指定している以上、取り出したメッセージは勿論キューから消えますので、 GetMessageが取り出すのはその次のメッセージになります。 そして、PeekMessageの引数msgに取り出した最初のメッセージは、 何も処理されないまま、GetMessageの引数として上書きされています。 > msgにGetMessageで渡された値が次のPeekMessageでバグってしまうと言うことでしょうか? いいえ。 > なぜバグってしまうのでしょうか? Windowsのルールでは、基本的に、受け取ったメッセージは TranslateMessage(&msg); DispatchMessage(&msg); に渡してあげる必要があります。 PeekMessage(NOREMOVE)であれば、キューからメッセージを捨てないので、 もう一度GetMessageすればそのメッセージが取得でき、Translate&Dispatchが可能ですが、 提示のPeekMessage(REMOVE)の例では、PeekMessageでmsg構造体に格納したデータを、 次のGetMessageで上書きしており、そのmsgはTranslate&Dispatchされません。 したがって、Windows OSから通知されるメッセージが予期せず歯抜けし、おかしな挙動をする可能性があります。(←バグ)
お礼
回答ありがとうございます。GetMessageで上書きとかいてありますが、 上書きしたらしたで、なぜTranslate&Dispatchされないのでしょうか?GetMessageメッセージでmsgを取得しているのに・・・勉強不足ですみません。
- MrBan
- ベストアンサー率53% (331/615)
MSDNを読んでください。 > このPeekMessageというものですがキューに溜めているということでいいのでしょうか。 いいえ。PeekMessageにキューに溜める機能はありません。 PM_REMOVEを指定してますので、キューから取り出してます。 (GetMessageとはブロッキングの有無などが違います) > はキューから出してGetMessageは待機してるということでいいのでしょか? PeekMessageでキュー内からmsgを取り出した場合(PeekMessageが0以外を返す)に、 GetMessageで待機して次のキューを取り出しmsgを上書きしていますので、 最初のPeekMessageで取り出したmsgは処理せずに捨ててます。 (つまり、バグってます) > これはキューの中は出さないで、GetMessageでPeekMessageからのキューを出しているということでいいのでしょか? PeekMessageでキューの中身があれば(この時点ではキューの中身を取り出さず)、GetMessageでその中身を取得しています。 PeekMessage自体は予めキューにメッセージがあるか確認しているだけで、 PeekMessageがキューにメッセージを溜めているわけではありません。 GetMessageもPeekMessageもキューの中身を取り出すためのAPIで、 キューに溜める機能はありません。(通常はシステムが溜めます。自分で溜めるには例えばPostMessage等を使います) GetMessageはキューの中身がなければキューイングされるまで待ちます。 PeekMessageはキューの中身がなければ無かったといって処理を返します。 また、PeekMessageは、その際にキューの中身を消すか否かを選択できます。 (つまり、削除せずに中身があるか確認することもできますし、削除してしまうこともできます)
お礼
わかりやすい説明ありがとうございます。まとめると > はキューから出してGetMessageは待機してるということでいいのでしょか? は、PeekMessageによってキューから取り出してまたGetMessageが待機してキューからまた取り直して前のpeekMessageによって取り出された キューは消されてしまういうことでよろしいのでしょうか?そして msgにGetMessageで渡された値が次のPeekMessageでバグってしまうと言うことでしょうか?なぜバグってしまうのでしょうか?どうかご教授よろしくお願いします。
お礼
わかりやすい回答ありがとうございます。メッセージ1が通ることがなく1つ飛ばしてしまうからバグが発生すると言ってもいいのでしょうか。わかりました。何回も説明ありがとうございました。