2011-03-15 5 views
2

Lorsque je lance une CException dans le thread principal, elle est attrapée par le framework et un message MessageBox affiche le texte de l'erreur. Quand je lance une erreur std :: runtime_error, l'application se bloque. Le problème est que je ne vois pas le texte de l'exception, et je dois passer du temps à comprendre que c'est quelque chose que j'ai 'lancé' au lieu d'une simple violation d'accès.Utilisation de std :: runtime_error au lieu de CException

Donc je me demande s'il y a un moyen de faire que std :: exception soit interceptée et que son texte soit affiché de la même manière que CException. J'aimerais pouvoir lancer std :: runtime_error à partir de n'importe quel gestionnaire de message sans écraser mon programme, sans encapsuler tous les gestionnaires de messages dans try ... catch. C'est déjà possible pour CException, parce qu'il y a un essai ... attrape quelque part dans le code pour la pompe d'événement (je pense que c'est CWinApp :: Run - mais je ne suis pas sûr).

[Éditer] J'ai trouvé la fonction qui attrape CExceptions, mais je ne suis pas sûr qu'il soit possible de le contourner. J'ai posté le code ci-dessous. Les instructions TRY ... CATCH_ALL ... END_CATCH_ALL capturent les CExceptions.

///////////////////////////////////////////////////////////////////////////// 
// 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; 
} 

Répondre

1

Quelque part dans la mise en œuvre de MFC de la boucle principale du message qu'il a une configuration try/catch qui donne le comportement que vous voyez quand CException types sont jetés.

Vous pouvez envelopper votre propre code dans diverses instructions try/catch pour intercepter les exceptions, comme déjà mentionné par d'autres.

Il serait également possible d'encapsuler la boucle de message de MFC avec un type de gestionnaire de «niveau supérieur» pour intercepter tout ce qui n'est pas détecté autrement. Pour ce faire, remplacez CWinApp::Run dans votre classe d'application dérivée, implémentez le try/catch souhaité et appelez la base CWinApp::Run à partir de votre bloc 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

Merci, j'ai trouvé quelle fonction attrape les CExceptions (c'est AfxCallWndProc), et j'ai édité ma question. Mais je ne suis pas sûr de pouvoir l'ignorer, car ce n'est pas vraiment une fonction virtuelle. CWinApp :: Run l'appelle, mais il est comme 20-30 entrées au-dessus dans la pile d'appels. – sashoalm

4

Je me demande donc s'il y a un moyen de faire std :: exception être pris et son texte affiché d'une manière similaire à celle CException.

Oui- en l'attrapant et en affichant son texte via MessageBox.

int main() { 
    try { 
     //.... 
    } 
    catch(const std::exception& except) { 
     MessageBox(NULL, except.what(), "OMGWTF FATAL ERROR", MB_OK); 
    } 
} 
+0

+1 pour "OMGWTF FATAL ERROR";). Mais vous devriez vraiment l'attraper comme 'const &' – Tim

+0

et l'ordre des paramètres à MessageBox est faux. voir la réponse de Bo. – Tim

2

Il existe, mais vous devez le faire vous-même. :-)

int main() 
{ 
    try 
    { 
     SomeFunction(); 
    } 
    catch (const std::exception & ex) 
    { 
     ::MessageBox(0, ex.what(), 0, 0); 
    } 
} 
0

Si vous avez des exceptions que vous pourriez raisonnablement être en mesure de continuer à partir, vous pouvez également remplacer CWinApp :: PumpMessage() au lieu de ou en plus de CWinApp :: Run().

Questions connexes