• 締切済み

WinAPI「MsgWaitForMultipleObjectsについて」

Windowsプログラミング初心者です。 MsgWaitForMultipleObjectsを使ってメッセージ待ちの処理をウェイトさせることでCPUの付加を抑えたいと考えて、以下のような処理を作りました。 4行目のPeekMessageで自分のウィンドウにユーザ定義のメッセージが届いたらループを抜け、届かなかった場合には8行目のMsgWaitForMultipleObjectsで次のメッセージが届くまでスリープしたいと思っています。 01 while(TRUE) 02 { 03 /* hWnd宛てのユーザ定義メッセージの有無を確認 */ 04 if(PeekMessage(msg, hWnd, WM_USER, WM_USER + 10, PM_REMOVE)){ 05 break; /* メッセージがあればwait処理終了 */ 06 } 07 08 if(MsgWaitForMultipleObjects(0, NULL, TRUE, INFINITE, QS_POSTMESSAGE) == -1){ 09 return ICCJZD_NG; 10 } 11 } これを動かすと、メッセージが届いているはずなのにMsgWaitForMultipleObjectsのスリープが解除されず、固まっているウィンドウ上をクリックするとスリープが解除されてユーザ定義のメッセージを受け取ってbreakします。 スリープ時間をINFINITEに設定していますが、これは可能な限りループを抑止したいからです。 ユーザ定義のメッセージが届いたら即MsgWaitForMultipleObjectsのスリープを解除させるにはどうしたらよいのでしょうか?

みんなの回答

  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.1

ヘルプには >スレッドがメッセージキューをチェックする関数を呼び出した後、 >指定した種類の未読の入力がキューの中に存在するときにこの関数を呼び出すと制御が戻りません。 ということなんで、直前に破棄してるのがWM_USER~WM_USER + 10だけだからじゃないんですか? というか、なんで普通にメッセージループみたいにGetMessage使わないの?

freshjive
質問者

お礼

GetMessageよりもMsgWaitForMultipleObjectsのほうが拾うメッセージが少ないと判断したので使用しています。

