2010-03-15 118 views
4

我想在Windows系統上使用全局CBT鉤子繼承當前聚焦的窗口。這與this question中發生的事情有關,但是錯誤是不同的。安全刪除窗口子類?

當此子類生效時會發生什麼情況,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; 
} 

我懷疑是歌劇院的主窗口在某種程度上繼承。我想象着正在發生的事情如下:

  1. 與它自己的基本的WndProc創建的窗口,並給予重點
  2. 我的應用程序子類的窗口,存儲原始的WndProc
  3. 戲子類自己的窗口
  4. 當窗口失去焦點時,我恢復原來的WndProc,從而忽略了第二個WndProc

這是真的嗎?還有其他解釋嗎?

回答

8

這可能發生,因爲Raymond Chen writes

考慮一下,如果別人有子類的「......做的東西......」節期間,窗口會發生什麼。當我們放棄窗口的時候,我們會刪除兩個子類,一個是我們安裝的,另一個是我們之後安裝的。如果另一個子類分配內存(這是很常見的),那麼除了子類無法做任何事情之外,該內存也會泄漏。

他繼續了一個解決方案:

這是一個非常繁瑣的過程,所以外殼團隊寫了一些輔助功能,做這一切爲您服務。 SetWindowSubclass函數完成安裝子類過程,記住前一個過程以及將引用數據傳遞給您提供的子類過程的所有工作。您可以使用DefSubclassProc函數將消息轉發到以前的子類過程,並在完成後使用RemoveWindowSubclass函數將自己從鏈中移除。 RemoveWindowSubclass做所有的工作來做正確的事情,如果你不是在鏈子頂端的櫥窗。

+0

永遠不會懷疑雷蒙德。 :)我不知道這些助手,所以你只是救了我一堆編碼,試圖自己修復。 :) – 2010-03-15 10:39:25