Dec 14, 2005

WM_SETREDRAWのばかばかばかばか、ばかん 涙

ポスト @ 17:12:30 | プログラミング,ATL/WTL

またまたCDialogResizeにやられました…

コントロール内でポップアップ表示をする代わりに、自コントロール内に子ウィンドウを貼り付けてそこに表示する、というロジックを組んでいるのですが、描画は自分自身も子のもすべて自前なので、「その子ウィンドウがvisibleかどうか」で描画コードやリサイズ時の描画パーツ再レイアウトコードを条件分岐させてました。

こういう場合、一般的にはフラグを持つのでしょうけど、「ウィンドウがvisibleかどうか」というWindowsの内部情報と完全に同期するはずの情報をわざわざアプリ側で持つのは冗長です。もちろん、悪意あるアプリが外部からWM_SHOWWINDOWを送りつけるとかされるとアウトですけど、その場合は見た目ももともとおかしくなってしまうので、そこまでは考えなくてもよい、というのが常識的な判断だったはずです。

しかし、そのゆに実装してみたコントロールをCDialogResize含みのダイアログアプリコンテナに貼り付けて、そのダイアログをリサイズしてみたところ、なぜか、子ウィンドウたちのZORDERが崩れてしまいます。

どうしてだろう、と追ってみたのですが、ぬわんと、WM_SIZEが連続して送信されてくる間だけ、子ウィンドウがinvisibleということになってしまっているのです
メッセージループでTRACE dumpさせると、もののみごとに、マウスでダイアログをつかんでる間だけ、invisibleになってます。

WM_SIZEを受けて、レイアウト再配置コードが走るのですが、その際、子ウィンドウが常にinvisible→現在は通常画面→メインのウィンドウ(も子ですけども)を最前面に、という流れになってしまっているようです。
ちょっと特殊な描画なので、各子ウィンドウでは背景消去をしていませんで、よって描画が乱れまくる、と。

あぁ、もしやこれはまたCDialogResizeのせいか!?!? と思い、atlframe.h の中身をチェック。しかし、そこではShowWindow(SW_HIDE)もSetWindowPos(..., SWP_HIDEWINDOW)も呼ばれてません。
仕方なく、そのあたりをすべてステップ実行して、1ステップずつ、Spy++で追ってみたわけですが、…

WM_SETREDRAWをFALSE指定で呼び出すと、トップレベルの親を含めてすべてのウィンドウがinvisibleになってました。涙

ちなみに、WM_SETREDRAWが具体的にどういう動作をするかは、MSDNにもまったく書いてません。

まぁ、リサイズ中のちらつきを抑えるための常套手段には違いないんですけどね、WM_SETREDRAW。

とまれ、OS自らが勝手にinvisibleを仕掛ける可能性がある以上、やはりアプリ側でフラグを持たないとダメなんだなぁ、というのが本日の教訓でした。トホホ

Trackback

No Trackbacks

Track from Your Website

http://blog.izumichan.com/trackback/tb.php?id=118

Comment

No Comments

Post Your Comment


*は入力必須です。E-Mailは公開されません。