DispatchMessage呼び出しでブロックする

このQ&Aのポイント
  • Win32APIのDispatchMessageについて質問させてください。ゲームのように自動的に更新描画されるアプリケーションで、メッセージループと同じスレッドで描画処理を行うことを想定しています。
  • 通常の挙動として、ウィンドウメニューを開いたりした場合、DispatchMessageの呼び出しがブロックするようです。(メニューを閉じるまで関数が戻らない)
  • 描画ループとメッセージループを別スレッドで非同期に処理する方法も試しているのですが、「メニューアイテムを選択してもメッセージが来ない現象」(これの条件など詳しくは調査できてないです)が発生したりして、いろいろ悩まされてます。何か情報がありましたら教えてください。
回答を見る
  • ベストアンサー

DispatchMessage呼び出しでブロックする

Win32APIのDispatchMessageについて質問させてください。 ゲームのように自動的に更新描画されるアプリケーションで、メッセージループと同じスレッドで描画処理を行うことを想定しています。 通常の挙動として、ウィンドウメニューを開いたりした場合、DispatchMessageの呼び出しがブロックするようです。(メニューを閉じるまで関数が戻らない) 例えば、Windows付属の「ピンボール」などでも、メニューを開いた瞬間にすべての時が止まります。 このような現象を避けたいのですが、何か良い方法はないでしょうか? 描画ループとメッセージループを別スレッドで非同期に処理する方法も試しているのですが、「メニューアイテムを選択してもメッセージが来ない現象」(これの条件など詳しくは調査できてないです)が発生したりして、いろいろ悩まされてます。 何か情報がありましたら教えてください。よろしくお願いします。 テスト実行の環境はWindows2000です。

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

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

>通常の挙動として、ウィンドウメニューを開いたりした場合、DispatchMessageの呼び出しがブロックするようです。(メニューを閉じるまで関数が戻らない) というかメニューが内部的に独自のメッセージループのような処理をしているのでしょう。 キャプションをドラッグしてウィンドウを移動させている間も同じ感じですよね。 これを回避するにはやはり別スレッドにするしかないと思います。 で、メッセージが来ないというのは、単に描画スレッドが処理を占有してしまってメッセージループのスレッドの処理が行われていないのではと思います。 なので、描画ループの中で、適時Sleep()でスレッドの制御を渡してあげてみたらどうでしょうか?

mojimojio
質問者

お礼

解答ありがとうございます。 >というかメニューが内部的に独自のメッセージループのような処理をしているのでしょう。 なるほど、そういうものなんですね。 ウィンドウ移動中に止まってしまうのも同じく困りモノです。 >で、メッセージが来ないというのは、単に描画スレッドが処理を占有してしまってメッセージループのスレッドの処理が行われていないのではと思います。 これ関しては、そういう理由ではないようです。他のメッセージは処理できているので。 でも、別スレッドでどうにかするしかないようですね。ちょっと調べてみます。

mojimojio
質問者

補足

締め切り遅くなりました。回答ありがとうございました。

