由于工作需要,还在用vs2005这个老古董,虽然很不喜欢。
虽然很轻,但有两个原因不喜欢:
调试总要加载符号,不让加非加,慢的无语
时不时总是无缘无故无法启动
无法启动这个事已经无数次出现了,重装,重启,屏蔽Assist均是无效。
后来无意间点击了C:\Program Files (x86)\Microsoft Visual Studio 8\Common7\IDE\devenv.com,可以启动了。
但这次这个方法也不行了,实在是忍无可忍。
决定干它。
上调试器,启动devenv.exe。
看到崩溃原因 c00000fd,就是栈溢出,看来应该是函数调用无限循环了。
不要问我为啥知道,因为之前遇到过。
看看栈,果然如此,user32->msdev!xxx->user32->msdev!xxx->...
0:000:x86> kn 10
打开IDA,简单看看msdev。
int __userpurge CAutoCompletionManagerCL::TargetSubclassProcSTATIC@<eax>(int a1@<esi>, HWND a2, unsigned int a3, unsigned int a4, unsigned int a5)
CAutoCompletionManagerCL::TargetSubclassProcSTATIC应该是个wndproc,本来逻辑应该是在内部CallWindowProcAW调用原始wndproc,但是CallWindowProcAW又调用了CAutoCompletionManagerCL::TargetSubclassProcSTATIC,这样死循环,一直到栈移除。
看看CAutoCompletionManagerCL::TargetSubclassProcSTATIC是哪里设置的,找到了:
int __userpurge CAutoCompletionManagerCL::AttachToCombo@<eax>(CAutoCompletionManagerCL *this@<ecx>, int a2@<eax>, struct IMsoControl *a3, HWND a4)
所以问题应该基本清晰了,SetWindowLongW(v11, -4, (LONG)CAutoCompletionManagerCL::TargetSubclassProcSTATIC);被重复设置了,*((_DWORD *)this + 12) = v7,保存的值被覆盖成了CAutoCompletionManagerCL::TargetSubclassProcSTATIC
所以这样死循环,导致调用栈溢出
第一次进入msenv!CAutoCompletionManagerCL::AttachToCombo设置SetWindowLongW返回就已经是msenv!CAutoCompletionManagerCL::TargetSubclassProcSTATIC
赋值之前看到原始地址:
msenv!CAutoCompletionManagerCL::AttachToCombo+0x60:
猜测CAutoCompletionManager::OnCreate中就已经调用SetWindowLongW了。
尝试使用条件断点看看能不能找到。
0:000:x86> u CAutoCompletionManagerCL::TargetSubclassProcSTATIC
断下后,确认函数没问题,看看调用栈。
可以看到msenv!CAutoCompletionManagerCL::VerifyAttachment在OnCreate内部设置了一次。
USER32!SetWindowLongW:
所以应该是msevn逻辑出现了问题,应该加上控件创建成功后,才能SetWindowsLong,或者直接在SetWindowLong之前判断是否已经设置过。
我可以给他改改代码,但是挺麻烦的。
再看看是不是有什么可以控制的条件,有更简单的修改方法。
看看CAutoCompletionManagerCL::AttachToCombo被谁调用了:
Breakpoint 0 hit
看看CAutoCompletionManagerCL::UseAutocompletion的逻辑:
int __userpurge CAutoCompletionManagerCL::UseAutocompletion@<eax>(CVSShellMenu *a1@<ecx>, struct IMsoControl *a2@<edi>, struct IMsoControl *a3)
猜测跟代码自动完成有关,这个CCmdWindow::ms_fEnableAutocompletion变量好像可以弄弄,如果设置为假,就完全不会进入后面的逻辑。
现在看看CCmdWindow::ms_fEnableAutocompletion在哪里设置的。
void __stdcall PrefInitPart2()
好像有戏,CommandWindowAutocompletion是用户配置相关的。CommandWindowAutocompletion未配置默认开启ms_fEnableAutocompletion。
int __userpurge GetUserOption@<eax>(int a1@<eax>, LPCWSTR lpValueName, LPBYTE lpData, DWORD cbData, unsigned int a5)
通过调试确认,最终找到配置位置:
计算机\HKEY_CURRENT_USER\SOFTWARE\Microsoft\VisualStudio\8.0\General
增加注册表CommandWindowAutocompletion,设置为0,这样ms_fEnableAutocompletion就是0,问题解决。
看名字这个有点像代码自动完成功能的,但不知道ms_fEnableAutocompletion配置为0之后会不会影响该功能。
哈哈,经过验证没有影响,终于又可以正常使用这个老古董了。
(完)