由于工作需要,还在用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之后会不会影响该功能。
哈哈,经过验证没有影响,终于又可以正常使用这个老古董了。
(完)