お久しぶりのWIN32ですw。
とあるプログラムで、ウィンドウハンドルをサブクラス化してたんですな。
サブクラスといっても、オブジェクト指向的な用語ではなく、Windows独特なので、知らない人も多いかもw
ウィンドウのメッセージを処理するプロシージャを置き換えて別の挙動をさせたいときに使うワザとでもいいましょうか。
こんな実装です。
WNDPROC oldProc = ::GetWindowLong( WinHandle, GWL_WNDPROC );
::SetWindowLong( WinHandle, GWL_WNDPROC, (WNDPROC)&MyProc );
その後、GetWindowLongPtr とか SetWindowLongPtr を使いましょうなどという別名みたいな推奨があったんですが、キャストが少なくなる程度でそれほど便利だとは思ってませんでした。 br>
自前のプロシージャでは、自分が処理するメッセージ以外を元のウィンドウに処理させます。
LRESULT CALLBACK MyProc( HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
if(Msg==自前処理)
{
return foo();
}
return ::CallWindowProc( oldProc, Wnd, Msg, wParam lParam );
}
こんな具合です。
処理が必要なくなったときは、同様に SetWindowLong を使って、ウィンドウプロシージャを元に戻しておきます。
::SetWindowLong( WinHandle, GWL_WNDPROC, oldProc );
と、そこに問題が。
アプリケーションの起動後にサブクラスした状態で、別の常駐プロセスが同様にサブクラス化をするんです。
本来、プロシージャのチェインは、
「MyProc」-「oldProc」
のつながりになっているわけで、このまま終了時に戻せば問題なかったわけです。
別のプロセスが同様にサブクラス化をすると、プロシージャのチェインがこうなります。
「別プロセス」-「MyProc」-「oldProc」
この状態で自前部分の終了処理が実施されてしまうと、別プロセスは ::CallWindowProc で MyProc を呼び出してしまい、アクセス違反で異常終了してしまいます。
サブクラス化を実施する手順と解除する手順が正しくないと必ずこうなってしまうわけです。
こりゃ困ったよ。
で、結論。
SetWindowSubclass
RemoveWindowSubclass
DefSubclassProc
というAPIが追加されてました。
Windows 2000 SP4 以降にしか対応してませんが、十分でしょうw
ま、苦労しましたよ(笑