2010-03-15 3 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; 
} 

Мое подозрение, что главное окно Opera как-то уже подклассифицировано. Я полагаю, происходит следующее:

  1. окно создается с его собственной основной WndProc, и фокус имеет
  2. Мое приложение подклассы окно, сохраняя оригинальный WndProc
  3. Opera подклассом свое собственное окно
  4. Когда окно теряет фокус, я восстанавливаю исходный WndProc, игнорируя второй WndProc

Возможно ли это так? Есть ли другие объяснения?

ответ

8

Это может произойти, так как Raymond Chen writes:

Рассмотрим, что произойдет, если кто-то другой подклассы окна во время «делать вещи ... ...» раздел. Когда мы закрываем окно, мы удалили бы два подкласса, тот, который мы установили, и тот, который был установлен после нас. Если в другом подклассе выделена память (которая очень распространена), тогда эта память просочилась, в дополнение к подклассу, не выполнив все, что она пыталась сделать.

Он продолжает с раствором:

Это довольно трудоемкий процесс, поэтому команда оболочки написал некоторые вспомогательные функции, чтобы сделать все это для вас. Функция SetWindowSubclass выполняет всю работу по подрыву процедуры установки подкласса, помня о предыдущем, и передает ссылочные данные в процедуру подкласса, которую вы предоставляете. Вы используете функцию DefSubclassProc для пересылки сообщения в предыдущую процедуру подкласса, и когда вы закончите, вы используете функцию RemoveWindowSubclass, чтобы удалить себя из цепочки. RemoveWindowSubclass выполняет всю работу, чтобы делать правильные вещи, если вы не являетесь програмой окна в верхней части цепочки.

+0

Не сомневайся, Раймонд Чен. :) Я не знал об этих помощниках, поэтому вы просто спасли мне кучу кодирования, пытаясь исправить это сам. :) –

Смежные вопросы