Использование std :: runtime_error вместо CException - PullRequest
2 голосов
/ 15 марта 2011

Когда я добавляю CException в основной поток, он аккуратно перехватывается платформой, и красивый MessageBox показывает текст ошибки. Когда я выкидываю std :: runtime_error, приложение просто падает. Проблема в том, что я не вижу текст исключения, и мне приходится тратить время на то, чтобы понять, что на самом деле я что-то «выбросил», а не просто нарушение прав доступа.

Поэтому мне интересно, есть ли способ сделать так, чтобы std :: исключение было перехвачено и его текст отображался так же, как CException.

Я бы хотел иметь возможность генерировать std :: runtime_error из любого обработчика сообщений без сбоя моей программы, без включения каждого обработчика сообщений в try ... catch. Это уже возможно для CException, потому что есть попытка ... поймать где-нибудь в коде для насоса событий (я думаю, что это CWinApp :: Run - но я не уверен).

[Изменить] Я нашел функцию, которая перехватывает CExceptions, но я не уверен, можно ли ее переопределить. Я разместил код ниже. Операторы TRY ... CATCH_ALL ... END_CATCH_ALL перехватывают исключения CEx.

/////////////////////////////////////////////////////////////////////////////
// Official way to send message to a CWnd

LRESULT AFXAPI AfxCallWndProc(CWnd* pWnd, HWND hWnd, UINT nMsg,
    WPARAM wParam = 0, LPARAM lParam = 0)
{
    _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
    MSG oldState = pThreadState->m_lastSentMsg;   // save for nesting
    pThreadState->m_lastSentMsg.hwnd = hWnd;
    pThreadState->m_lastSentMsg.message = nMsg;
    pThreadState->m_lastSentMsg.wParam = wParam;
    pThreadState->m_lastSentMsg.lParam = lParam;

#ifdef _DEBUG
    _AfxTraceMsg(_T("WndProc"), &pThreadState->m_lastSentMsg);
#endif

    // Catch exceptions thrown outside the scope of a callback
    // in debug builds and warn the user.
    LRESULT lResult;
    TRY
    {
#ifndef _AFX_NO_OCC_SUPPORT
        // special case for WM_DESTROY
        if ((nMsg == WM_DESTROY) && (pWnd->m_pCtrlCont != NULL))
            pWnd->m_pCtrlCont->OnUIActivate(NULL);              
#endif

        // special case for WM_INITDIALOG
        CRect rectOld;
        DWORD dwStyle = 0;
        if (nMsg == WM_INITDIALOG)
            _AfxPreInitDialog(pWnd, &rectOld, &dwStyle);

        // delegate to object's WindowProc
        lResult = pWnd->WindowProc(nMsg, wParam, lParam);

        // more special case for WM_INITDIALOG
        if (nMsg == WM_INITDIALOG)
            _AfxPostInitDialog(pWnd, rectOld, dwStyle);
    }
    CATCH_ALL(e)
    {
        lResult = AfxProcessWndProcException(e, &pThreadState->m_lastSentMsg);
        TRACE(traceAppMsg, 0, "Warning: Uncaught exception in WindowProc (returning %ld).\n",
            lResult);
        DELETE_EXCEPTION(e);
    }
    END_CATCH_ALL

    pThreadState->m_lastSentMsg = oldState;
    return lResult;
}

Ответы [ 4 ]

4 голосов
/ 15 марта 2011

Так что мне интересно, есть ли способ make std :: exception будет пойман и его текст отображается так же, как CException.

Да, перехватывая его и отображая текст через MessageBox.

int main() {
    try {
        //....
    }
    catch(const std::exception& except) {
        MessageBox(NULL, except.what(), "OMGWTF FATAL ERROR", MB_OK);
    }
}
2 голосов
/ 15 марта 2011

Да, но вы должны сделать это сами.: -)

int main()
{
    try
    {
        SomeFunction();
    }
    catch (const std::exception & ex)
    {
        ::MessageBox(0, ex.what(), 0, 0);
    }
}
1 голос
/ 15 марта 2011

Где-то в реализации основного цикла сообщений в MFC есть настройка try / catch, которая дает поведение, которое вы видите, когда выбрасываются CException типы.

Вы можете заключить свой собственный код в различные операторы try / catch, чтобы перехватить исключения, как уже было сказано другими.

Также можно было бы обернуть цикл сообщений MFC своего рода обработчиком «верхнего уровня», чтобы перехватить все, что не поймано иначе. Для этого переопределите CWinApp::Run в своем производном классе приложения, реализуйте желаемый try / catch и вызовите базу CWinApp::Run из вашего блока try.

int CMyApp::Run()
{
    try
    {
        return CWinApp::Run();
    }
    catch(const std::exception& ex)
    {
        MessageBox(NULL, ex.what(), "Error", MB_OK | MB_ICONERROR);
        return 1;  // or some appropriate code
    }
}
0 голосов
/ 20 марта 2011

Если у вас есть исключения, от которых вы могли бы разумно продолжить, вы также можете переопределить CWinApp :: PumpMessage () вместо или в дополнение к CWinApp :: Run ().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...