|
dos,
你的最后两句话离答案已经很近了。其实使用WinDBG或者VS观察一下汇编代码,答案就有了。
下面是没有MessageBox时,OnBnClickedException函数的代码:
TestThrowDll!CTestThrowDllDlg::OnBnClickedException: 00401460 6a01 push 1 00401462 e837000000 call TestThrowDll!ThrowExceptionFun (0040149e) 00401467 c3 ret
而下面是有MessageBox时的代码:
TestThrowDll!CTestThrowDllDlg::OnBnClickedException: 00401460 55 push ebp 00401461 8bec mov ebp,esp 00401463 6aff push 0FFFFFFFFh 00401465 68b0224000 push offset TestThrowDll!_allmul+0x40 (004022b0) 0040146a 64a100000000 mov eax,dword ptr fs:[00000000h] 00401470 50 push eax 00401471 83ec08 sub esp,8 00401474 53 push ebx 00401475 56 push esi 00401476 57 push edi 00401477 a120504000 mov eax,dword ptr [TestThrowDll!__security_cookie (00405020)] 0040147c 33c5 xor eax,ebp 0040147e 50 push eax 0040147f 8d45f4 lea eax,[ebp-0Ch] 00401482 64a300000000 mov dword ptr fs:[00000000h],eax 00401488 8965f0 mov dword ptr [ebp-10h],esp 0040148b 894dec mov dword ptr [ebp-14h],ecx 0040148e 6a00 push 0 00401490 6a00 push 0 00401492 68a0354000 push offset TestThrowDll!`string' (004035a0) 00401497 c745fc00000000 mov dword ptr [ebp-4],0 0040149e e8e5010000 call TestThrowDll!CWnd::MessageBoxA (00401688) 004014a3 6a01 push 1 004014a5 e864000000 call TestThrowDll!ThrowExceptionFun (0040150e) 004014aa 8b4df4 mov ecx,dword ptr [ebp-0Ch] 004014ad 64890d00000000 mov dword ptr fs:[0],ecx 004014b4 59 pop ecx 004014b5 5f pop edi 004014b6 5e pop esi 004014b7 5b pop ebx 004014b8 8be5 mov esp,ebp 004014ba 5d pop ebp 004014bb c3 ret 004014bc 8b4dec mov ecx,dword ptr [ebp-14h] 004014bf 6a00 push 0 004014c1 6a00 push 0 004014c3 68b0354000 push offset TestThrowDll!`string' (004035b0) 004014c8 e8bb010000 call TestThrowDll!CWnd::MessageBoxA (00401688) 004014cd b8aa144000 mov eax,offset TestThrowDll!CTestThrowDllDlg::OnBnClickedException+0x4a (004014aa) 004014d2 c3 ret
也就是说,当OnBnClickedException方法中的Try{}catch块中只调用了一个ThrowExceptionFun函数时,编译器将异常处理代码优化掉了。
优化掉的原因如你在EMAIL中说的,“默认的exe的release方式编译选项里是/EHsc,按MSDN上的说明,就是"仅捕获 C++ 异常并通知编译器假定 extern C 函数从未引发 C++ 异常"。而DLL导出函数恰好是用extern C声明了。”既然try{}catch中只有一段肯定不抛出异常的函数调用,那么这个异常处理就“没有用”了。从上面的汇编清单可以看到,裁掉后的确节约了很多空间(EXE的大小)和时间(运行时少执行很多准备异常捕捉的代码)。
加上了MessageBox调用后,因为MessageBox被认为是可能抛出异常,所以异常保护代码就在了。这也是为什么把MessageBox加在Throw前面还是后面都可以的原因。
找到了根源后,只要在OnBnClickedException方法前使用一下编译器指令禁止优化:
#pragma optimize( "", off )
那么即使没有MessageBox调用,那么也会捕捉到异常了。
|