関連するQ&A

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

    ウィンドウプロシージャ周りを触っているのですが、  ・ウィンドウにマウスが乗っていつつ、マウスが動いている時  ・キーボードーを押した瞬間 にメインループに処理が回らず 全体の処理が止まってしまいます。 上の問題を解決するには、どうすれば良いでしょうか? ※以下コード ---------------------------------------------- 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); ---------------------------------------------- また、ゲームなどのリアルタイム更新に向いた ウィンドウプロシージャの作り方などの説明サイト等ご存知でしたら そちらも教えて頂けると幸いです。

  • 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くらいして戻ってきています。 なにかよいアイディアを持っている方がいらっしゃいましたら教えてください。 よろしくお願いします。

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

    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で待機状態になるということでよろしいのでしょうか?ご教授お願いします。

  • モードレスダイアログのタブ移動

    メインループでメッセージを拾ってモードレスで表示した画面のTabキー制御を行いたいのですが、以下のプログラムでTabキーはコントロール間を移動しますが、移動の順番がタブオーダーと全く違います。 ------------------------------------------------- // メイン ウィンドウを作成して、実行します Form1^ m_form = gcnew Form1(); m_form->Show(); msg.message = WM_CREATE; while (msg.message != WM_QUIT) { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (!IsDialogMessage( (HWND)m_form->Handle.ToPointer(), &msg )) { // メッセージが未処理の場合は処理を行う TranslateMessage(&msg); DispatchMessage(&msg); } } } ------------------------------------------------- m_form->ShowDialog(); にしたり、上記ループを Application::Run(gcnew Form1()); に変更するとちゃんとタブオーダーの順番で移動します。 訳有りで、ループ処理を変えたくはありません。 ネットで調べる限りタブ移動について「IsDialogMessage」を 入れるという疑問はあったのですが、それ以降の動作については 何も書かれていないようです。 上記ループの書き方でタブ移動がうまく行えない場合が あるのでしょうか? どなたかご存知でしたら教えてください

  • コンソールアプリケーションでのWIN32 APIメッセージ処理

    コンソールアプリケーションでのWIN32 APIメッセージ処理 VisualStdio.NET 2005のC++で作成しているコンソールアプリケーションで、 PostMessageでメッセージを送信しているのに、PeekMessageで検出できません。 下のプログラムに誤った点があるのでしょうか? 尚、ウィンドウハンドルの確認部分はパスしますが、 PostMessageとPeekMessageの引数hWndをNULLに置き換えるとメッセージの検出はできるので、 やはり、ウィンドウハンドルに問題があるのかもしれません。 #include <windows.h> #include <stdio.h> void main( void ) {   char OldTitle[1024], NewTitle[1024];   char WindowText[1024], ConsoleTitle[1024];   HWND hWnd;   MSG Msg;   /*** ウィンドウハンドルの取得 ***/   GetConsoleTitle( OldTitle, 1024 );   wsprintf( NewTitle, "%d/%d", GetTickCount(), GetCurrentProcessId());   SetConsoleTitle( NewTitle );   Sleep(40);   hWnd = FindWindow( NULL, NewTitle );   SetConsoleTitle( OldTitle );   /*** ウィンドウハンドルの確認 ***/   GetWindowText( hWnd, WindowText, 1024 );   GetConsoleTitle( ConsoleTitle, 1024 );   if ( strcmp( WindowText, ConsoleTitle ) != 0 ){     printf( "ウィンドウハンドルが不正です" );     return;   }   /*** メッセージの送信と検出 ***/   PostMessage( hWnd, 1050, 0, 0 );   do{     while ( PeekMessage( &Msg, hWnd, 0, 0, PM_REMOVE )){       printf( "メッセージを検出しました" );       return;     }   } while( 1 ); }

  • PeekMessage

    キューにあるメッセージを調べて、その結果で 処理を場合分けしようと思っています。  case 123:   //ここでキューにWM_LBUTTONDOWNがあればそれは消さずに   //PM_NOREMOVEでMyFunc()を実行する。   MSG msg;   PeekMessage(&msg, hWndCap, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_NOREMOVE);   if(msg.message == WM_LBUTTONDOWN) MyFunc();  break; これであってますか? キューにメッセージが2つ以上溜まっていることもあると思うけど そんな時はPeekMessage()でMSG構造体にメッセージを入れたら どうなるんですか? 2つ以上溜まっている場合、1番有効なメッセージがMSG構造体に 格納されて、その後それがSendMessage()されて、2番有効な メッセージがPeekMessage()でMSG構造体に格納 っていうのを繰り返すんですか?

  • ウィンドウハンドルがメッセージ処理ループの後おかしくなる(?)

    下のコードをコンパイルしても、 WinMain KillTimer hr=ERROR_INVALID_WINDOW_HANDLE (0x00000578) というエラーメッセージが出てうまく通りません。 エラーを無視する意味でKillTimerをせずにやってしまえば、特に問題ないのですが、後々問題が出てきても怖いので、直したいです。 メッセージ処理ループの手前でKillTimerを行うと、エラーは出ませんし、 メッセージ処理ループのすぐ後でSetTimerを行うと、SetTimerでエラーが出るので、 ループでおかしくなるのかな、と思いました。 プログラムをシェイプアップしてもエラーがとれませんし、 もしかして根本的な間違いがあるのでしょうか・・・? #include <windows.h> #include <dxerr9.h> #define kWCLASS_NAME "WndClass" // ウィンドウクラス名 #define kWINDOW_NAME "Wnd" // ウィンドウ名 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow ) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInst; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName =NULL; wcex.lpszClassName = kWCLASS_NAME; wcex.hIconSm = NULL; RegisterClassEx(&wcex); /* --- メイン・ウィンドウの作成 --- */ HWND hWnd; hWnd = CreateWindow(kWCLASS_NAME, kWINDOW_NAME, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInst, NULL); /* --- ウィンドウの表示 --- */ ShowWindow( hWnd, SW_SHOWDEFAULT ); UpdateWindow( hWnd ); /* --- タイマのセット --- */ if ( SetTimer( hWnd, 1, 1000, NULL ) == 0 ) // WM_TIMERはWndProcで処理 { DXTRACE_ERR( "WinMain SetTimer", GetLastError() ); return -1; } /* --- メッセージ処理ループ --- */ MSG msg; ZeroMemory( &msg, sizeof( msg ) ); while ( msg.message != WM_QUIT ) // PostQuitMessage()が呼ばれたら終了 { if ( !GetMessage( &msg, NULL, 0, 0 ) ) { msg.message = WM_QUIT; } else { TranslateMessage( &msg ); DispatchMessage( &msg ); } } /* --- タイマの破棄 --- */ if ( KillTimer( hWnd, 1 ) == 0 ) { DXTRACE_ERR( "WinMain KillTimer", GetLastError() ); return -1; } /* --- 終了処理 --- */ // ウィンドウクラスの登録解除 if ( UnregisterClass( kWCLASS_NAME, hInst ) == 0 ) { DXTRACE_ERR( "WinMain UnregisterClass", GetLastError() ); return -1; } return 0; }

  • 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からのキューを出しているということでいいのでしょか?

  • WM_NCLBUTTONUPについて

    タイトルバー上でのマウスボタンのアップを検出したいので、 WM_NCLBUTTONUPメッセージを拾うために、単純に以下のようなコードを書きました。 が、このコードではうまくWM_NCLBUTTONUPメッセージを拾えません。 ウィンドウを最大化しているときは問題なくメッセージを拾えるのですが、 それ以外の時(縮小表示)はメッセージを拾えません。 ただ、WM_NCLBUTTONDOWNは正しく拾うことができました。 ウィンドウが縮小表示になっている時にWM_NCLBUTTONUPを取得する場合には何か特殊な処理が必要なんでしょうか? ご存知の方がいらっしゃったら、よろしくお願いします。 // ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_NCLBUTTONUP: MessageBox(hWnd, "UP", "LBUTTON", MB_OK); return 0; case WM_DESTROY: // ウインドウが破棄されたときの処理 PostQuitMessage(0); return 0; default: // デフォルトの処理 return DefWindowProc(hWnd, message, wParam, lParam); } }

  • 質問なのですが・・・

    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が通らないのですがどうしたら通るようになるのでしょうか。

専門家に質問してみよう