Click here to Skip to main content
15,891,874 members
Articles / Web Development / HTML

Integrating Crash Reporting into Your Application - A Beginners Tutorial

Rate me:
Please Sign up or sign in to vote.
4.91/5 (30 votes)
5 Feb 2012CPOL12 min read 90.7K   4.4K   170  
This article shows how to use CrashRpt error reporting library with an MFC application
<!-- This comment will put IE 6, 7 and 8 in quirks mode -->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="icon" href="../favicon.ico" type="image/x-icon" />
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<title>CrashRpt: Using CrashRpt API</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javaScript" src="search/search.js"></script>
<link href="doxygen.css" rel="stylesheet" type="text/css"/>
</head>
<body onload='searchBox.OnSelectItem(0);'>

<table border="0" bgcolor="#FFFFFF" cellspacing="5" width="100%">
 <tr>
  <td width="24px" rowspan="2"><img src="../logo.png" alt="Logo" /></td>
  <td><font family="Arial" size="+2">crashrpt</font></td>
  <td rowspan="2" align="right"><a href="http://sourceforge.net/donate/index.php?group_id=279722"><img src="../donate_small.png" alt="Donate" /></a></td>
 </tr>
 <tr>
  <td colspan="2"><i>A crash reporting system for Windows applications</i></td>
 </tr>


</table>


