・第 6 章バックグラウンドで走れ マホラムズ「次は WaitMessage との関係だ」 ■ワタソン「安心したよ」 ■ワタソン「これさえわかれば安心してプログラミングに戻れるぞ ! 」 にワタソン「よーし理解したぞ , ホラムズ。これで全部かい ? 」 ▽ホラムズ「そういう場合はタイマを使うべきだろうね。これなら安心だ」 どうしたらいいのかな ? 」 ■ワタソン「ずっと , バックグラウンドで処理を続けるプログラムを作りたいときは , するのはよくないね」 マホラムズ「そうだ。しかしすべてのメッセージループを , PeekMessage を使って記述 大丈夫みたいだな」 ■ワタソン「わかった。僕のプログラムは , 計算中だけ PeekMessage を使っているから うにしよう」 マホラムズ「だから , PeekMessage がどうしても必要なとき以外は GetMessage を使うよ ■ワタソン「うーん , そうか。パワーマネージメントとは思いもよらなかったなあ」 機構が入っているよ」 節減するモードに切り替えられるんだ。実際に Wind 。 ws3.1 にはこれを行う パソコンを考えてみたまえ。システムがアイドル状態に入れば , 消費電力を マホラムズ「例えば , CPU が 386SL なんかでパワーマネージメント機構の入ったノート 0 ワタソン「え ? なにか特別なことでもあるのかい ? 」 結構重要なんだけどな」 マホラムズ「そうかなあ。システムがアイドル状態に入れるか入れないかというのは , するために使っていてもさ」 なにもないのなら , PeekMessage しているアプリがその時間を PeekMessage ■ワタソン「ああ , そういうことか。それは関係ないじゃないか。だって , やることが マホラムズ「処理すべきメッセージがなにもない状態だろうね」 第ワタソン「アイドル状態ってなんだい ? 」 Wind 。 ws そのものがアイドル状態に入ることができない」 用するときには注意が必要だね。それから PeekMessage を使っていると , WaitMessage はあまり使わない API だと思うけど , これを PeekMessage と併 マホラムズ「キューにメッセージがあるのに W a i tMe s sage は待ち続けるんだ ■ワタソン「どうなるんだい ? 」 きていることを確認した直後に WaitMessage すると少々問題が起こる」 ▽ホラムズ「そう。もし PM_NOREMOVE で PeekMessage して , キューにメッセージが ■ワタソン「 WaitMessage というと , メッセージがくるまで待っている API だね」 マホラムス
。第 6 章 バックグラウンドで走れ しろ副作用みたいなものだからね」 ■ワタソン「ええ ! ? そんな馬鹿な」 ▽ホラムズ「 PeekMessage の第 1 番の目的は , メッセージキューの中を調べることだよ。 そして , GetMessage と違ってメッセージがくるまで待たずにリターンして くれる。これこそが PeekMessage という API の存在する目的さ」 ■ワタソン「でも資料を読んでいたら , ほかのタスクを動かすためには PeekMessage を 使えって書いてあるよ」 マホラムズ「そうだね。でも , ほかのタスクに実行を許す API がどれだけあるか , わか るかい ? 」 「 GetMessage, PeekMessage, WaitMessage の 3 つかな。ああ , それに Yield ■ワタソン もあるね」 マホラムズ「そう。その中で , メッセージがきていてもきていなくても , すぐにリター ンしてくれるのはどれかな ? 」 「 PeekMessage と Yield だけだね」 ■ワタソン マホラムズ「そして , Yield を使うと , 自分のアプリのメッセージキューにメッセージが たまってしまう問題が防げないから , 残るのは PeekMessage というわけだ」 ■ワタソン「あれ , PeekMessage を使えっていうのはそんな理由なの ? 」 「そうだよ」 マホラムズ ■ワタソン「なんだあ。なにかもっと特別なすごい理由があるのかと思ったよ」 0 フィルターい道 ■ワタソン「じゃあ , よくわからない謎その 2 を教えてくれ。受け取るウインドウのハン ドルやメッセージの範囲を制限するための引数があるけど , これって使い道 があるのかな」 マホラムズ「ああ , そのことかそれを使うと , 特定のウインドウの特定のメッセージ だけを調ることカ : できるね」 0 ワタソン「そんなことをしたら , 調べなかったメッセージがどんどんキューにたまっ てしまって , トラブルのもとになると思うんだけど」 マホラムズ「そういう使い方をするときは , ほかのタスクに実行のチャンスをあげる , という用途は忘れることだね」 ■ワタソン「というと , 例えばどんな使い方ができるのかな ? 」 ホラムズ「うーん , 最優先でマウスメッセージを処理したいアプリケーションがあっ たとしよう」 ■ワタソン「最優先 ? 」
まだある注意点朝 0 まだあるラ嶂点 0 ワタソン「ふむふむ」 住ワタソン「ほかに注意点はあるかい ? 」 マホラムズ「それでは , アトランダムに注意点をあげてみよう。まず WM_TIMER メッ セージがある場合だ」 ワタソン「タイマメッセージだね ? 」 マホラムズ「 PM_NOYIELD の指定があっても , 無視されてしまう。タイマメッセー はそれこそ , 時間どおりが命だからしかたがないね」 ■ワタソン「なるほど。まあ , タイマメッセージならしかたがないか」 ン マホラムズ「第 2 引数にウインドウハンドルが指定された場合 , その子ウインドウや孫ウ インドウなども対象に含まれてしまう」 ■ワタソン「なるほど。ウインドウといっても , 子ウインドウを貼りつけて一見ひとつ のウインドウに見えるけど , そうじゃないっていうのもあるからね。いいか もしれない。でも , 子ウインドウじゃなくて , そのウインドウあてのメッセ ージだけを受け取りたいときはどうしたらいいんだろう」 マホラムズ「まず , PM_NOREMOVE の PeekMessage でメッセージを調べる」 。「そして , PeekMessage に引数として渡した MSG 構造体の中の hwnd メンバ ーを調べれば , どのウインドウにあてたものかがすぐにわかる」 ■ワタソン「あ , そんなことができるわけ ? MSG 構造体つてプラックポックスだとば かり思っていたよ」 ▽ホラムズ「中を参照してはいけないという決まりはないよ。で , もし目的のウインド ウあてのメッセージなら , 今度は PM_REMOVE つきの PeekMessage か GetMessage でメッセージを取り出して , これを処理すればいいのさ」 ■ワタソン「なあるほど」 マホラムズ「じゃあ , 次の注意。 PeekMessage を使っていても , WM_PAINT メッセージ は処理されるまではキューから取り除かれない」 「ええ ? それじゃあ PeekMessage ではウインドウの書き直しはできないわ けか ? それは困るなあ」 マホラムズ「そうじゃないよ。処理されるまでは取り除かれないだけさ」 「え ? 違うの ? 」 ホラムズ「 DispatchMessage でウインドウ関数に送って描画してやれば , ちゃんと WM_PAINT はキューからなくなってくれるわけさ。だから , 普通にプログ ラムを書いているときには , 気にしなくて大丈夫だよ」 ■ワタソン ■ワタソン マホラムス
PM NOYIELD の効用 マホラムズ「つまり・・ ■ワタソン マホラムス ■ワタソン ほかのタスクに実行を許す wh ile ( キューがいつばい ) ■ワタソン「ああ , そうだ」 マホラムズ「という形だね ? 」 PostMessage( ・・ 「 PeekMessage じゃないのかい ? 」 する ? 」 マホラムズ「じゃあ , ずばり , ほかのタスクに実行を許すというのは , どの API で実現 ▽ホラムズ「この場合 , キューが空くまでのほんの一瞬でいいんだ。それくらいなら , 自分のアプリケーションのメッセージの処理が遅れてもかまわないだろう ? でもいいんだ」 ■ワタソン「ああ , なあるほど。長い時間遅らせるのではなく , 一瞬待つだけならそれ なら , YieId を使ってもよくないか ? 」 マホラムズ「それはちょっと違うなあ。ほかのタスクに実行チャンスをあげるのは , む ないか。どうやって使うんだい ? 」 なんだろう ? それができないようなオプションがあっても意味がないじゃ ■ワタソン「それも意味不明なんだよ。ほかのタスクに実行チャンスをあげるための API クに切り替えることは許さないという意味のフラグなんだ」 PM_NOYIELD というのは , PeekMessage を行うが , その代わりほかのタス 本来ほかのタスクに制御を明け渡すという意味のある言葉なんだ。つまり マホラムズ「これは , Yield という API と関係があるんじゃない。 Yield という単語は , YieId とどういう関係があるんだい ? 」 「 PeekMessage には PM NOYIELD というフラグがあるんだけど , これは v ホラムズ「なんだい ? 」 ■ワタソン「さっきからずっと資料を見ていて , 疑問に思うことがあるんだけど」 マホラムズ「またなにか考え込んでいるな。どうした ? うまく動かないのか」 OPM_NOYIELD の効用 ちゃんとメッセージを処理したほうがいいね」 こういうのは例外的だね。ほとんどの場合 , PeekMessage を使って ・「でも ,
第 6 章 バックグラウンドで走れ ■ワタソン「 WM_QUIT ? 」 FALSE になるから , 必要ならそれもチェックする必要があるね」 マホラムズ「ただし , 途中で WM ー QUIT メッセージに出合うと GetMessage の戻り値が ワタソン「こう書けばいいのか」 DispatchMessage( &msg ) ; TranslateMessage( &msg ) ; GetMessage( 中略 ) ; if( b ) { b = PeekMessage( 中略 ) ; BOOL b ; MSG msg ; void MessageGaAttaraYare( void ) には , TransIateMessage がセットだから , こう書く」 マホラムズ「つまり , DispatchMessage API を呼び出すということさ。 DispatchMessage ■ワタソン「メッセージを処理するって , どういうことなんだよ」 マホラムズ「これじゃあ , メッセージを取り出しただけで , それを処理していないよ」 GetMessage( 中略 ) ; if( b ) { b = PeekMessage( 中略 ) ; BOOL b ; MSG msg ; void MessageGaAttaraYa 「 e( void ) ■ワタソン「それじゃあ , こうかな ? 」 値で , メッセージがきているかどうかはすぐにわかるよ」 マホラムズ「メッセージがきていたらそれを処理してやらないと。 PeekMessage の戻り
多重呼び出しの問題を マホラムズ「そう。マウスの動きを , なるべく滑らかに追従するようにしたいという目 的かなんかでね」 ワタソン「でも , メッセージは勝手にウインドウ関数に飛んでくるだけだよ。順番な んて変えられるのかい ? 」 マホラムズ「つまり , メッセージを GetMessage で取る前に , PeekMessage でもって待ち 行列の中にマウスメッセージがあるかどうかを調べればいいんだよ」 ■ワタソン「あ ! なるほど。そうか , そういう使い方ができるのか ! 」 マホラムズ「それに , PM_NOYIELD も指定しておけばタスクを切り替えられる恐れも ない。これに目的のウインドウのハンドルも指定すれば完璧だね。あらゆる メッセージの処理に先立って , 指定ウインドウのマウスの動きを優先的に処 理できるわけだ」 ■ワタソン「 PeekMessage って , そんな使い方もできるのか。すごいなあ」 ▽ホラムズ「そのためにいくつかのキーワードが定義されている。 WM_KEYFIRST と WM_KEYLAST はキーボードメッセージの最初と最後。 WM_MOUSEFIRST と WM_MOUSELAST はマウスメッセージの最初と最後のメッセージ番号が 定義されている。これを指定して , 例えばこんな書き方をするわけだ ( リス ト 4 ) 」 PeekMessage ( &msg, hWnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOYIELD ー PM_REMOVE リスト 4 ■ワタソン「奥が深いなあ」 マホラムズ「そう , 奥が深いからこそ , これ以外にも注意しなければならないことは多 いよ」 0 多重呼び出しの問題 ■ワタソン「そのほかに注意しなければならないことって , 例えば ? 」 ▽ホラムズ「うん。例えば , 君のこのプログラムで [ レンダリング ] というメニューを選 ぶと , 計算が始まって PeekMessage を呼び出すようになるよね」
誤解しやすい引数・ マホラムズ「ははあ。わかったぞ」 ■ワタソン「なにがわかったんだい ? 」 「単純なミスをしているよ」 ■ワタソン「え ? どこどこ」 マホラムス ▽ホラムズ ■ワタソン「ほう , よくわかったね。どうしてわかったんだい ? 」 ルを見ながら書いただろう」 v ホラムズ「これはサンプルソースからコピーしてきたんじゃなくて , 自分でマニュア マホラムズ「その前に , PeekMessage がそもそもなんなのかを考えてみようじゃないか。 でも , どうして PeekMessage なんか使う気になったんだい ? 」 ■ワタソン「僕の作ったプログラムは計算に時間がかかるんだ。だけど , その計算中に ほかのプログラムの処理が止まってしまうのは , Windows のマナー違反だろ う ? やつばり , なにかほかのプログラムを使いながら , バックで少しずつ 絵ができていくのを見たかったんだ。資料を調べたら , PeekMessage を呼べ って書いてあったからそうしたんだけど , 僕は間違っているかい ? 」 マホラムズ「いや , そんなことはないよ。そういう場合は , 確かに PeekMessage を使わ なければならない」 ■ワタソン「使い方が間違っているのかい ? 」 マホラムズ「そうだな。まず , 引数の意味を理解しているかだな」 ■ワタソン「自信はないなあ。最初が MSG 構造体へのポインタ。はっきりとした意味は わからないけど , そういう引数を要求しているから渡しているだけなんだ。 2 番目はウインドウのハンドル。これは理解しているよ。 3 番目と 4 番目は受 け取るメッセージの範囲だけど , とりあえず全部が対象だ。そんでもって , 最後が動作のフラグ。メッセージをここで取ってしまうとまずいから , PM ー NOREMOVE というフラグを指定している。どこか , まずいところがあ るかい ? 最初の引数は理解していないから , そのへんが疑わしいな」 マホラムズ「残念。最大の問題は , 2 番目のウインドウハンドルだよ」 ■ワタソン「ええっ ? 僕のプログラムのメインウインドウのハンドルを渡しているん だけど , それじゃあ , まずいの ? 」 ・「 2 番目の引数の意味を , もう一度よく調べてごらん」 ■ワタソン「メッセージを調べるウインドウ・・・・・・」 マホラムズ「そう。ということは , どういうことかな ? 」 ■ワタソン「指定したウインドウにきたメッセージを調べるってことだろう ? 」 v ホラムズ「じゃあ , 指定したウインドウ以外にきたメッセージはどうなるだろうね」 ■ワタソン「ああ ! そうか , わかったぞ。調べてくれないんだ ! 別ウインドウとし て作ったステータスウインドウのボタンをいくら押しても , そのウインドウ
またまたハングする PeekMessage ・ 0 またまたハングする PeekMessage ■ワタソン「ホラムズのうそっき」 v ホラムズ「どうしたんだい ? いったい」 ■ワタソン「また入力が利かなくなっちゃった。うそを教えただろう」 マホラムズ「うそなんか教えていないさ。全部説明しないうちに行ってしまったんじゃ ないか」 ■ワタソン「全部って , まだ問題があったの ? 」 マホラムズ「 5 番目の引数はなんだったつけ」 ■ワタソン「ええと , PM_NOREMOVE だよ」 マホラムズ「そのフラグが指定されていると , キューからメッセージを取らないんだよ ■ワタソン「そうだよ」 ホラムズ「じゃあ , キューの中にメッセージが残ってしまうよね」 第ワタソン「そうとも。だって , メッセージを処理するのは GetMessage のところだか こで処理したらまずいもの」 マホラムズ「でも , 計算が終わるまで GetMessage にはいかないんだろう , このプログラ ムは」 ■ワタソン「え ? そうなの ? 」 マホラムズ「だって , そうじゃないか。君のプログラム , 計算中に PeekMessage を呼び 出してはいるが , GetMessage は呼び出していないよ」 ■ワタソン「あれ ? そうなの ? ? 」 ホラムズ「ああ , そうさ。だから , メッセージはどんどんキューにたまっていくばか りさ」 ■ワタソン「メッセージが全部キューに・ マホラムズ「わかったかい ? 」 0 ワタソン「もしかして , キューにどんどんメッセージがたまってしまったら , いつか はオーバーフローしてしまうよね。オーバーフローしたらどうなるんだろう」 マホラムズ「それ以上 , メッセージが入らなくなる」 第ワタソン「ということは ? 」 マホラムズ「キーを押しても , マウスを動かしても , メッセージがキューに入らないわ けだ。それに , キューに入ったとしても , 君のプログラムはそのメッセージ を取り出そうとしていないから , どうにもならないね」 ■ワタソン「じゃあ , どうしたらいいんだい ? 」 ら ,
第 6 章 バッククラウンドで走れ プログラムだけは , 入力が利かないんだよ。どうしてなのか , その原因がど うんだ。ほかのプログラムは入力できるんだが , PeekMessage をやっている ・ワタソン「あ , そうだ。 PeekMessage を呼ぶと , 入力がまったく利かなくなってしま か相談があったんだろう ? 」 マホラムズ「まあまあ。ちょっと冗談をいっただけじゃないか。それよりも , 私になに ・ワタソン「君は僕のことをそんな人間だと思っていたのか。失敬な」 誌に投稿するのかと思ったよ」 マホラムズ「なんだあ , 僕はてつきり , 女の子の絵を描いて工ッチなパソコンゲーム雑 ラムをずっと組んでいたんだ」 出す , 本格的なコンピュータグラフィックなんだぞ。そのための計算プログ 法だよ。 3 次元の物体に当たっている光を視点から逆に追跡して画像を作り ■ワタソン「怒るぞ , ホラムズ。僕はレイトレーシングの話をしているんだ。光線追跡 うしてもわからないんだ」 マホラムズ「よし。プログラムを見せてみたまえ」 ■ワタソン「すぐにプリントアウトしてくるよ。それはそうと , なあホラムズ・・・ 。僕 たち , ずいぶん長いつき合いだよね」 マホラムズ「なんだい , いきなり ? 」 ■ワタソン「ホラムズは相当コレクションしているんだろ ? ピーさせてくれない ? 」 マホラムズ「・・・・・・」 / ・・ 0 しやすい引数 マホラムズ「まずはソースを見せたまえ」 ■ワタソン「この関数で処理しているんだ ( リスト 1) 」 void MessageGaAttaraYare(void) MSG msg; PeekMessage ( &msg, hWnd, 0 , 0xffff, PM_NOREMOVE リスト 1 女の子の CG を。僕にもコ
バッククラウンドれ 期 ndo Ⅳ s でも , うまく作ればバックグラウンドで処理を実行することができるんだ。でも , そのた めには , PeekMessage というス円を完璧に理解する必要がある。でも , こいつがまた , 一筋瑁で は使えないんだよなあ。使い方を間違えるとハングアップしちゃうこともあるからね。理解するに は僕も骨を折ったよ。でも使い方さえわかれば : 人をあっといわせるプログラムだって作れるよ。 ワタソン談 ②ハングする PeekMessage マホラムズ「最近 , パソコンに向かって没頭しているみたいだったけど , なにかトラブ い ? 」 ■ワタソン「ホラムズ。実は , ちょっと困ったことがあるんだ。相談にのってくれるか ■ワタソン「なんだいそれは ? 」 マホラムズ「 CG か。 MAG フォーマットかい。それとも GIF かな。 JPEG だったら偉い ■ワタソン「そうなんだ。実は CG のプログラムを作っていてね」 ルでも起こったのかい ? 」 の CG とか , 水着の女の子の写真とか , コレクションしたことないのかい ? 」 ホラムズ「 CG の画像データのフォーマットの名前じゃないか。ほら , アニメの主人公