У меня есть приложение Win32 MFC, скомпилированное с VS2008. В приложении есть 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.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 и _пытаться/_Кроме.
Используя / EHa, я могу поймать исключение, используя как try / catch, так и _пытаться/_except на моей рабочей машине, используя / EHsc используя _пытаться/_Кроме. Но ни одна из этих комбинаций не работает для другой машины (с чистой Win8.1): она не ловит исключение.
Демонстрационный проект (скомпилирован с Visual Studio 2008 Professional SP1 + MFC): Вот.
PS: проблема была временно решена путем добавления условия if к вызову SendMessage (), но здесь я хочу исследовать проблему с обработкой исключений.
Заранее благодарю за ваши комментарии.
Вы не контролируете все кадры между RaiseException
(или эквивалент) и __try/__except
: Есть SendMessage()
позвонить в промежутке.
Раймонд Чен объяснил это лучше всего: Когда вы передаете управление через кадры стека, все кадры между ними должны быть включены в шутку
Других решений пока нет …