</body>
<!-- Generated by Doxygen 1.5.9 -->
<script type="text/javascript">
<!--
function changeDisplayState (e){
  var num=this.id.replace(/[^[0-9]/g,'');
  var button=this.firstChild;
  var sectionDiv=document.getElementById('dynsection'+num);
  if (sectionDiv.style.display=='none'||sectionDiv.style.display==''){
    sectionDiv.style.display='block';
    button.src='open.gif';
  }else{
    sectionDiv.style.display='none';
    button.src='closed.gif';
  }
}
function initDynSections(){
  var divs=document.getElementsByTagName('div');
  var sectionCounter=1;
  for(var i=0;i<divs.length-1;i++){
    if(divs[i].className=='dynheader'&&divs[i+1].className=='dynsection'){
      var header=divs[i];
      var section=divs[i+1];
      var button=header.firstChild;
      if (button!='IMG'){
        divs[i].insertBefore(document.createTextNode(' '),divs[i].firstChild);
        button=document.createElement('img');
        divs[i].insertBefore(button,divs[i].firstChild);
      }
      header.style.cursor='pointer';
      header.onclick=changeDisplayState;
      header.id='dynheader'+sectionCounter;
      button.src='closed.gif';
      section.id='dynsection'+sectionCounter;
      section.style.display='none';
      section.style.marginLeft='14px';
      sectionCounter++;
    }
  }
}
window.onload = initDynSections;
-->
</script>
<div class="navigation" id="top">
  <div class="tabs">
    <ul>
      <li><a href="index.html"><span>Contents</span></a></li>
      <li><a href="modules.html"><span>API&nbsp;Reference</span></a></li>
      <li><a href="files.html"><span>File&nbsp;Reference</span></a></li>
    <li>
      <form action="search.php" method="get">
        <table cellspacing="0" cellpadding="0" border="0">
          <tr>
            <td><label>&nbsp;<u>S</u>earch&nbsp;for&nbsp;</label></td>
            <td><input type="text" name="query" value="" size="20" accesskey="s"/></td>
          </tr>
        </table>
      </form>
    </li>
    </ul>
  </div>
  <div class="navpath"><a class="el" href="index.html">CrashRpt Documentation</a>&nbsp;&raquo&nbsp;<a class="el" href="using_crashrpt.html">Using CrashRpt in Your Project</a>
  </div>
</div>
<div class="contents">
<h1><a class="anchor" name="using_crashrpt_api">Using CrashRpt API </a></h1>CrashRpt library provides several API functions, structures and classes that can be used in your project (see <a class="el" href="group___crash_rpt_a_p_i.html">CrashRpt Functions</a>, <a class="el" href="group___crash_rpt_structs.html">CrashRpt Structures</a>, <a class="el" href="group___crash_rpt_wrappers.html">CrashRpt Wrapper Classes</a>).<p>
<dl class="note" compact><dt><b>Note:</b></dt><dd>Older versions of CrashRpt provided different set of API functions that are now declared obsolete. Those obsolete API functions are still supported for compatibility with older versions of CrashRpt, but it is recommended that you use the newer functions instead. Here is the complete list of <a class="el" href="group___deprecated_a_p_i.html">Obsolete Functions</a>.</dd></dl>
All CrashRpt functions have <code>cr</code> prefix, CrashRpt structures have <code>CR</code> prefix and CrashRpt classes have <code>Cr</code> prefix.<p>
All CrashRpt functions using character set dependent arguments have two versions of function name (multibyte versions are A-suffixed and wide character versions are W-suffixed). For example, <a class="el" href="group___crash_rpt_a_p_i.html#g24acb589d629460590d85735e12b5337" title="Character set-independent mapping of crInstallW() and crInstallA() functions.">crInstall()</a> function has two versions of function name: <a class="el" href="group___crash_rpt_a_p_i.html#g18a7a7421e1522f787ba451eaf424b0e">crInstallA()</a> and <a class="el" href="group___crash_rpt_a_p_i.html#gc1f98f531d9a1c67f090768ce4316ffd" title="Installs exception handlers for the caller process.">crInstallW()</a>. Typically in your program you use a character set independent mapping of function name, for example use <a class="el" href="group___crash_rpt_a_p_i.html#g24acb589d629460590d85735e12b5337" title="Character set-independent mapping of crInstallW() and crInstallA() functions.">crInstall()</a> that expands into <a class="el" href="group___crash_rpt_a_p_i.html#gc1f98f531d9a1c67f090768ce4316ffd" title="Installs exception handlers for the caller process.">crInstallW()</a> if you use wide character set or into <a class="el" href="group___crash_rpt_a_p_i.html#g18a7a7421e1522f787ba451eaf424b0e">crInstallA()</a> if you use multibyte character set.<h2><a class="anchor" name="enabling_crash_reporting">
Enabling Crash Reporting</a></h2>
To enable crash reporting support in your C++ application you use <a class="el" href="group___crash_rpt_a_p_i.html#g24acb589d629460590d85735e12b5337" title="Character set-independent mapping of crInstallW() and crInstallA() functions.">crInstall()</a> and <a class="el" href="group___crash_rpt_a_p_i.html#g6fe5cff31697f687b29dc73cd34d72b4" title="Installs exception handlers to the caller thread.">crInstallToCurrentThread2()</a> functions. There are two functions because of difference in work of exception handlers. Some of them work for entire process and others work for caller thread only.<p>
The function <a class="el" href="group___crash_rpt_a_p_i.html#g24acb589d629460590d85735e12b5337" title="Character set-independent mapping of crInstallW() and crInstallA() functions.">crInstall()</a> installs exception handlers that work on per-process basis. Typically you call the <a class="el" href="group___crash_rpt_a_p_i.html#g24acb589d629460590d85735e12b5337" title="Character set-independent mapping of crInstallW() and crInstallA() functions.">crInstall()</a> in the beginning of your <b>main()</b> or <b>WinMain()</b> function.<p>
You pass configuration settings to <a class="el" href="group___crash_rpt_a_p_i.html#g24acb589d629460590d85735e12b5337" title="Character set-independent mapping of crInstallW() and crInstallA() functions.">crInstall()</a> through the <a class="el" href="group___crash_rpt_structs.html#g61e78b3a8180a386e7a40ecf125e5c1d">CR_INSTALL_INFO</a> structure. The configuration settings include application name and version, recipient's e-mail address or URL, path for saving error reports, Privacy Policy URL and so on.<p>
You can also create a crash callback function <a class="el" href="group___crash_rpt_a_p_i.html#ga5587485696de27611c497382de06ce3" title="Client crash callback function prototype.">LPGETLOGFILE()</a> and pass its pointer to <a class="el" href="group___crash_rpt_a_p_i.html#g24acb589d629460590d85735e12b5337" title="Character set-independent mapping of crInstallW() and crInstallA() functions.">crInstall()</a>. The crash callback function is called on crash.<p>
On application exit, you use the <a class="el" href="group___crash_rpt_a_p_i.html#gb5ff3a104014a1e138878a1882822442" title="Unsinstalls exception handlers previously installed with crInstall().">crUninstall()</a> function to unset exception handlers.<p>
The function <a class="el" href="group___crash_rpt_a_p_i.html#g6fe5cff31697f687b29dc73cd34d72b4" title="Installs exception handlers to the caller thread.">crInstallToCurrentThread2()</a> installs exception handlers that work on per-thread basis. In a multi-threaded program you call the <a class="el" href="group___crash_rpt_a_p_i.html#g6fe5cff31697f687b29dc73cd34d72b4" title="Installs exception handlers to the caller thread.">crInstallToCurrentThread2()</a> for all threads except the main one. Typically you call this function in the beginning of the thread procedure.<p>
Just before the return from the thread procedure, call the <a class="el" href="group___crash_rpt_a_p_i.html#gaf56dbee81338534d96ab23f694be43c" title="Uninstalls C++ exception handlers from the current thread.">crUninstallFromCurrentThread()</a> function to unset exception handlers from the caller thread. No need to call the <a class="el" href="group___crash_rpt_a_p_i.html#gaf56dbee81338534d96ab23f694be43c" title="Uninstalls C++ exception handlers from the current thread.">crUninstallFromCurrentThread()</a> function in the main execution thread, because <a class="el" href="group___crash_rpt_a_p_i.html#gb5ff3a104014a1e138878a1882822442" title="Unsinstalls exception handlers previously installed with crInstall().">crUninstall()</a> will do that for you automatically.<p>
You can use <a class="el" href="group___crash_rpt_wrappers.html">CrashRpt Wrapper Classes</a> to simplify installation and uninstallation of exception handlers in your program. Use <a class="el" href="class_cr_auto_install_helper.html" title="Installs exception handlers in constructor and uninstalls in destructor.">CrAutoInstallHelper</a> wrapper class to install exception handlers in your <b>main()</b> function. In a multi-threaded program, use <a class="el" href="class_cr_thread_auto_install_helper.html" title="Installs (uninstalls) exception handlers for the caller thread in class&#39; constructor...">CrThreadAutoInstallHelper</a> wrapper class to install exception handlers in each worker thread.<h2><a class="anchor" name="adding_a_custom_file">
Adding a Custom File</a></h2>
Typically an application creates and maintains a log file where operations and errors are written. Such a log file can be helpful for crash analysis and should be added to your application's error report. You add application-specific files to the error report using <a class="el" href="group___crash_rpt_a_p_i.html#g382c00cf76818ba1a66eb89715a030ea" title="Character set-independent mapping of crAddFile2W() and crAddFile2A() functions.">crAddFile2()</a> function.<h2><a class="anchor" name="adding_a_custom_property">
Adding a Custom Property</a></h2>
One way to add application-defined info to the error report is adding a file as described above. But sometimes you may want to extend the crash description XML file by adding a named literal property to the file. You can do this through the <a class="el" href="group___crash_rpt_a_p_i.html#g5bc9d5a06b3ef1bb62e61b109f890730" title="Character set-independent mapping of crAddPropertyW() and crAddPropertyA() functions...">crAddProperty()</a> function.<p>
For example, you may need to add the info about the amount of free disk space on a specific disk drive at the moment of crash, or about the version of the graphics card driver.<h2><a class="anchor" name="adding_a_screenshot">
Adding a Screen Shot</a></h2>
It may be useful to have a screen shot of user's desktop at the moment of crash. This may help to see which button user clicked before the crash, to see the desktop state and easier reproduce the crash. For example, for multi-monitor desktops it may be useful to see if the application window is positioned on the primary monitor, on the secondary monitor, or at the boundary of two monitors. Sometimes it may be enough to see only the region of the desktop occupied by your application and not the rest of desktop.<p>
But there is one thing to take in account. By enabling screenshot capture, you should be careful about user's privacy. Some parts of the desktop screenshot may contain private or user identifying information: folder names, wallpapers, photos, text fragments and so on. That's why you should always provide a link to your Privacy Policy page describing what information you collect on crash and what purposes you use it for. By clicking the Send Report button, user confirms he/she is familiar with the contents of the error report and accepts the terms of the Privacy Policy.<p>
You can make a screen shot of user's virtual screen or a screen shot of your main window using the <a class="el" href="group___crash_rpt_a_p_i.html#g7a2a09a4be002f99d1f224e5a5baae82" title="Adds a screenshot to the crash report.">crAddScreenshot()</a> function.<h2><a class="anchor" name="adding_a_reg_key">
Adding a Registry Key</a></h2>
Many applications store settings inside of Windows registry. Application's settings might be useful for crash analysis. Since v.1.2.6, you can ask CrashRpt to dump a registry key contents on crash. Use the <a class="el" href="group___crash_rpt_a_p_i.html#ge5c00c702ef3b674f9c4a509f61728e1">crAddRegKey()</a> function.<h2><a class="anchor" name="debugging_a_remote_logics_error">
Debugging a Remote Logics Error</a></h2>
Sometimes it is required to remotely debug some application logics error. Such an error, for example, infinite loop in a worker thread, may not cause program crash. To collect the information about error that doesn't cause crash, a software developer might provide an ability to generate error report manually on user demand, for example on a key combination press. The <a class="el" href="group___crash_rpt_a_p_i.html#g60af60c28c64a1d3baa11f1220b9c3f4" title="Manually generates an errror report.">crGenerateErrorReport()</a> function allows to generate an error report manually.<h2><a class="anchor" name="silent_mode">
Silent (non-GUI) Mode</a></h2>
<b>Since v.1.2.2</b>, CrashRpt can function in silent mode. In this mode, no <em>Error Report</em> window is shown on crash and no interaction with user is performed. The silent mode is enabled by specifying the <a class="el" href="_crash_rpt_8h.html#eac654ac2258cdf40a907dca1617e193">CR_INST_NO_GUI</a> flag for <a class="el" href="struct_c_r___i_n_s_t_a_l_l___i_n_f_o_a.html#1798fdbe4869846814ebe004a316037c">CR_INSTALL_INFO::dwFlags</a> structure member.<p>
The silent mode is designed for server applications or services that do not need to interact with user on crash. The silent mode should not be used for regular GUI applications. For regular interactive applications, a user should provide his/her consent to allow sending the error report.<h2><a class="anchor" name="automatic_app_restart">
Automatic Application Restart</a></h2>
<b>Since v.1.2.4</b>, you can tell CrashRpt to restart your application automatically when crash occurs. This can be done by specifying the <a class="el" href="_crash_rpt_8h.html#92c65e94c4f6f1363644114be2c49f7a">CR_INST_APP_RESTART</a> flag for the <a class="el" href="struct_c_r___i_n_s_t_a_l_l___i_n_f_o_a.html#1798fdbe4869846814ebe004a316037c">CR_INSTALL_INFO::dwFlags</a> structure member.<p>
You can pass command line parameters to the executable being restarted using <a class="el" href="struct_c_r___i_n_s_t_a_l_l___i_n_f_o_a.html#7d9dc7839f981433dda0be4d18b256c2">CR_INSTALL_INFO::pszRestartCmdLine</a>, but can't specify another executable for restart. Only the same executable can be restarted that was used to start the current process.<p>
The application is restarted only if at least 60 seconds have elapsed since its start up. This is done to avoid cyclic restarts of an application that crashes right on its start up. Also, the application is restarted only if the user does provide his/her consent.<p>
If you generate an error report manually, the caller process is not terminated automatically. If you do not want to terminate the caller process, and want to avoid starting the second instance of the application, specify the <a class="el" href="struct_c_r___e_x_c_e_p_t_i_o_n___i_n_f_o.html#b3769ed1dc4f6c36d77c420b38d59687">CR_EXCEPTION_INFO::bManual</a> flag.<h2><a class="anchor" name="testing_if_intercepted">
Testing If Exceptions are Intercepted</a></h2>
When you install crash reporting support to your program, it is important to test if CrashRpt intercepts exceptions properly. Use <a class="el" href="group___crash_rpt_a_p_i.html#g71fc93e6828f68f88b80326104489720" title="Emulates a predefined crash situation.">crEmulateCrash()</a> function to emulate an exceptional situation. You may call this function in each thread of your program to ensure all exceptions will be caught.<h2><a class="anchor" name="get_err_msg">
Getting Error Messages</a></h2>
Typically a CrashRpt API function returns zero value if succeeded and non-zero if failed. To get text error message of the last called function, use <a class="el" href="group___crash_rpt_a_p_i.html#g062f47d5f7284d72793c60699c7caa33" title="Defines character set-independent mapping for crGetLastErrorMsgW() and crGetLastErrorMsgA()...">crGetLastErrorMsg()</a>.<h2><a class="anchor" name="api_reference">
CrashRpt API Reference</a></h2>
<ul>
<li><a class="el" href="group___crash_rpt_a_p_i.html">CrashRpt Functions</a></li><li><a class="el" href="group___crash_rpt_structs.html">CrashRpt Structures</a></li><li><a class="el" href="group___crash_rpt_wrappers.html">CrashRpt Wrapper Classes</a></li><li><a class="el" href="group___deprecated_a_p_i.html">Obsolete Functions</a></li></ul>
<h2><a class="anchor" name="using_crashrpt_api_faq">
FAQ</a></h2>
<b>I need to modify some crashrpt configuration info (i.e. uPriorities) based on information collected after <a class="el" href="group___crash_rpt_a_p_i.html#g24acb589d629460590d85735e12b5337" title="Character set-independent mapping of crInstallW() and crInstallA() functions.">crInstall()</a>. What is the best way ?</b><p>
Currently, there are no ways to modify the CrashRpt configuration info after calling <a class="el" href="group___crash_rpt_a_p_i.html#g24acb589d629460590d85735e12b5337" title="Character set-independent mapping of crInstallW() and crInstallA() functions.">crInstall()</a>. It is recommend to hardcode the info you pass to <a class="el" href="group___crash_rpt_a_p_i.html#g24acb589d629460590d85735e12b5337" title="Character set-independent mapping of crInstallW() and crInstallA() functions.">crInstall()</a> function, that means not reading it from an INI file or from another source.<p>
However, if you strongly wish to read crashrpt configuration info from an external file, call <a class="el" href="group___crash_rpt_a_p_i.html#g24acb589d629460590d85735e12b5337" title="Character set-independent mapping of crInstallW() and crInstallA() functions.">crInstall()</a> after reading the info from that file. Simple file reading functionality is not likely to crash. So the probability you miss a crash while reading the file is small.<p>
<b>We ship a software (game etc.) and certain crashes only happen on certain hardware. So we need some sort of functionality that gathers GPU/CPU/general hardware information upon crash report generation. What do we do?</b><p>
We introduced a function <a class="el" href="group___crash_rpt_a_p_i.html#g5bc9d5a06b3ef1bb62e61b109f890730" title="Character set-independent mapping of crAddPropertyW() and crAddPropertyA() functions...">crAddProperty()</a> specially for purposes of extending the crash description XML as you wish. You can also use the <a class="el" href="group___crash_rpt_a_p_i.html#g382c00cf76818ba1a66eb89715a030ea" title="Character set-independent mapping of crAddFile2W() and crAddFile2A() functions.">crAddFile2()</a> function, which allows to add a user-defined file to the crash report.<p>
<b>I want to uniquely identify the installation by what the error reports are sent. What do I do?</b><p>
In CrashRpt v.1.2.1, we introduced a function <a class="el" href="group___crash_rpt_a_p_i.html#g5bc9d5a06b3ef1bb62e61b109f890730" title="Character set-independent mapping of crAddPropertyW() and crAddPropertyA() functions...">crAddProperty()</a> specially for purposes of extending the crash description XML as you wish. You can create the installation GUID in your program, store it in the registry or in a file and pass this GUID to the <a class="el" href="group___crash_rpt_a_p_i.html#g5bc9d5a06b3ef1bb62e61b109f890730" title="Character set-independent mapping of crAddPropertyW() and crAddPropertyA() functions...">crAddProperty()</a> function, so the named property will be added to the crashrpt.xml and you will be able to identify the installation and associate the bugs together.<p>
The following code example shows how to do this (code provided by tdev):<p>
<div class="fragment"><pre class="fragment">  <span class="comment">// ... upon program start, check if GUID is not existing, if not create one:</span>
  GUID *g = <span class="keyword">new</span> GUID();
  CoCreateGuid(g);
  
  <span class="keywordtype">char</span> buf[120];
  sprintf( buf, <span class="stringliteral">"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"</span>,
    g-&gt;Data1, g-&gt;Data2, g-&gt;Data3, UINT(g-&gt;Data4[0]), UINT(g-&gt;Data4[1]), UINT(g-&gt;Data4[2]), 
    UINT(g-&gt;Data4[3]), UINT(g-&gt;Data4[4]), UINT(g-&gt;Data4[5]), UINT(g-&gt;Data4[6]), UINT(g-&gt;Data4[7]));
  <span class="keyword">delete</span> g;
  std::string guid = std::string(buf);

  <span class="comment">//... later, add it to the crashreport:</span>
  <a class="code" href="group___crash_rpt_a_p_i.html#g5bc9d5a06b3ef1bb62e61b109f890730" title="Character set-independent mapping of crAddPropertyW() and crAddPropertyA() functions...">crAddProperty</a>(<span class="stringliteral">"SystemGUID"</span>, guid);
</pre></div><p>
<b>My software's worker thread hangs up on user's machine (but no crash happens). How do I debug the problem?</b><p>
To collect information about such error, you may provide an ability to generate error report manually, for example on a key combination press. When the key combination is pressed, generate error report manually using <a class="el" href="group___crash_rpt_a_p_i.html#g60af60c28c64a1d3baa11f1220b9c3f4" title="Manually generates an errror report.">crGenerateErrorReport()</a> function.<p>
<b>What is the minidump type? What minidump type should I use?</b><p>
The minidump type defines what information is contained in the minidump. The default minidump type is <b>MiniDumpNormal</b>. However, the <b>MiniDumpNormal</b> type contains only essential info required to recover the stack traces for each thread. To recover the state of global variables, other minidump types should be used. For additional info, see the <a href="http://www.debuginfo.com/articles/effminidumps.html">Effective Minidumps</a> article. </div>
<hr size="1"><address style="text-align: right;"><small>Generated on Sat Oct 22 17:37:43 2011 for CrashRpt by&nbsp;
<a href="http://www.doxygen.org/index.html">
<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.9 </small></address>
</body>
</html>

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Russian Federation Russian Federation
I am a software developer currently living in Tomsk, Russia. I received a PhD degree in Computer Science from Tomsk Polytechnic University in 2010. I have been professionally developing C/C++ and PHP software since 2005. I like contributing to open-source and writing programming articles for popular web resources, like CodeProject. Besides writing, I love skiing and watching Formula-1.

Comments and Discussions