hoge diary - October 10, 2009

[プログラミング] ウィンドウ移動中のメッセージループは別物

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() を呼び出したときには内部メッセージループに入ることは知っていましたが、まさかウィンドウの移動やサイズ変更でも内部のループに入ることは知りませんでした。おそらく、別のループに入る条件はほかにもたくさんあるでしょう(あったような気がしますが、思い出せません…)。それを踏まえると、定期的な処理をしたいがためにアプリのメッセージループを使うのは、あまりよい方法ではなく、そういう処理をしたいのであれば、素直にタイマーを使いなさい、ということでしょう。

コメント

名前(何でも可):

テキスト(http:// を含む内容は投稿できません):

トラックバック

トラックバック URI: https://www.pakunet.jp/hoge/trackback/2009101001

トラックバックはありません.


Valid XHTML 1.1! Valid CSS!
© 2004-2009 ぱくちゃん.
Last modified: Sat Oct 10 17:47:26 JST 2009