関連するQ&A

  • スレッド中でウインドウのイベント(Windows)

    カテゴリー違いかもしれませんが、 Windowsでスレッド中でウインドウを生成すると、 イベントの処理ができなくなります。 (たぶんもとのイベントループにメッセージがいって  そこで終わっていると思うのですが) これを避ける方法とかあるのでしょうか? メインループにメッセージを送ってそこでウインドウを 生成してもらうのが由緒正しい方法なのでしょうか? 用語とかむちゃくちゃかもしれませんが よろしくお願いします。

  • VC++ メインループでのイベント監視方法

    こんにちは。 VC++2008Expressでプログラムをしようと思っている初心者です。 以下、変な疑問があり、お尋ねしたいと思います。 よろしくお願いします。 Windowsアプリケーション Win32API クラスで別スレッドを作成して、そのスレッドからのイベントを WinMainループで受け取る方法ですが 通常皆様はどういう風にするのでしょうか? クラスは、その他のプログラムでも流用可能で様々なアプリに対応しやすいようにしあげたいのですが。。 別スレッドでイベント発生時にWinMainにどのように教えるのが普通のやり方なんでしょうか? 僕の考えでは、WinMain関数内のループ内で常時イベント発生していないか 以下のように監視させるか eventloop el; while(GetMessage(&msg,NULL,0,0)) {   TranslateMessage(&msg);   DispatchMessage(&msg);      if(el::boolEvent){     イベント処理へ   } } とするのが良いか? これだとクラスの関数、変数の使い方さえ分かるようにしておけば流用は簡単 なのかなと思いますが。。 メインのループ内にこんな監視を入れるようなプログラムをみたことないので ナンセンスなのではと思います。 次に考えられるのは、クラスのイベント発生で作成したSendMessageを送って メッセージ処理でイベント処理をさせるのが良いのかなって思いますが これだと、流用するときに対応したMessage(キュー?ですかね)を作成しないといけなく 私的に分かりにくいなーって思います。。。 変なことで悩んで先に進まないのですが、皆様はどのようにコーディングされるのでしょうか? ちなみにイベントというのは、RS232Cで受信があって、そのデータを加工したあとで メモリに格納して格納しましたよってイベントです。 どうかよろしくお願いします。

  • iアプリ、それともJava(?)における文字表示の挙動について

    iアプリ、それともJava(?)における文字表示の挙動について public void run(){  Graphics g = getGraphics();  while(true){   g.lock();   int i = 1;   g.drawString("hogehoge",0,15 + i); //下にずれて表示されていく。   g.unlock(true);   i++;  }//while() }//run() 【質問】 whileループで繰り返し、上記のような処理がなされる場合、 一度表示した文字は残らず、ループの繰り返し毎に、 何も表示されていない所に、1から表示しなおされる形で、 処理が行われています。 例えば、ループなしの簡単なHellow World!のような文字表示サンプルプログラムですと、 そのHellow World!という文字列を1度描画したら、そのまま描画されたままですが、 whileループの場合、 ループごとに、真っ白な状態に初期化され、その上に次の描画が行われ…ということを、 繰り返しているようです。 この時の、「毎回のループの初めに行われているであろう、真っ白な状態への初期化」は、 どういった仕組みで行われているのでしょうか? 別の言い方で言うと、 「whileループの描画処理が、蓄積されていかないのは何故?また、その蓄積がなされない理由(しくみ)はどこに?」 となります。 上記whileループの挙動に対し、 文字と文字が重なっていく、とか、 上段から下段へと文字がどんどん蓄積されながら描画されていく、 なんてことを想定していたわけですが、 実際には、そうはならないため、質問をさせて頂きました。、 このあたりのことについて、どなたか、お分かりになる方、ご教示下さい。 宜しくお願い致します。

    • ベストアンサー
    • Java
  • CPU資源をなるべく消費しないでイベントを待機する

    こんにちは。 VC++2008Exressを使用して、以下のようなプログラムを作成したいと思います。 初心者で、どうやって作成すれば良いのか悩んでおります。 参考になるものなどありましたら、ご教授ください。 Windowsアプリケーション Win32API メッセージループ内でWaitForSingleObjectなどのイベントを待機する関数を使用して イベントを待つようにしたいのですが メッセージループ内でメッセージも待機できイベントも待機できるような方法はないでしょうか? 今のところ、実現はしておりませんが検討しているのは メッセージ待機用のスレッドを作成して、GetMessageで待機して メッセージがきたら、SetEvent関数でメインのメッセージループ内の WaitForSingleObjectを返す。 また、別のメッセージ以外のイベントを監視するスレッドを作成して WaitForSingleObjectで監視してイベントが来たら、さきと同じイベントを SetEvent関数を使用しメインのメッセージループ内のWaitForSingleObjectを返す。 という感じでメッセージとイベントをメッセージループ内で監視するようにするしか 分かりません。 その他、簡単な関数で実現可能なものなどありませんでしょうか? WaitForMultiObjectsとか、MsgWaitForMultiObjectsやら調べてみましたが、いまいち使い方が。。。。 また、スレッドは監視イベントが来るたびに終了させた方がよいのでしょうか? それでは、またスレッド作成を繰り返すので効率悪い気がします。 無限ループで監視させた方が良いのではと思いますが、CPU資源的には・・・。 というようなことで悩んでおります。 どうか、ご教授ください。よろしくお願いします。

  • 物理シミュレーションの可視化(C#)

    C#で物理シミュレーションをしようと考えています。粒子が飛び交う様子をシミュレートし、StartやStopが可能で、粒子のパラメータなどを逐一変更できるようなものにする予定です。 で、シミュレートする部分は大体できたのですが、どのようにして画面に描画するかで悩んでいます。 C#でテトリスを作ったことがあるのですが、Threadで描画(this.Invalidate()の呼び出し)と計算(テトリミノの落下)を無限ループさせるという、かなり強引な手段で作り上げてしまいました。ループの時間間隔の調整はThread.Sleep()で、無限ループの停止、開始は外部からそのThreadをSuspend、Resumeさせることで行っていました。 こんな設計ではどこかでガタがくると思います。C#ではこういう場合、どのようにプログラムするのでしょうか? できることなら、ひな形となるようなコードを拝見したいのですが… 一例として、添付画像のようなプログラムをどのように実装するか、教えていただけますでしょうか。

  • Win32 メッセージループ

    ウィンドウズプログラミングを勉強はじめたばかりなのですが、2つ質問があります。教えてもらえると助かります。 まず、GetMessage関数の第2引数です。 これはメッセージを取得するウィンドウハンドルを指定とありました。NULLを使えばそのスレッドのすべてのメッセージを取得することになると思いますが、NULL以外で実際にウィンドウハンドルを指定するプログラムは一体どういうときなのか知りたいです。 試しにCreateWindow関数でウィンドウを2つ作りをメッセージを取得したいウィンドウハンドルを指定したところ指定しなかった方はメッセージを取得しませんでした、もちろん想定どおりです。しかし、メッセージの取得するウィンドウでサイズなど変更できない場合がありました(取得しないウィンドウをクリックした直後など)これはメッセージキューのメッセージ処理によるものだと(自分の考えなのであってるか不明)思います。結局NULL以外使い道ないんじゃないかとと思ってしまいました。 もう一つの質問です。 ウィンドウプロシージャはコールバック関数であるのでしょうか?システムから呼ばなくてはいけない理由が知りたいです。 これも自分の勝手なよそうですが、DispatchMessage関数が送るメッセージをシステムがどのウィンドウプロシージャを呼び出すのかMSG構造体のウィンドウハンドルを見てさらにWNDCLASSEX構造体などから判断して決めるのをシステムが行うのでコールバック関数なのかな? DispatchMessage関数が直接ウィンドウプロシージャ呼び出さない理由が知りたい。

  • Windowsプログラムでのメッセージループ

    Microsoft Visual C++6.0でWin32ApplicationでWindowsプログラムを作る勉強を始めました。 『Visual C++ 1 はじめてのWindowsプログラミング』(山本信雄 著) という本で勉強しています。 WinMain函數の中に次のような「メッセージループ」というものがあるんですね。 while(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } 本の説明では 「メッセージループとは、GetMessageでメッセージの有無を常に確認しつづけるループです。Windowsプログラムは、何もしていないように見えるときでも常にメッセージループをじっこうしているのです。」 ということです。 また 「もしもメッセージがなければ、GetMessageは他のアプリケーションに処理を讓ります。これによってWindowsのマルチタスクがじつげんされています。」 ともありました。 私が思ったのは、 他のアプリケーションに処理を讓ってしまったら、上の説明にあるような「常にメッセージループをじっこうしている」ことにはならないんではないか、 ということです。 逆に、メッセージがあり續けたら、他のアプリケーションに処理を讓らないのでしょうか。 WindowsのマルチタスクはGetMessageが行っているのではなくて、WindowsというOSが行っているのではないでしょうか。 GetMessageが他のアプリケーションに処理を讓っている間の状態というのは、GetMessage函數がじっこうされている状態なのでしょうか。それとも、その間プログラムは停止しているのでしょうか。停止しているのだとしたら、再開するのはGetMessageの次のTranslateMessageからでしょうか。 編集部に質問を送ったのですが、返事はありません。 初級者ゆえ何か勘違いしているのかもしれません。 よろしくお願いいたします。

  • DLL の中の関数呼び出し

     Windows NT workstation Ver4.0 の上で、ボーランドC++ Ver5 を使って、owl を使ったソフトを作っています。  メーラーを作ろうとして、blatj のソースコードを組み込んでいます。 その中で、gensock.dll を読み込んで、その中の関数を呼び出すところがあるのですが、関数のエイトりーポイントが NULL で返ってきます。  自作した他の DLL については、関数の呼び出しは、 順調なのですが、この gensock.dll については上手くゆかないのです。  そこで、 ボーランドのDLLと、マイクロソフトのDLLでは 呼び出し方にどのような違いがあるのでしょうか?  Win API を使ってみても  TModule を使ってみても 同じような現象が起きています。  解決方法は gensock.dll のソースコード を使ってボーランドのコンパイラでDLLを作り直す以外には無いのでしょうか?

  • invokeLaterの逆に

    私は、SwingUtilities.invokeLater(Runnnable doRun)では、イベントディスパッチ・スレッド以外からの描画を伴うリクエストを、AWT-EventDispatchThreadの実行と同期して実行させるための機構だと理解しています。これは描画を伴う処理を描画のタイミングに集約して効率化する機能です。 では、逆にイベントディスパッチ・スレッドの過程で実行していながらも、描画の変化と直接関係ない処理を、イベントディスパッチ・スレッドの描画サイクルの終了後に後回しで行う方法はないのでしょうか?

  • スレッドの安全な終了のさせ方

    スレッドの安全な終了のさせ方  メインスレッドにてCreateThread命令を使い、あるサブスレッドを作りました。 このサブスレッドは内部でmallocを使い動的に配列領域を確保して その配列領域をforループ等で「かなり時間の掛かる処理」として繰り返し アクセスしています。 ループが終了した時に「free」を実行してmalloc領域を開放しています。 アプリ終了時にメインスレッドからこのサブスレッドを終了させるのに メインウインドウにWM_DESTROYメッセージが送られた時、これまで単に そこで「CloseHandle(hSubThread);」とだけ書いていたのですが、 もしかしたらこれでは場合によっては(サブスレッドがループ処理中だったら) malloc領域が開放されずにリークしてしまうのではないかと思いました。  そこでイベントオブジェクトを使い、サブスレッドがループ処理中の 時には非シグナル状態にして、ループが終了しfreeで領域を開放した後 シグナル状態にするということにして、メインスレッドはそれを WaitForSingleObjectで待つという構造にしました。 ところが「メインスレッドに待ちを作るな」という言葉通り、これでは 上手く行きませんでした。サブスレッドはその時間の掛かる処理の 最中でSendMassage等でメインスレッドの処理を促すような命令を (例えばその処理の進捗状況を表示するなど)を幾つも行っていたので、 もしWaitFor~でメインを待たせると「サブスレッドの処理も進まなくなり 結果両方がロックして動かなくなってしまう」という悲しい状況に 嵌ってしまうのです。 SendMessageを徹底的に無くすということも考えたのですが、 (例えばPostMessageに書き換えるなどもやってみたのですが、これは 全く意図した動作をしてくれない場合もあり)、別の方法では どうしても代替できないケースもあって、全て消すというのは 現実的ではないのかもと。。  このようなサブスレッドを安全に終了させるにはどうしたら良いでしょうか? あるいは単にデストロイ時にCloseHandleとするだけでも良いのでしょうか?

専門家に質問してみよう