jirentabu / crashrpt

Automatically exported from code.google.com/p/crashrpt
0 stars 0 forks source link

Use different text / icon in case the application will not be closed after the crash report is sent #125

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
We would like to collect crashes that may not necessary kill the application, 
but we would like to let the operator to finish his work if possible before 
restarting the application. It is true that the application will likely not be 
in a consistent state, but there is a tradeoff between losing his work and 
working with inconsistent application.

We would like to be able to display different error message for the case the 
application will be closed (crash caught by the crash reporter handlers) and 
different message for the case the application will not be closed. Something 
like:

"A critical exception happened. The application is not in consistent state. 
Save your work and restart the application."

The non-closing crash report is generated by the following structured exception 
handler. The handler makes sure that just a single crash report window will be 
open at the same time. The filter is used in __try / __catch block when calling 
risky parts of the code, ideally if there is a central dispatcher. It makes 
sense to add a similar handler to the CrashRpt dll.

// Crash reporting static variables.
// Don't start another crash reporter if another one is running.
static size_t s_nCrashRptMaxNonCriticalErrors   = 5;
static HANDLE s_hCrashRptSenderProcess          = 0;
static volatile LONG s_nCrashRptThreadsInCrashRptSEHExceptionFilter = 0;

int CrashRptSEHExceptionFilter(unsigned int code, struct _EXCEPTION_POINTERS 
*ep)
{
    LONG lockCount = ::InterlockedIncrement(&s_nCrashRptThreadsInCrashRptSEHExceptionFilter);
    if (lockCount == 1) {
        // Only the first crash handler is allowed to generate the crash report.
        if (s_hCrashRptSenderProcess != 0) {
            // Verify whether the CrashSender application is still running.
            if (::WaitForSingleObject(s_hCrashRptSenderProcess, 0) == WAIT_OBJECT_0) {
                ::CloseHandle(s_hCrashRptSenderProcess);
                s_hCrashRptSenderProcess = 0;
            }
        }
        if (s_hCrashRptSenderProcess == 0 && (s_nCrashRptMaxNonCriticalErrors --) > 0) {
            // Launch the CrashSender application
            CR_EXCEPTION_INFO exc;
            memset(&exc, 0, sizeof(CR_EXCEPTION_INFO));
            exc.cb = sizeof(CR_EXCEPTION_INFO);
            exc.pexcptrs = ep;
            exc.exctype = CR_SEH_EXCEPTION;
            exc.code    = ep->ExceptionRecord->ExceptionCode;
            exc.bManual = TRUE;
            ::crGenerateErrorReport(&exc);
            s_hCrashRptSenderProcess = exc.hSenderProcess;
        }
    }
    ::InterlockedDecrement(&s_nCrashRptThreadsInCrashRptSEHExceptionFilter);
    return EXCEPTION_EXECUTE_HANDLER; // let the application crash with unhandled exception
}

Original issue reported on code.google.com by bubn...@gmail.com on 3 Jan 2012 at 12:04

GoogleCodeExporter commented 9 years ago

Original comment by zexspect...@gmail.com on 5 Jan 2012 at 8:28

GoogleCodeExporter commented 9 years ago
BTW, I solved the different texts by following trick. I added following method 
to extract different text based on the idx parameter:

CString Utility::GetINIString(LPCTSTR pszFile, LPCTSTR pszSection, LPCTSTR 
pszName, UINT idx)
{  
    TCHAR szBuffer[2048] = _T("");
    CString sTextRandom = _T("!@#$%^&*()jhqwhfs#@^%@!%^*(@#_)&(*&^%#@!)@#_)");
    CString name;
    name.Format(_T("%s_%d"), pszName, idx);
    GetPrivateProfileString(pszSection, name, sTextRandom, szBuffer, 1024, pszFile);
    if (sTextRandom == szBuffer)
        // The indexed text was not found and has been initialized with the default value. Try the text field without the index.
        GetPrivateProfileString(pszSection, pszName, sTextRandom, szBuffer, 1024, pszFile);

    CString sResult = szBuffer;
    sResult.Replace(_T("\\n"), _T("\n"));

    return sResult;
}

Basically it will search for VariableName_idx first and if it does not find it, 
then it looks for VariableName. 

I then use the index to address the particular texts:
    sHeading.Format(Utility::GetINIString(g_CrashInfo.m_sLangFileName, _T("MainDlg"), _T("HeaderText"), g_CrashInfo.m_nTextGroupID), g_CrashInfo.m_sAppName);

m_nTextGroupID is added to CRASH_DESCRIPTION and it is copied in 
CCrashHandler::GenerateErrorReport() from CR_EXCEPTION_INFO. So by default the 
index is set to 0, but when the user calls GenerateErrorReport(), he may opt to 
override the index.

In the language file I then define multiple lines per dialog item:
HeaderText=%s has stopped working and will be closed.
HeaderText_1=%s has crashed internally and may not continue running reliably. 
Save your work and restart the application.
HeaderText_2=User has triggered %s to generate manual crash report. 

Thanks, Vojtech

Original comment by bubn...@gmail.com on 5 Jan 2012 at 9:00

GoogleCodeExporter commented 9 years ago
Not clear about your custom handler. What is this? As I imagine, there should 
be the single centralized handler - CCrashHandler, so no custom handlers needed.

Not clear how you will determine when to close the app and when to continue its 
execution. Can you clarify this? 

Currently, CrashRpt has an ability to notify client app about crash through 
crash callback. As I imagine it, CrashRpt should pass crash information to 
crash callback function and the callback function will determine if to close 
the app or not, based on crash information. 

So, I need more information from you to better understand your needs. 

Original comment by zexspect...@gmail.com on 29 Aug 2012 at 7:32

GoogleCodeExporter commented 9 years ago

Original comment by zexspect...@gmail.com on 19 Sep 2012 at 4:21

GoogleCodeExporter commented 9 years ago
I added a new-style crash callback replacing the obsolete LPGETLOGFILE() 
callback.
Added PFNCRASHCALLBACK() callback function prototype, CR_CRASH_CALLBACK_INFO
structure and crAddCrashCallback() function.

Added an ability to continue program execution after crash. This can be 
performed
through crash callback (see CR_CRASH_CALLBACK_INFO::bContinueExecution structure
member).

Hovewer, I did not implement changes related to different icon/text for 
critical and non-critical errors. IMHO, it would be better if your application 
display some dialog telling user about the crash and asking him/her to save the 
work and exit the app.

Original comment by zexspect...@gmail.com on 17 Oct 2012 at 3:57

GoogleCodeExporter commented 9 years ago
This issue was closed by revision r1432.

Original comment by zexspect...@gmail.com on 17 Oct 2012 at 3:58