PeekMessageとは?キューの扱いについて

このQ&Aのポイント
  • PeekMessageとは、キューに溜まったメッセージを取得するための関数です。
  • PeekMessageを使用すると、キューに溜まったメッセージを取得し、それを後続の処理で利用することができます。
  • また、PeekMessageの引数にPM_REMOVEを指定すると、取得したメッセージをキューから削除することができます。
回答を見る
  • ベストアンサー

PeekMessageについて

確認したいのですが、 MSG msg; while(TRUE) { if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if(msg.message==WM_QUIT) { return (int) msg.wParam; } TranslateMessage(&msg); DispatchMessage(&msg); } else { } } このPeekMessageというものですがキューに溜めているということでいいのでしょうか。 後、 MSG msg; while(TRUE) { if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if(!GetMessage(&msg,NULL,0,0)) { return (int) msg.wParam; } if(msg.message==WM_QUIT) { return (int) msg.wParam; } TranslateMessage(&msg); DispatchMessage(&msg); } else { } } の if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if(!GetMessage(&msg,NULL,0,0)) { return (int) msg.wParam; } はキューから出してGetMessageは待機してるということでいいのでしょか? if(PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)) { if(!GetMessage(&msg,NULL,0,0)) { return (int) msg.wParam; } これはキューの中は出さないで、GetMessageでPeekMessageからのキューを出しているということでいいのでしょか?

  • 79562
  • お礼率68% (164/239)

質問者が選んだベストアンサー

  • ベストアンサー
  • MrBan
  • ベストアンサー率53% (331/615)
回答No.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に渡ることがありません。

79562
質問者

お礼

わかりやすい回答ありがとうございます。メッセージ1が通ることがなく1つ飛ばしてしまうからバグが発生すると言ってもいいのでしょうか。わかりました。何回も説明ありがとうございました。

その他の回答 (2)

  • MrBan
  • ベストアンサー率53% (331/615)
回答No.2

メッセージキューの話で言えば、 ・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から通知されるメッセージが予期せず歯抜けし、おかしな挙動をする可能性があります。(←バグ)

79562
質問者

お礼

回答ありがとうございます。GetMessageで上書きとかいてありますが、 上書きしたらしたで、なぜTranslate&Dispatchされないのでしょうか?GetMessageメッセージでmsgを取得しているのに・・・勉強不足ですみません。

  • MrBan
  • ベストアンサー率53% (331/615)
回答No.1

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は、その際にキューの中身を消すか否かを選択できます。 (つまり、削除せずに中身があるか確認することもできますし、削除してしまうこともできます)

79562
質問者

お礼

わかりやすい説明ありがとうございます。まとめると > はキューから出してGetMessageは待機してるということでいいのでしょか? は、PeekMessageによってキューから取り出してまたGetMessageが待機してキューからまた取り直して前のpeekMessageによって取り出された キューは消されてしまういうことでよろしいのでしょうか?そして msgにGetMessageで渡された値が次のPeekMessageでバグってしまうと言うことでしょうか?なぜバグってしまうのでしょうか?どうかご教授よろしくお願いします。

関連するQ&A

  • メッセージループについて

    while(true) { if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if(msg.message==WM_QUIT) break; DispatchMessage(&msg); if(!GetMessage(&msg,NULL,0,0)) { } } else { } これはpeekMessageがメッセージを取り出してメッセージがあったら if(msg.message==WM_QUIT) break; DispatchMessage(&msg); if(!GetMessage(&msg,NULL,0,0)) を実行して、GetMessage()で待機してもし、メッセージがWM_QUITならGetMessageにWM_QUITのメッセージを渡してメッセージが消えてPeekMessageはメッセージキューがないため、0を返し永遠にelseを繰り返すという認識でよろしいのですか? あと、while(true) { if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if(!GetMessage(&msg,NULL,0,0)) { } if(msg.message==WM_QUIT) break; DispatchMessage(&msg); } else { } if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))がWM_QUITのメッセージで そしてメッセージが消えてGetMessageで待機状態になるということでよろしいのでしょうか?ご教授お願いします。

  • メッセージループ

    while(true) { if(PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)) { if(msg.message==WM_QUIT) break; DispatchMessage(&msg); if(!GetMessage(&msg,NULL,0,0)) { return (int)msg.wParam; } } } else { } このソースで実行して消したら終了しませんでした。 なぜ終了できなかったのでしょうか?

  • 質問なのですが・・・

    while(true) { if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if(msg.message==WM_QUIT) break; DispatchMessage(&msg); } else { if(FAILED(Render(g_pD3DDevice))) DestroyWindow(hWindow); } } でRenderが通らないのですがどうしたら通るようになるのでしょうか。

  • LinuxでDoEvents()同等機能

    Linux初心者です。 2.6-18-at9 Debianで及ばずながらマルチスレッドのプログラムを書いています。 VBにはOSにコントロールを戻すDoEventsという機能があります。 Windows/VC++ではこれと同等機能の関数を使っています: DWORD DoEvents(VOID) { MSG msg; while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ){ if ( msg.message == WM_QUIT ){ return( msg.message ); } TranslateMessage( &msg ); DispatchMessage( &msg ); } return( 0 ); } どなたかの示唆によるもので内容はよく理解していませんが、Windows下ではこれで長年つかえてきました。 Linux-gccで同等の関数は定義できるのでしょうか?。

  • Sleep(1)が1msでもどってこない。

    Sleep(1)が1msでもどってこない。 ゲームのループ処理を作っていまして、 空いている時間をシステムに返すためにSleep(1)を呼んで いるのですが、 while( msg.message != WM_QUIT ) { if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } else { //ゲーム的な処理 //時間があまればSleep() } } といった定番なことをしているのですが、 30FPSで固定されません。 調べてみるとSleep(1)が2msくらいして戻ってきています。 なにかよいアイディアを持っている方がいらっしゃいましたら教えてください。 よろしくお願いします。

  • APIのメッセージループの流れとTranslateMessage

    while(GetMessage(&msg, NULL, 0, 0) > 0){ TranslateMessage(&msg); DispatchMessage(&msg); } もしも「a」が押されたときは、 GetMessageで受け取って TranslateMessageでWM_CHARに変換され DispatchMessageでWM_CHARとしてのメッセージが送られる という流れになるはずです。 けど、実際には一度プロシージャにWM_KEYDOWNが送られます。 TranslateMessageが先にメッセージを変換してるので、WM_KEYDOWNが送られることはありえないと思うのですが、なぜでしょうか。 何か重大な思い違いをしているのでしょうか・・?

  • ウィンドウ内でマウスが乗ると更新が止まります・・

    ウィンドウプロシージャ周りを触っているのですが、  ・ウィンドウにマウスが乗っていつつ、マウスが動いている時  ・キーボードーを押した瞬間 にメインループに処理が回らず 全体の処理が止まってしまいます。 上の問題を解決するには、どうすれば良いでしょうか? ※以下コード ---------------------------------------------- while(TRUE) { if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if(msg.message == WM_QUIT) { break; } else { TranslateMessage(&msg); DispatchMessage(&msg); } } else { // 処理メッセージが無いとき WINDOWPLACEMENT wndpl; GetWindowPlacement(hWnd, &wndpl); if((wndpl.showCmd != SW_HIDE) && (wndpl.showCmd != SW_MINIMIZE) && (wndpl.showCmd != SW_SHOWMINIMIZED) && (wndpl.showCmd != SW_SHOWMINNOACTIVE)) { ... ゲームのような、常時更新が必要なループ処理 ... } } Sleep(1); // 最小化等でフリーズしないため } ---------------------------------------------- //以下メッセージ処理側の一部 case WM_KEYDOWN: if (wParam == VK_ESCAPE) { PostQuitMessage(0); } break; case WM_MOUSEMOVE: return DefWindowProc(hWnd, msg, wParam, lParam); default: return DefWindowProc(hWnd, msg, wParam, lParam); ---------------------------------------------- また、ゲームなどのリアルタイム更新に向いた ウィンドウプロシージャの作り方などの説明サイト等ご存知でしたら そちらも教えて頂けると幸いです。

  • 変数の内容がコロコロ変わる、原因を教えてください。

    VC++2010でプログラムしていますが、下記変数TESTの内容がプログラム実行中にある時点で勝手に変更されてしまいます。もちろんプログラム中に変数TESTを変更する記述は何処にも書いていません。 64bit環境での変数設定の注意点を教えてください。 long TEST=0; long TEST1; char LOOP=1; int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { while(LOOP) { if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) ) { TranslateMessage( &msg );//翻訳する DispatchMessage( &msg );//急送する } TEST1 = 7777777; if(TEST)Beep(3000,100); }//while(LOOP) return msg.wParam; }//WinMain

  • DirectXでのゲーム作り error C2065: 'MsgProc'の解決法

    DirectXについて学びたくなり「15歳から始めるDirectX9 3Dゲームプログラミング」という本を使って勉強しています。 しかしウインドウを作り×ボタンを押したら終了というプログラムの所でエラーがでています。 どうかエラーの原因を教えてください。 #include<windows.h> #include<tchar.h> int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPInst,LPSTR lpCmd, int nCmd){     WNDCLASSEX wc = {sizeof  (WNDCLASSEX),CS_CLASSDC,MsgProc,0L,0L,hInst,NULL,NULL,NULL,NULL,_T("My Window"),NULL};     RegisterClassEx(&wc);     HWND hWnd = CreateWindow(_T("BUTTON"),_T("ウインド名"),WS_OVERLAPPEDWINDOW,100,100,300,300,NULL,NULL,hInst,NULL);     ShowWindow(hWnd,SW_SHOWDEFAULT);     MSG msg;     ZeroMemory(&msg,sizeof(msg));     while(msg.message!=WM_QUIT){         if(PeekMessage(&msg,NULL,0L,0L,PM_REMOVE)){             TranslateMessage(&msg);             DispatchMessage(&msg);         }     }     UnregisterClass(_T("My Window"),hInst);     return 0; } エラー内容は : error C2065: 'MsgProc' : 定義されていない識別子です。 です。 環境は Microsoft Visual Studio 8 Microsoft DirectX SDK (March 2008) で、環境設定はきちんとできていると思います。 どうかお願いします。

  • 別関数に渡す変数のポインタが難しい

    構造体初心者で、ポインタもよく分かっていません。 12, 8 と表示するつもりのソースだけど、実行結果は違っていました。 直してください。 ソースは長いけど、スケルトンに構造体とTextOutを付けたぐらいのものです。 #include <windows.h> struct MYOBJ { int a; int b; }; LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int) { MSG msg; WNDCLASS wc; 投稿できなかったからここを消しました。 wc.lpszClassName = "x"; if(RegisterClass(&wc) == 0)return 0; HWND hWnd = CreateWindow("x","",WS_OVERLAPPEDWINDOW|WS_VISIBLE,0,0,320,240,NULL,NULL,hInst,NULL); while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } void myfunc(struct MYOBJ *obj)//ここが違うかもしれません。 { obj->a += 2; obj->b -= 2; } LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { HDC hDC; PAINTSTRUCT ps; char buf[30]; switch(uMsg) { case WM_CREATE: struct MYOBJ myobj; myobj.a = 10; myobj.b = 10; myfunc(&myobj);//ここが違うかもしれません。 return 0; case WM_PAINT: hDC = BeginPaint(hWnd, &ps); wsprintf(buf, "%d, %d", myobj.a, myobj.b); TextOut(hDC, 0, 0, buf, strlen(buf)); EndPaint(hWnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; default: return DefWindowProc(hWnd, uMsg, wParam, lParam); } return 0; }

専門家に質問してみよう