窗口子类化的问题:无限循环

时间:2010-09-08 11:46:51

标签: winapi

我有一个在MS VC ++ 6上编写的应用程序。它为几个控件窗口执行子类化(我需要这个用于自定义皮肤机制)。新的窗口过程调用窗口过程(它的地址在子类化操作期间保存)在它的主体结尾 - 当然使用CallWindowProc。

多年来一直工作好,直到我的一个客户(WinXP)抱怨应用程序在启动后立即失败。我看到了崩溃转储:堆栈溢出发生了。像这样:

user32.dll!__ SEH_prolog()+ 0x1b bytes

user32.dll!_CallWindowProcAorW@24()+ 0x51 bytes

user32.dll!_CallWindowProcW@20()+ 0x1b bytes

MyModule.dll!CSkinManager :: SkinWindowProc(HWND__ * hWnd = 0x00150526,unsigned int mess = 70,unsigned int wParam = 0,long lParam = 1230632)Line 7120 C ++

user32.dll!_InternalCallWinProc@20()+ 0x28 bytes

user32.dll!_UserCallWinProcCheckWow@32()+ 0xb7 bytes

user32.dll!_CallWindowProcAorW@24()+ 0x51 bytes

user32.dll!_CallWindowProcW@20()+ 0x1b bytes

02ef007c()

user32.dll!_InternalCallWinProc@20()+ 0x28 bytes

user32.dll!_UserCallWinProcCheckWow@32()+ 0xb7 bytes

user32.dll!_CallWindowProcAorW@24()+ 0x51 bytes

user32.dll!_CallWindowProcW@20()+ 0x1b bytes

MyModule.dll!CSkinManager :: SkinWindowProc(HWND__ * hWnd = 0x00150526,unsigned int mess = 70,unsigned int wParam = 0,long lParam = 1230632)Line 7120 C ++

user32.dll!_InternalCallWinProc@20()+ 0x28 bytes

user32.dll!_UserCallWinProcCheckWow@32()+ 0xb7 bytes

user32.dll!_CallWindowProcAorW@24()+ 0x51 bytes

user32.dll!_CallWindowProcW@20()+ 0x1b bytes

02ef007c()

...

user32.dll!_InternalCallWinProc@20()+ 0x28 bytes

user32.dll!_UserCallWinProcCheckWow@32()+ 0xb7 bytes

user32.dll!_CallWindowProcAorW@24()+ 0x51 bytes

user32.dll!_CallWindowProcW@20()+ 0x1b bytes

MyModule.dll!CSkinManager :: SkinWindowProc(HWND__ * hWnd = 0x00150526,unsigned int mess = 70,unsigned int wParam = 0,long lParam = 1230632)Line 7120 C ++

user32.dll!_InternalCallWinProc@20()+ 0x28 bytes

user32.dll!_UserCallWinProcCheckWow@32()+ 0xb7 bytes

user32.dll!_CallWindowProcAorW@24()+ 0x51 bytes

user32.dll!_CallWindowProcW@20()+ 0x1b bytes

02ef007c()

user32.dll!_InternalCallWinProc@20()+ 0x28 bytes

MyModule.dll - 我的应用程序中我的DLL的名称; CSkinManager :: SkinWindowProc - 我在子类中使用的窗口过程的名称。什么是'02ef007c()' - 我不知道。 WinDbg显示'+ 0x02ef007b'而不是这个 - 这也没有说明我。从我看到的崩溃转储:我的进程中嵌入了几个DLL,例如一些名为“Digital Guard”的软件的AME_SMTPSensor.dll(类似于防病毒)。或者是'Microsoft JPN手写输入UI'的penjpn.dll(我的客户是日语)。也许'02ef007c()'指向这种嵌入式DLL的代码?

这种或那种方式,窗口程序的无尽结束发生了。我的Windows程序CSkinManager :: SkinWindowProc在其工作结束时调用CallWindowProc(OldProcAdds),其中OldProcAdds是前一个窗口过程。这个OldProcAdds位于神秘的'02ef007c()'中,最后调用CSkinManager :: SkinWindowProc。在一段时间内,堆栈溢出。

我的版本是:一旦创建了我的窗口的一些嵌入式DLL子类窗口过程。然后我将其分类;和前一个窗口过程的存储地址。在此之后,嵌入式DLL检测到这个事实并且AGAIN做了子类化 - 我认为它总是想要'在顶部'。在它的窗口过程中,像我一样,保存了前一个窗口过程的地址(我的CSkinManager :: SkinWindowProc) ;并最终调用它。我们有无尽的循环。

我该怎么办?不幸的是我无法访问该PC;我只能调查转储,日志等。

1 个答案:

答案 0 :(得分:1)

一旦另一个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;