2014-02-18 2 views
1

У меня есть приложение Win32 MFC, составленное с VS2008. Приложение имеет TreeConrtol. Существует обработчик TVN_ITEMCHANGING и внутри обработчика я принудительно перекрашиваю измененный элемент дерева.Не всегда можно поймать SEH на WoW64 на «чистой» Windows 8.1

Вот код с обработчиков 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; 
} 

Если выбрать элемент в элементе управления Tree (программно или с помощью щелчок мышью), затем после удаления всех элементов из дерева управления (с помощью DeleteAllItems или по одному) я получаю TVN_ITEMCHANGING для элемента, который уже не существует, поэтому код сверху ведет к структурированному сбору исключений, когда вызов :: SendMessage (hTreeCtrl, TVM_GETITEMRECT, ...).

Это нормально, но ... Блок __except никогда не будет выполнен на некоторых Windows 8.1 Pro x64 (и, возможно, на других версиях Windows).

Моя рабочая машина - английский Windows 8.1 Pro x64 (сборка 9600), обновленная из Windows 8. На этой машине все работает нормально (обработчик получает исключение и отображается MessageBox). Однако на чистом английском языке Windows 8.1 Pro x64 (сборка 9600), загруженном из MSDN, блок __except не вызывается, а приложение аварийно завершает работу. Имя модуля неисправности: COMCTL32.dll

Я запускаю тот же .exe-файл на обоих компьютерах. Как вы думаете, почему это может произойти?

Вот рабочий пример. Я скомпилировал его с помощью/EHsc, а затем с/EHa (реальный проект был скомпилирован с помощью/EHa и использовал try/catch).

Код в примере отличается от функции сверху: у меня есть возможность использовать try/catch и _ try/ _except.

Использование/Пьеха Я могу поймать исключение, используя оба пытаются/улова или _ попробовать/ _except на моей рабочей машине, используя/EHsc используя _ попробовать/ _except. Но ни одна из этих комбинаций не работает для другой машины (с чистым Win8.1): она не исключает исключения.

Демо-проект (скомпилирован с Visual Studio 2008 Professional SP1 + MFC): here.

PS: Проблема была временно решена путем добавления условия для вызова SendMessage(), но здесь я хочу изучить проблему с обработкой исключений.

Заранее благодарим за ваши комментарии.

+2

Это * ужасно * практика. Вы не можете больше рассуждать о состоянии своей программы после проглатывания первой. –

ответ

2

Вы не контролируете все кадры между RaiseException (или эквивалентом) и __try/__except: Между ними есть SendMessage().

Рэймонд Чен объяснил, что лучше: When you transfer control across stack frames, all the frames in between need to be in on the joke

+0

Спасибо за ссылку, она очень познавательная и объясняет, что может произойти, когда вы поймаете исключение_, но не контролируете все промежутки между ними, но это не объясняет, почему исключение может быть найдено на одном компьютере и не может быть уловлено на другой с той же версией Windows и сборкой. – Mar