最終更新: 2010-07-05T02:44+0900
既存のコード(主に検索ボックス)の切り貼りで、とりあえず機能するものに。
ソース面の難はニンともしがたいが機能面の問題くらいは何とかしたいところ。以下、わかっている問題点。
switch-caseで break忘れというまぬけぶりが原因だった。
フォント(HFONT)の削除漏れも修正した。
ツールチップはリストの上下数ピクセルで出ていた。(役に立たない!でもマウスオーバーでツールチップが出てもうるさいだけなのでそのまま)
他に、WM_PAINTで行っていた処理を、本来あるべき位置である WM_COMMAND(CBN_SELCHANGE)で行うように変更した。
キーボードアクセラレータを有効にするのは難しい。矢印や PageUp/PageDownキーまでが登録されているから、単純に有効にするとアクセラレータにそれらの入力を奪われてリストの操作が行えなくなる。
ドロップダウンリストにフォーカスがあるときでもエディタのキーボードショートカットを有効にした。優先順位は
なぜ一部のキーボードショートカットを無効にするかというと、リストの先頭のアイテムが選択されているときに Homeを押してもリストはこの入力を処理しない(すでに先頭が選択されているから)のだが、リストの選択位置に依存してキーの意味が変わってしまう(リストの先頭を選択↔キャレットを行頭に移動)のは不自然だと思うから。同様のキーをわかっている分だけ無効にした結果が上記リストの 2。モディファイアキーの状態やリストの選択位置を考慮して、もっと多くのキー入力をキーボードショートカットとして渡す余地はある(が、こんなアドホックな対処にこれ以上の手間をかけるのもどうかと)。
追従しないことにむしろ驚いた。ブラウザにできてテキストエディタにできないはずがない。
ファイル名も与えられていた場合は、それを上書き保存先にしてくれると尚良し。長めの出力をコマンドプロントからエディタに流して読んだりできる。
svn diff hoge.rb | sakura --stdin "hoge.rb.diff"
Set/GetWindowLongPtr(hwnd, GWLP_USERDATA, ) の代わりに Set/Get/RemoveProp(hwnd, TEXT("MyData"), ) を使うようにした。
参考> http://hilbert.elcom.nitech.ac.jp/~taki/program.html
以下のものを見つけた。
答え。GWLP_USERDATAはウィンドウに属し、その領域は WNDCLASSEX.cbWndExtraの値に従って確保される。
いったいどこを読み書きしていたんだろう? クラッシュしなかったのは Windowsが俺みたいなうっかりもののために余白を空けていたから?
言い訳。msdnのこの記述は非常に誤解を招きやすいと思う。予め 32ビットだけメモリが確保されてると勘違いしても仕方ないじゃない?
GWLP_USERDATA | ウィンドウに関連付けられた 32 ビット値を取得します。この 32 ビット値は、ウィンドウを作成したアプリケーションで使用する目的で各ウィンドウが持っているものです。この値の初期値は 0 です。
現状の理解で、この「32 ビット値」の出所は、読み書き(Get/Set)の単位が 4バイトだというところから。LONG=32ビットだから。
ここで、LONG_PTRが 64ビットのとき、GetWindowLongPtr(,GWLP_USERDATA)は 64ビット値を取得するのでは?ドキュメントあってる?という新たな疑問。
GWLP_USERDATAのように汎用的な場所から取得した値を恐る恐る CMainToolbar* にキャストするより、特別な名前をつけた場所に保存した値をキャストする方がまだ安心できる、という理由で改訂した。
ありふれた課題のようで GWLP_USERDATA を検索するだけで似たような話が見つかる。最初にリンクを張ったページは理解しやすかったが ATLのは難しい。これから読む > WTL/ATLのメッセージマップ実現のしくみ
GWLP_USERDATAと WNDCLASSEX.cbWndExtraが別物の可能性。
別物。GWLP_USERDATAは負のオフセット(-21)。cbWndExtraで確保した領域には 0から始まるオフセット(バイト単位)でアクセスする。
GWLP_USERDATAの有効な領域はポインタのサイズに関係なく、ドキュメント通りの 32ビットなのかについては winuser.hを見てもよくわからない。GWLP?_USERDATA(-21)から GWL_EXSTYLE(-20)まで差が 1しかないし……。GWLP?_* というのはオフセットでなく特別扱いされる値で、Windowsのソースを見ないと何もわからない、ということ? GWLP_USERDATAにポインタを格納できるのとできないのの差は大きいからハッキリ 64ビットサイズだと知りたい。
/* * Window field offsets for GetWindowLong() */ #define GWL_WNDPROC (-4) #define GWL_HINSTANCE (-6) #define GWL_HWNDPARENT (-8) #define GWL_STYLE (-16) #define GWL_EXSTYLE (-20) #define GWL_USERDATA (-21) #define GWL_ID (-12) #ifdef _WIN64 #undef GWL_WNDPROC #undef GWL_HINSTANCE #undef GWL_HWNDPARENT #undef GWL_USERDATA #endif /* _WIN64 */ #define GWLP_WNDPROC (-4) #define GWLP_HINSTANCE (-6) #define GWLP_HWNDPARENT (-8) #define GWLP_USERDATA (-21) #define GWLP_ID (-12)
// まだファイルタイプは取得できないっぽい。常に基本(0)になる。 //::SendMessageAny( m_hwndFileTypeBox, CB_SETCURSEL, m_pOwner->GetDocument().m_cDocType.GetDocumentType().GetIndex()+1, 0 ); ::SendMessageAny( m_hwndFileTypeBox, CB_SETCURSEL, 0, 0 );
とコメントアウトしていた部分を復活させて
::SendMessageAny( m_hwndFileTypeBox, CB_SETCURSEL, m_pOwner->GetDocument().m_cDocType.GetDocumentType().GetIndex(), 0 );
ちょっと修正した(謎の+1を取り除いた)だけ。
アプリケーションの起動と同時にツールバーが作成されるときであれば、コメントの内容は正しい。アプリケーションが起動してファイルが読み込まれた後でツールバーが表示する設定に変更されたとき(このときもツールバーが作成される)は、そうではなかった。