2003/04/01

おバカさん

エイプリルフール? なんすか、それ食いもんっすか?

というわけで特にネタを用意しませんでした。いや、用意はしたんですけど、したんですけど、私がおバカさんでした。

3月中旬に「今年のエイプリルフールは何しましょうかね」と考えた結果、4/01→401→401認証エラーだなぁという短絡的発想の元、4/01にトップページにいきなりBasic認証をかけて401エラーを吐かせてそこでネタばらしと行こうと思って早速実験。

あれー、ちゃんと401エラー用のHTMLを設定したのに認証エラー時のHTMLがApacheのデフォルトの無機質なメッセージだなぁ。

……はっ。トップページに認証かける→当然エラー用HTMLのあるディレクトリにも認証がかかる→認証エラー時用HTMLを読み込むのに認証が必要→卵が先か鶏が先か?(それは違う)というわけで、トップページに認証をかけてエラー用HTMLを吐かせるのは無理である、と。バカだなぁ、オレ。

というわけで、今日は特にどうとかすることもなく普通に更新しました。

今日もTaskTrap

VisualStyle時代のオーナードローメニュー

ふと、とりあえずアイコンメニューでもやろうか、ということでオーナードローでうねうねと作業。

で、WindowsXPで好きなVisualStyleを使っていて、さらに選択範囲の色とかをカスタマイズしてる人の場合、従来の(VisualStyleを考慮していない)実装だとこんな感じのメニューになるわけですよ。

オーナードローメニューがVisualStyleを考慮していない

ほーら、アイコンつきの選択されたメニューアイテムの描画方法が、ポップアップしてる方のWindowsが描画した標準スタイルのメニューの選択部分と違うわけですよ。

このVisualStyleに伴うメニューの描画方式の変更はWindowsXPからなので、WindowsXP登場以前のアプリケーションはこうなっても仕方ないですが、さすがにWindowsXP登場以降のアプリケーションなのにVisualStyleに対応してないのは恥ずかしいものです(といいつつ、世の中はオンラインソフトからパッケージソフトまでオーナードローメニューがほとんどVisualStyleに対応されてないわけですが)。というわけで、TaskTrapはそんな恥ずかしいことをしていられないので(っていうか、これに気がつかない開発者は気にしないんだろうけど、Windowsの標準インターフェースを踏襲したものにこだわる人はとことんこだわりますよね)、Webでそれ系の情報をあさってみたんですが、特に引っかからないので自力でやってみることに。

といっても、要は色の指定さえ間違えなければいいんですね。VisualStyle非対応が問題になるのはメニューが選択状態になったときのみなので、選択状態になったときにどう描画すればいいかと書いておきます。

  1. まずは、メニューの描画範囲の背景をGetSysColor(COLOR_MENUHILIGHT)の色で塗りつぶします(ってか、FillRectでGetSysColorBrush(COLOR_MENUHILIGHT)を呼べばOK)
  2. つぎに、アイコンを書き込んだりテキストを書き込んだり(テキストの色はGetSysColor(COLOR_HIGHLIGHTTEXT)です)
  3. 最後に、メニューの描画範囲のふちをGetSysColor(COLOR_HIGHLIGHT)色、solid、1pxのペンでくるっと囲めばOK

という感じで描画するわけですが、COLOR_MENUHILIGHTはWINVERが0x0501以降でのみ定義されてるんで、WindowsXP以外でそれを使ってもNULL(というか、黒)が返ってきます。で、このVisualStyleを使っているかどうかはuxtheme.dllの BOOL IsThemeActive(void) という関数で判別できるんで、LoadLibrary("uxtheme.dll")してNULLだったら(WindowsXPではないので)従来の描画、GetAddressProc(hUxthemeLib, "IsThemeActive")してその関数の実行結果が真であればVisualStyle描画、偽であれば従来の描画、という感じでわけるとOKです。

で、そういう処理をやった結果がこれ。

VisualStyleに対応した選択メニューの描画

はい、オーナードローメニューながらWindows標準のメニューと同じ描画になってますよね。

というわけで、「オレはVisualStyleなメニューじゃないと満足しない」「とりあえず流行の先っぽに乗っておきたい」「っていうかオレがVisualStyle」というような人はこれを実装してみてはどうでしょうか。

なお、多くのVisualStyleではMenuHilightとHighlightがデフォルトで同じ色に設定されているものがほとんどでして、そのへん、WindowsXPのVisualStyleがメニューの選択範囲についてMenuHilightを背景色に、Highlightを選択範囲のボーダーにしてることに気がつかないようになっています。というよりも、これは過去のアプリケーションのオーナードローとの差異を見せないための配慮なのかもしれません。

ちなみに、VisualStyleを使っていても画面のプロパティから[デザイン]→[詳細]で選択範囲の色を決められるので、ここで選択範囲の背景色を設定すると、Highlightにその色が入るようになってまして、MenuHilightとHighlightの色が違ってくると上のスクリーンショットのように非対応アプリケーションでは差が出てくる、というわけです。

WindowsXPのVisualStyleとしては、メニュー及びメニューバーの選択部分は「背景をMenuHilight、文字をHighlightText、ふちどりをHighlight」とするのが標準(e.g. メモ帳)であり、Windows Explorer(とIE)はメニューバーの選択部分のオーナードローだけがVisualStyle非対応とかいう手抜きっぷりです。というか、よくよく見るとWindows Shellだからってきっちり統一されてないんですね。たとえば、

新規作成メニューは選択項目文字色が違う

このように、新規作成メニュー(送るメニューも)では選択文字色が普通のメニューのテキスト色になってる、とか。

Operaの謎

TaskTrapでアイコンメニューを実現するということで、ウィンドウハンドルからアイコンを得る必要があるんですよ。で、その実現方法は、

  • SendMessageでWM_GETICONを送りつける
  • GetClassLongでGCL_HICONSMを得る

という2つの方法があって、前者はWM_SETICONで設定したアイコンしか取れないので、とりあえず前者を試してみて取れなかったら後者で取る、というのが一般的のようです。

で、やってみたんですが、どうしても取れないアイコンがあるんです。それは、Opera。どうもウィンドウクラスを作るときにOperaはhIconSmallを設定してないようなんですよ。これはこまった。で、TaskTrapの(すでにアイコンメニューを実現してる)競合ソフトでOperaのアイコンが取れているのかを調べてみると、やっぱり取れてないみたいです(ちなみにそのソフトのアイコンメニューはVisualStyle非対応でした)。

なーんだ、じゃ、取れなくても仕方がないや。……って、やはりあきらめるわけにはいかんのですよ。どうしても取りたいわけですよ。ということで、ウィンドウハンドルからごにょごにょして実行ファイルのフルパスを取得して(すげー面倒)、そこからSHGetFileInfoでゲットしてみると、取れました。まぁ、取れて当たり前ですが。まぁ、そもそもOperaが悪いんだ、といいたいところですがどーせhIconSmallを設定していないソフトが他にもありそうなのでとりあえず対処、と。

……なにげにタスクバーのアイコンもフルパスがわかったので(Explorer.exe)も取れたりして、まぁよかったかなぁ、と。

うされもん @acidlemonについて

|'-')/ acidlemonです。鎌倉市在住で、鎌倉で働く普通のITエンジニアです。

30年弱住んだ北海道を離れ、鎌倉でまったりぽわぽわしています。

外部サイト情報

  • twitter
  • github
  • facebook
  • instagram
  • work on kayac