4

グローバルCBTフックを使用して、現在フォーカスされているウィンドウをWindowsシステムでサブクラス化しようとしています。これはこの質問で何が起こるかに関連していますが、バグは異なります。

このサブクラス化が有効な場合は、Opera(バージョン10.50)のメインウィンドウが表示されなくなります。Operaには「スプラッシュ画面」があり、メインウィンドウの[開始]をクリックして、Operaが正しくシャットダウンしなかった後に表示されるようにする必要があります。このウィンドウがポップアップするたびに、Operaのメインウィンドウは表示されません。Operaが適切にシャットダウンされ、このスプラッシュ画面が表示されない場合、メインウィンドウは正常に表示されます。

HHOOK hHook;
HWND hWndSubclass = 0;

void SubclassWindow(HWND hWnd)
{
    Unsubclass();
    FARPROC lpfnOldWndProc = (FARPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LPARAM)SubClassFunc);
    SetProp(hWnd, L"PROP_OLDWNDPROC", lpfnOldWndProc);
    hWndSubclass = hWnd;
}

void Unsubclass()
{
    if (hWndSubclass != 0 && IsWindow(hWndSubclass))
    {
        FARPROC lpfnOldWndProc = (FARPROC)GetProp(hWndSubclass, L"PROP_OLDWNDPROC");
        RemoveProp(hWndSubclass, L"PROP_OLDWNDPROC");
        SetWindowLongPtr(hWndSubclass, GWLP_WNDPROC, (LPARAM)lpfnOldWndProc);
        hWndSubclass = 0;
    }
}

static LRESULT CALLBACK SubClassFunc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    if (message == WM_MOVING)
    {
        // do something irrelevant
    }
    else if (message == WM_DESTROY)
    {
        Unsubclass();
    }
    FARPROC lpfnOldWndProc = (FARPROC)GetProp(hWndSubclass, L"PROP_OLDWNDPROC");
    return CallWindowProc((WNDPROC)lpfnOldWndProc, hWndSubclass, message, wParam, lParam);
}

static LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode == HCBT_SETFOCUS && hWndServer != NULL)
    {
        SubclassWindow((HWND)wParam);
    }
    if (nCode < 0)
    {
        return CallNextHookEx(hHook, nCode, wParam, lParam);
    }
    return 0;
}

BOOL APIENTRY DllMain( HINSTANCE hInstance, 
                   DWORD  Reason, 
                   LPVOID Reserved
                 )
{
    switch(Reason)
    { 
        case DLL_PROCESS_ATTACH:
            hInst = hInstance;
            return TRUE;
        case DLL_PROCESS_DETACH:
            Unsubclass();
            return TRUE;
    }
    return TRUE;
}

私の疑惑は、Operaのメインウィンドウがどういうわけかすでにサブクラス化されているということです。私は次のことが起こっていると想像します:

  1. ウィンドウは独自の基本的なWndProcで作成され、フォーカスが与えられます
  2. 私のアプリケーションはウィンドウをサブクラス化し、元のWndProcを保存します
  3. Operaは独自のウィンドウをサブクラス化します
  4. ウィンドウのフォーカスが失われると、元のWndProcを復元し、2番目のWndProcを無視します。

これは本当にそうなのだろうか?他に説明はありますか?

4

1 に答える 1

10

レイモンド・チェンが書いているように、これは起こる可能性があります:

「...何かをする...」セクションで他の誰かがウィンドウをサブクラス化した場合にどうなるかを考えてみてください。ウィンドウのサブクラス化を解除すると、インストールしたサブクラスと、後にインストールしたサブクラスの2つのサブクラスが削除されます。他のサブクラスがメモリを割り当てた場合(これは非常に一般的です)、サブクラスが実行しようとしていたことを実行できなかったことに加えて、そのメモリがリークされました。

彼は解決策を続けます:

これは非常に面倒なプロセスであるため、シェルチームは、これらすべてを実行するためのヘルパー関数をいくつか作成しました。このSetWindowSubclass関数は、サブクラスプロシージャをインストールし、前のプロシージャを記憶し、指定したサブクラスプロシージャに参照データを渡すという面倒な作業をすべて実行します。この関数を使用しDefSubclassProcてメッセージを前のサブクラスプロシージャに転送し、完了したら、このRemoveWindowSubclass関数を使用してチェーンから自分自身を削除します。RemoveWindowSubclassあなたがチェーンの一番上にある窓の調達者でない場合、正しいことをするためにすべての仕事をします。

于 2010-03-15T10:10:00.503 に答える