Проблема с оконным подклассом: бесконечный цикл - PullRequest
0 голосов
/ 08 сентября 2010

У меня есть приложение, написанное на MS VC ++ 6. Оно выполняет создание подклассов для нескольких окон элементов управления (мне нужно было это для пользовательского механизма создания скинов). Новая оконная процедура вызывает оконную процедуру (ее адрес был сохранен во время операции подкласса) в конце ее тела - конечно, с использованием CallWindowProc.

Это работало нормально в течение многих лет, пока один из моих клиентов (WinXP) не пожаловался на сбой приложения сразу после запуска. То, что я получил в аварийном дампе, я увидел: произошло переполнение стека. Как это:

user32.dll! __ SEH_prolog () + 0x1b байт

user32.dll!_CallWindowProcAorW@24 () + 0x51 байт

user32.dll!_CallWindowProcW@20 () + 0x1b байт

MyModule.dll! CSkinManager :: SkinWindowProc (HWND__ * hWnd = 0x00150526, unsigned int mess = 70, unsigned int wParam = 0, long lParam = 1230632) Строка 7120 C ++

user32.dll!_InternalCallWinProc@20 () + 0x28 байт

user32.dll!_UserCallWinProcCheckWow@32 () + 0xb7 байт

user32.dll!_CallWindowProcAorW@24 () + 0x51 байт

user32.dll!_CallWindowProcW@20 () + 0x1b байт

02ef007c ()

user32.dll!_InternalCallWinProc@20 () + 0x28 байт

user32.dll!_UserCallWinProcCheckWow@32 () + 0xb7 байт

user32.dll!_CallWindowProcAorW@24 () + 0x51 байт

user32.dll!_CallWindowProcW@20 () + 0x1b байт

MyModule.dll! CSkinManager :: SkinWindowProc (HWND__ * hWnd = 0x00150526, unsigned int mess = 70, unsigned int wParam = 0, long lParam = 1230632) Строка 7120 C ++

user32.dll!_InternalCallWinProc@20 () + 0x28 байт

user32.dll!_UserCallWinProcCheckWow@32 () + 0xb7 байт

user32.dll!_CallWindowProcAorW@24 () + 0x51 байт

user32.dll!_CallWindowProcW@20 () + 0x1b байт

02ef007c ()

....

user32.dll!_InternalCallWinProc@20 () + 0x28 байт

user32.dll!_UserCallWinProcCheckWow@32 () + 0xb7 байт

user32.dll!_CallWindowProcAorW@24 () + 0x51 байт

user32.dll!_CallWindowProcW@20 () + 0x1b байт

MyModule.dll! CSkinManager :: SkinWindowProc (HWND__ * hWnd = 0x00150526, unsigned int mess = 70, unsigned int wParam = 0, long lParam = 1230632) Строка 7120 C ++

user32.dll!_InternalCallWinProc@20 () + 0x28 байт

user32.dll!_UserCallWinProcCheckWow@32 () + 0xb7 байт

user32.dll!_CallWindowProcAorW@24 () + 0x51 байт

user32.dll!_CallWindowProcW@20 () + 0x1b байт

02ef007c ()

user32.dll!_InternalCallWinProc@20 () + 0x28 байт

Где MyModule.dll - имя моей DLL в моем приложении; CSkinManager :: SkinWindowProc - имя той оконной процедуры, которую я использовал в подклассах. Что такое 02ef007c () - я не знаю. Вместо этого WinDbg отображает «+ 0x02ef007b» - это мне тоже ничего не говорит. Из аварийного дампа я увидел: несколько DLL были встроены в мой процесс, например, AME_SMTPSensor.dll некоторого программного обеспечения с именем «Digital Guard» (что-то вроде антивируса). Или penjpn.dll из «Microsoft JPN рукописного ввода ввода» (мой клиент японский). Может быть, '02ef007c ()' указывает на код такой встроенной DLL?

Так или иначе, бесконечные оконные процедуры происходили. Моя оконная процедура CSkinManager :: SkinWindowProc в конце своей работы вызывает CallWindowProc (OldProcAdds), где OldProcAdds - предыдущая оконная процедура. Этот OldProcAdds, расположенный в таинственном '02ef007c ()', в конце вызывает CSkinManager :: SkinWindowProc. Через некоторое время стек переполняется.

Моя версия: некоторые из встроенных DLL-файлов процедуры подкласса окна моего окна, как только оно было создано. Тогда я вложил в это подкласс; и сохраненный адрес предыдущей оконной процедуры. Сразу после этого встроенная DLL обнаружила этот факт, и ОПЯТЬ сделал подкласс - я думаю, что он всегда хочет быть «на вершине». При этом его оконная процедура, как моя, сохраняет адрес предыдущей оконной процедуры (мой CSkinManager :: SkinWindowProc) ; и называет это в конце. У нас бесконечный цикл.

Что я могу сделать? К сожалению, у меня нет доступа к этому ПК; Я могу только исследовать дампы, логи и т. Д.

1 Ответ

1 голос
/ 08 сентября 2010

Как только другой dll переклассифицирует ваше окно, вы попадете в мир боли.Вы ничего не можете сделать, и вы полностью зависите от их глючного кода: - потому что они переклассифицировали окно, их старый процесс теперь является вами, а ваш старый процесс - им.

Единственный выход из этой ситуации - это установить флаг для обнаружения рекурсии:

// declare a variable with static storage.
// Should make it thread local if theres any chance you are
// subclassing multiple thread's windows
__declspec(thread) int gRecursive=0;


// in your windowproc, inhibit the recursive call.
if(!gRecursive++){
   ret = CallWndProc(OldProc,...);
   gRecursive--; 
}
return ret;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...