1

我有用 VS2008 编译的 Win32 MFC 应用程序。该应用程序具有 TreeConrtol。有一个 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_GETITEMRECT, ...) 时会导致结构化异常引发。

没关系,但是... __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 / _except。但是这些组合都不适用于另一台机器(使用干净的 Win8.1):它不会捕获异常。

演示项目(使用 Visual Studio 2008 Professional SP1 + MFC 编译):这里.

PS:通过在 SendMessage() 调用中添加 if 条件暂时解决了问题,但这里我想调查一下异常处理的问题。

提前感谢您的评论。

4

1 回答 1

2

您不能控制RaiseException(或等效)和__try/__except:之间的所有帧:中间有SendMessage()调用。

Raymond Chen 解释得最好:当你在堆栈帧之间转移控制时,中间的所有帧都需要开玩笑

于 2014-02-18T09:44:18.537 回答