我有用VS2008编译的Win32 MFC应用程序。该应用程序具有TreeContol。有一个TVN_ITEMCHANGING处理程序,在该处理程序中,我强制重新绘制更改后的树项。
以下是使用SEH处理程序和直接WinAPI调用而不是MFC包装器的代码(这不会影响问题):
void CMainDlg::OnTvnItemChangingMainTree(NMHDR *pNMHDR, LRESULT *pResult)
{
NMTVITEMCHANGE *pNMTVItemChange = reinterpret_cast(pNMHDR);
HWND hTreeCtrl = _ctrlTree.GetSafeHwnd();
RECT rect;
__try
{
*(HTREEITEM*) &rect = hItem;
if ((BOOL) ::SendMessage(hTreeCtrl, TVM_GETITEMRECT,
(WPARAM) FALSE, (LPARAM) &rect))
{
::InvalidateRect(hTreeCtrl, &rect, TRUE);
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
::MessageBox(NULL, L"SEH exception is Here", L"__except Block", MB_OK);
}
*pResult = 0;
}
如果我在树控件中选择了一个项目(通过编程或鼠标单击),那么在从树控件中删除所有项目后(通过使用DeleteAllItems或逐个),我将获得已经不存在的项目的TVN_ITEMCHANGING,因此上面的代码在调用:SendMessage(hTreeCtrl,TVM_GETTEMRECT,…)时会引发结构化异常。
没关系,但是。。。__except块永远不会在某些Windows 8.1 Pro x64上执行(可能在其他Windows版本上)。
我的工作机器是从Windows 8更新的英文Windows 8.1 Pro x64(内部版本9600)。在那台机器上,一切都很正常(处理程序捕获异常并显示MessageBox)。然而,在从MSDN下载的干净英文Windows 8.1 Pro x64(内部版本9600)上,__except块不会被调用,应用程序崩溃。故障模块名称:COMCTL32.dll
我在两台计算机上运行相同的.exe文件。你认为为什么会发生这种情况?
下面是一个工作示例。我先用/EHsc编译,然后用/EHa编译(真正的项目是用/EHa编写的,使用try/catch)。
示例中的代码与上面的函数不同:我添加了使用try/catch和_try/_except的选项。
使用/EHa,我可以在我的工作机器上使用try/catch或_try/_except来捕获异常,使用/EHsc使用_try/_eexcept来捕捉异常。但这些组合都不适用于其他机器(使用干净的Win8.1):它不会捕获异常。
演示项目(使用Visual Studio 2008 Professional SP1+MFC编译):此处。
PS:通过在SendMessage()调用中添加if条件,这个问题暂时得到了解决,但在这里我想研究一下异常处理的问题。
提前感谢您的评论。
您不能控制RaiseException
(或等效)和__try/__except
之间的所有帧:两者之间有SendMessage()
调用。
Raymond Chen解释得最好:当你在堆栈帧之间传输控制时,中间的所有帧都需要在笑话中