/ 最近 .rdf 追記 編集 設定 本棚

脳log[20220212]



2022年02月12日 (土) GetWindowLongPtr 関数の第二引数(nIndex)について不思議に思った。これはウィンドウごとに割り当てられた値を取得する 0 を起点としたオフセット値だという。正の値はウィンドウクラスで指定して確保させた余分なバイトサイズ分だけ有効。マイナスはポインタサイズだけ有効。その他に Windows が内部で利用するために確保している領域もあり、それらのオフセットは GWLP_XXX として定義されている。GWLP_WNDPROC(-4)/GWLP_HINSTANCE(-6)/GWLP_HWNDPARENT(-8)/GWLP_ID(-12)/GWL_STYLE(-16)/GWL_EXSTYLE(-20)/GWLP_USERDATA(-21)。■第一の疑問。オフセット値はバイト単位なの? たとえば 6 バイト余分に確保させたとして、有効な正の範囲は 0-5 になると書いてあるけど、5 を指定して返ってくるポインタサイズの整数(LONG_PTR。32ビット/64ビット)の中身はどういうものになるのか。有効な値は 1 バイト分だけで残りはこちらのあずかり知らぬゴミになるのかどうか。■第二の疑問。これも同じ。オフセット値がバイト単位だとして、予め定義された定数が必ずしも 4 バイト単位でなく半端な値なのはどういうことか。GWLP_WNDPROC(-4) と GWLP_HINSTANCE(-6) と GWLP_HWNDPARENT(-8) で返ってくる値は 2 バイトずつオーバーラップしているのではないか。GWLP_HINSTANCE(-6) の肩身の狭さよ。GWL_EXSTYLE(-20) と GWLP_USERDATA(-21) も 1 しか違わない。GWLP_USERDATA(-21) から始まる 32ビット/64ビット がプログラマに開放されているなら、GWL_EXSTYLE(-20) のための領域はどこにあるのか。■第三の疑問も同じ。単位がバイト単位だとして、GWL_XXX という GWLP_XXX の下位非互換定数が #ifdef _WIN64 という分岐によって #undef されているのに対して、GWLP_XXX 定数が _WIN64 によらず概ね 4 バイト単位の単一定義なのはなぜか。GWLP_WNDPROC(-4) を -8 と定義しないでもいいのはどういう理屈か。■第四の疑問。マイナスの値はポインタサイズ分だけ有効と書いてあるけど、そのあたりの値は GWLP_WNDPROC(-4)/GWLP_HINSTANCE(-6)/GWLP_HWNDPARENT(-8) によって予約されているように見える。だとすれば、「有効なオフセットは 0 以上でウィンドウクラスで指定した cbWndExtra のサイズ分だけ有効。それ以外の値を取得するにはオフセットとして以下の定数を……」と書けばいい話で、あえて「負の値はポインタサイズだけ有効。それ以外の値を取得するには……」と負の値を括り出す理由はないように思える。■1つ2つの勘違いがないと説明がつかないように思う。どこを間違えている? GetWindowLongPtr のソースコードを読ませてくれ。■SetWindowLongPtr(hwnd, 0, 0x0123456789ABCDEF) と SetWindowLongPtr(hwnd, GWLP_USERDATA, 0x0123456789ABCDEF) した結果がどう読み取られるかを cbWndExtra とオフセットを変えて調べてみた。cbWndExtra7.png, cbWndExtra8.png, cbWndExtra9.png cbWndExtra16.png。オフセット値は 1 バイト単位であり、取得できる値はオーバーラップしている。ただし LONG_PTR サイズの読み取り枠が cbWndExtra のサイズ内に収まっていなければいけない。64ビット環境の場合はつまり、cbWndExtra が 8 未満の時に値の設定と取得はできない(0 が返ってくる)。8 バイトを確保しているときはオフセットとして 0 のみが有効。GWLP_WNDPROC(-4) と GWLP_HINSTANCE(-6) は 2 バイト(0x14a0) を除いて値が共通しているが共通部分の値がシフトしているわけではない。GWLP_USERDATA(-21) の値(8 バイト)がどこに保存されているのか謎。cbWndExtra の使い方はわかったけど既定のオフセットの意味はやっぱりわからない。負値はオフセット扱いじゃないんかな。じゃあ負のオフセットは LONG_PTR サイズまで有効とか書くなって話なんだけど。■わかった!!!Valid values are in the range zero through the number of bytes of extra window memory, minus the size of a LONG_PTR」を読み間違えていた。有効な値は 0 から cbWndExtra までと 0 からマイナスポインタサイズまでではなく、0 から「cbWndExtra マイナス ポインタサイズ」までだった。えええええ、そこにカンマを入れる? そしてカンマひとつでここまで勘違いをひきずるか>自分。■オンラインでは見つけられなかったけど PC 内に日本語訳を見つけた。「nIndex 取得する値に 0 から始まるオフセットを指定します。有効なオフセットは、0 から拡張ウィンドウメモリのバイト数 -8 までです。たとえば、拡張メモリが 24 バイト以上ある場合、16 を指定すると、3 番目の整数値が取得できます。その他の値を取得するときは、次のいずれかの値を指定します。 」 具体例まで追加していい仕事してますよ。見つからんかったけど。