Good-bye ATL
ATL/WTL に依存していた部分を素の C++ で書き直し。これで VC++ Express Edition でも動くかな。
Windows プログラミングを C++ で行う際に面倒なのは、ウィンドウプロシージャに this ポインタを渡すこと。SetWindowLongPtr(), GetWindowLongPtr() を使ってウィンドウハンドルに this ポインタを関連付けるにしても、CreateWindowEx() した時点で WM_MINMAXINFO などいくつかのメッセージが飛んでくるため、それをメンバ関数で処理しようと思うと、結局は一度 this ポインタをグローバルな領域に書いておく必要がある。
ATL では 一度グローバル変数 _Module からたどれるデータ構造にスレッドIDをキーにして this ポインタを書き込んでおいて、後でウィンドウプロシージャを thunk に差し替える という方法を採用している。
あそこまで作りこむのは面倒なので、多少パフォーマンスが落ちるがお手軽なところで手を打っておく。次のような内容の thunk を作成し、これを最初からウィンドウプロシージャとして登録。
IA32 だと scratch register どれか忘れたので、とりあえずスタックに保存して %eax 使用。%eax, %ecx あたりは呼び出された側で値壊して OK だったような気がするけど、資料どこにいったかなぁ…。
2007/12/25 追記
ABI の資料を HDD から発見。eax, ecx, edx は callee 側で破壊して OK ということで、私が書いた thunk は push, pop 命令を消して、その間に挟まれている 8(%esp) を 4(%esp) にすれば良いね。
ABI は今だと SCO のサイトからダウンロードできる。Intel386™ Architecture Processor Supplement Fourth Edition の p.37-38 あたり。
Windows プログラミングを C++ で行う際に面倒なのは、ウィンドウプロシージャに this ポインタを渡すこと。SetWindowLongPtr(), GetWindowLongPtr() を使ってウィンドウハンドルに this ポインタを関連付けるにしても、CreateWindowEx() した時点で WM_MINMAXINFO などいくつかのメッセージが飛んでくるため、それをメンバ関数で処理しようと思うと、結局は一度 this ポインタをグローバルな領域に書いておく必要がある。
ATL では 一度グローバル変数 _Module からたどれるデータ構造にスレッドIDをキーにして this ポインタを書き込んでおいて、後でウィンドウプロシージャを thunk に差し替える という方法を採用している。
あそこまで作りこむのは面倒なので、多少パフォーマンスが落ちるがお手軽なところで手を打っておく。次のような内容の thunk を作成し、これを最初からウィンドウプロシージャとして登録。
- 第一引数に渡ってくるウィンドウハンドル (hWnd) をメンバ変数に保存
- hWnd を this ポインタに差し替え
push %eaxIA32 のコードをハンドアセンブルする気にはなれなかったので、それっぽいコードを書いて GNU as でアセンブルし、出力を逆アセンブルして thunk の雛形に。
movl 8(%esp), %eax ; %eaxをスタックに退避した分だけ +4 ずれてる。
movl %eax, pThis->m_hWnd
pop %eax
movl pThis, 4(%esp)
jmp WndProc
IA32 だと scratch register どれか忘れたので、とりあえずスタックに保存して %eax 使用。%eax, %ecx あたりは呼び出された側で値壊して OK だったような気がするけど、資料どこにいったかなぁ…。
2007/12/25 追記
ABI の資料を HDD から発見。eax, ecx, edx は callee 側で破壊して OK ということで、私が書いた thunk は push, pop 命令を消して、その間に挟まれている 8(%esp) を 4(%esp) にすれば良いね。
ABI は今だと SCO のサイトからダウンロードできる。Intel386™ Architecture Processor Supplement Fourth Edition の p.37-38 あたり。
ラベル: プログラミング

0 件のコメント:
コメントを投稿
この投稿へのリンク:
リンクを作成
<< ホーム