安全删除窗口子类?

Veg*_*sen 4 c++ winapi subclassing

我试图使用全局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;
}
Run Code Online (Sandbox Code Playgroud)

我怀疑Opera的主窗口已经以某种方式已经被子类化了.我想以下情况正在发生:

  1. 该窗口是使用它自己的基本WndProc创建的,并且具有焦点
  2. 我的应用程序对窗口进行子类化,存储原始的WndProc
  3. Opera子类化它自己的窗口
  4. 当窗口失去焦点时,我恢复原始的WndProc,从而忽略第二个WndProc

真的可以这样吗?还有其他解释吗?

Tho*_*mas 9

这可能发生,正如雷蒙德陈写道:

考虑如果其他人在"......做东西......"部分中将子窗口子类化,会发生什么.当我们取消分类窗口时,我们将删除两个子类,即我们安装的子类,以及我们之后安装的子类.如果另一个子类分配了内存(这是很常见的),那么该内存就会泄漏,除了子类无法做任何尝试.

他继续解决方案:

这是一个非常繁琐的过程,因此shell团队编写了一些帮助函数来为您完成所有这些.该SetWindowSubclass函数执行安装子类过程的所有繁琐工作,记住前一个过程,并将引用数据传递给您提供的子类过程.您可以使用该DefSubclassProc函数将消息转发到上一个子类过程,并在完成后使用该RemoveWindowSubclass函数将您自己从链中删除.RemoveWindowSubclass如果你不是链条顶端的窗口,那么所有工作都要做正确的事情.