У меня есть приложение, написанное на 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) ; и называет это в конце. У нас бесконечный цикл.
Что я могу сделать? К сожалению, у меня нет доступа к этому ПК; Я могу только исследовать дампы, логи и т. Д.