[プログラミング] ウィンドウ移動中のメッセージループは別物
MFC や Windows フォームを使わずに、ウィンドウを使うアプリを作るときは、メッセージループが出てきます。でも、このメッセージループで何か処理をしよう、というのは Windows から見たら邪道のようです。
Windows プログラムをスクラッチから書いていたときの話です。
メッセージループが動いている様子を確認するために、PeekMessage() API を使って以下のコードを書きました。
MSG msg;
for (;;)
{
BOOL msg_arrived = ::PeekMessage( &msg, NULL, NULL, NULL, PM_REMOVE );
if ( msg_arrived )
{
if ( msg.message == WM_QUIT )
break;
::TranslateMessage( &msg );
::DispatchMessage( &msg );
}
// メッセージループが動いていることを確認する何かの処理
SomeOperationInEveryMessageLoop();
}
RegisterClassEx, CreateWindow を呼び出してウィンドウを作った後、メッセージループに入り、SomeOperationInEveryMessageLoop() 関数がちゃんと呼ばれていました。
ところが、そのウィンドウのタイトルバーの上でマウスの左ボタンを押したままにすると…、メッセージループ中の SomeOperationInEveryMessageLoop() が呼ばれなくなりました。おや?
「titlebar drag message loop」でググってみると、MSDN のフォーラムがヒットしました。
それによれば、マウスクリックによって Windows 内部のモーダルループに制御が移ってしまうとのこと。なんと。ちなみに下記はその書き込みの引用。
Clicking on the title bar starts a modal message loop inside of windows to allow the user to move the window.
自作のメッセージループが回らない今回の謎は解けましたが…、これで終わるのもなかなかもったいないので、解決法はないものかと、同じキーワードで続けてググってみて、もっともそれらしい解決法を発見。
メッセージループそのものには割り込めないから、タイマーでメッセージを送らせて処理するしかない、ってことです。
DialogBox() や MessageBox() を呼び出したときには内部メッセージループに入ることは知っていましたが、まさかウィンドウの移動やサイズ変更でも内部のループに入ることは知りませんでした。おそらく、別のループに入る条件はほかにもたくさんあるでしょう(あったような気がしますが、思い出せません…)。それを踏まえると、定期的な処理をしたいがためにアプリのメッセージループを使うのは、あまりよい方法ではなく、そういう処理をしたいのであれば、素直にタイマーを使いなさい、ということでしょう。
トラックバック
トラックバック URI: https://www.pakunet.jp/hoge/trackback/2009101001
トラックバックはありません.