Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Integrating Crash Reporting into Your Application - A Beginners Tutorial

0.00/5 (No votes)
5 Feb 2012 2  
This article shows how to use CrashRpt error reporting library with an MFC application

CrashRptTutorial/errorreport.PNG

Introduction

If you are a software vendor, you might have faced the problem of fixing the crashes (critical errors, exceptions) of your app on user’s machine located on the other side of the globe. For example, assume a user writes you an email where he describes the error in your software. Of course, you are interested in making the user happy, so you start asking him to provide more information, to give a screenshot or an error message. The problem is that user has no technical knowledge and usually can’t provide you with as many details as you need to reproduce the crash. Typical users would just give up using your application if it crashes frequently and start using your competitor’s software (sounds sad).

So, what can be done to collect technical information about errors more easily? The answer is distributing a crash reporting library with your software, which would collect all required information about the problem and send the information to you (user just would need to provide his consent by pressing the “Send report” button). The technical information the crash reporting library would collect for you includes the following: the crash minidump file containing the call stack at the moment of crash helping you to see the line of code where exception had happened, screenshot of the desktop at the moment of crash helping you to see what button user had clicked and helping you reproduce the problem.

In this tutorial, I will show how to integrate one such an Open-source crash reporting library called CrashRpt with your application. You may be already interested if CrashRpt works with your application or not. If your application is written in C/C++ using Visual C++ .NET 2003, 2005, 2008, 2010 or Visual C++ Express, and if your app is WinAPI/ATL/WTL/MFC-based, the answer is yes. CrashRpt supports Win32 and Win64 processor architectures. It works in Windows 2000, XP, Vista and Windows 7.

For the demonstration, I use an MFC application, because I figured out that using CrashRpt with MFC may cause some confusion. For example, one problem MFC users experience is determining the right place in the code where to initialize the crash reporting library.

This article is aimed to be a beginner’s tutorial. The source code and binary files I use for demonstration are attached to the article. The code of CrashRpt library (v.1.3.0) is also attached, but it is recommended that you download the latest version from the external site.

In conclusion of the tutorial, I give some links for an interested reader who may want to become familiar with more advanced topics, like using CrashRpt in a multi-threaded application, sending error report over the Internet to an HTTP server, postprocessing error reports using a command line tool and so on.

Note: You may also refer to the Add Crash Reporting to Your Applications with the CrashRpt Library article by Mike Carruth, which is a little obsolete, but contains many interesting details of CrashRpt usage.

Integrating CrashRpt with your Application

First of all, we will create a simple document-view MFC application which always crashes when saving the document through File->Save menu.

Simple MFC Application

In this tutorial, we will create a very simple MFC application from scratch in Visual Studio 2005. To do this, we open Visual Studio window and then open menu File and select the New->Project… from the menu.

In the appeared New Project dialog, we choose MFC Application from the templates list and enter the SimpleApp name into the Name field and press the OK button. Then, when the MFC Application WizardSimpleApp dialog appears, we just click the Finish button to generate project files for the new SimpleApp application.

Now, we will add a code that would crash the application. Of course, we can insert such a bad code into any place of our application (as it happens in real life), but to make things simple, we will make our app crash when saving the document. To do so, in the SimpleAppDoc.cpp file, modify the CSimpleAppDoc::Serialize() method in the following way:

// CSimpleAppDoc serialization

void CSimpleAppDoc::Serialize(CArchive& ar)
{
  if (ar.IsStoring())
  {
    // TODO: add storing code here

    int* p = NULL;
    *p = 13;

  }
  else
  {
     // TODO: add loading code here
  }
} 

The method above contains NULL pointer assignment, which when executed, will raise an access violation exception.

Note: If you are interested to know what other code may crash your application, you can refer to the Making Your C++ Code Robust article.

Finally, we press F5 to compile and run the created application. The application window should appear (see the figure below).

CrashRptTutorial/image001.png

Figure 1 – SimpleApp MFC Application Window

To see what happens on crash, in the SimpleApp window, we open menu File and choose Save. We enter some file name and press the Save button. The application will terminate with an error message.

You can find the application we’ve just created attached to this tutorial (SimpleApp.zip archive).

Now, we will install the CrashRpt library. In this demo, we will use the latest version of CrashRpt available at the time of writing this tutorial - v.1.3.0.

Downloading CrashRpt

First, we should get the CrashRpt library source code. You can download the latest CrashRpt distribution archive from here. The archive uses 7z format, so we can unpack the archive with the 7zip tool. We unpack it to some folder, for example to C:\CrashRpt.

Note: The CrashRpt v.1.3.0 source code is also attached to this article, but it is recommended that you get the latest version from CrashRpt project website.

Let’s look inside the CrashRpt folder. It contains several subfolders and files.

The bin subfolder contains compiled CrashRpt binaries (CrashRpt1300.dll, CrashSender1300.exe and so on). CrashRpt consists of two core modules: CrashRpt1300.dll and CrashSender1300.exe. CrashRpt1300.dll contains functionality for intercepting exceptions in a client software. CrashSender1300.exe contains functionality for compressing and sending error reports to the software's support team. CrashRpt is separated into these modules to be able to close the application which have crashed and to continue sending the error report in CrashSender1300.exe in the background.

The include and lib subfolders contain header files and import library files. We will need these files later when compiling and linking the SimpleApp application.

The lang_files subfolder contains language INI files named like crashrpt_lang_XX.ini, where XX is a language abbreviation. The INI files contain localized strings for CrashRpt dialogs, so you can localize it to your favourite language.

The top-level folder contains file CrashRpt_vs2010.sln, which is the CrashRpt solution file for Visual Studio 2010. If you use Visual Studio 2010, you can double-click this file and refer to the Compiling CrashRpt section below. But in this tutorial, I will show how to generate CrashRpt solution file for an older version, Visual Studio 2005.

Generating CrashRpt Project Files in CMake

We will use CMake cross-platform make system to generate CrashRpt solution file very easily. If you don’t have CMake, download its installer from here and install CMake on your computer. I use the latest version at the moment, CMake 2.8.7.

Next, we will run the CMake-GUI wizard by opening menu Start and choosing CMake 2.8->CMake (cmake-gui). The CMake dialog should appear. In the dialog, we need to provide the path to folder where we've unpacked the CrashRpt archive (in our case, C:\CrashRpt). Enter this path into the “Where is the source code: and Where to build the binaries: fields as shown in the figure below and press the Configure button.

CrashRptTutorial/image003.png

Figure 2 – Generating CrashRpt Project Files for Visual Studio 2005 with CMake

The generator selection dialog appears where we need to select Visual Studio 8 2005 from the drop-down list and press the Finish button. Then press the Generate button. If everything is OK, you should see the “Generating done” message. Now, go to C:\CrashRpt folder and you should be able to see the CrashRpt.sln file. Double-click the file to open it in Visual Studio.

Compiling CrashRpt

Compiling CrashRpt yourself is strongly recommended if you want CrashRpt to handle exceptions that may occur in C run-time (CRT) libraries. CrashRpt distribution archive already contains compiled CrashRpt binaries, but it is not recommended to use them with your software, because your software may use different C run-time DLLs, and CrashRpt won't be able to intercept exceptions in your C run-time libraries.

Compiling CrashRpt is very straightforward – you just need to select Release configuration and press F7. If everything is OK, you should be able to find CrashRpt binaries in the bin subfolder.

Using CrashRpt API

Now, we add CrashRpt include and lib folders to the Visual Studio search path to let Visual C++ compiler and linker know about the location of CrashRpt include and lib files.We accomplish this by opening menu Tools-> Options in Visual Studio window. Then in appeared dialog, we select Projects and Solutions->VC++ Directories. Finally, in the Show directories for combo box, select Include files, then add the path to C:\CrashRpt\include directory to the list. In the Show directories for combo box, select Library files, then add the path to C:\CrashRpt\lib directory to the list.

To be able to use CrashRpt API functions, we include CrashRpt.h header file at the beginning of the SimpleApp.cpp file.

#include <CrashRpt.h>  

When application starts, we need to initialize CrashRpt. We do this by inserting some CrashRpt functions into the SimpleApp application code. But we need to insert them into the right place which is called CWinApp::Run() method. We insert the following code into the SimpleApp.cpp file:

int CSimpleAppApp::Run() 
{
  BOOL bRun;
  BOOL bExit=FALSE;
  while(!bExit)
  {
    bRun= CWinApp::Run();
    bExit=TRUE;
  }
  return bRun;
} 

We have overridden the CWinApp::Run() method. The CWinApp::Run() method is called when an MFC application starts, so this is the right place to initialize CrashRpt.

Next, we initialize CrashRpt by calling the crInstall() function and pass it the configuration parameters through CR_INSTALL_INFO structure. Below our Run() method with inserted CrashRpt API functions is presented:

int CSimpleAppApp::Run() 
{
  // Install crash reporting
 
  CR_INSTALL_INFO info;
  memset(&info, 0, sizeof(CR_INSTALL_INFO));
  info.cb = sizeof(CR_INSTALL_INFO);  
  info.pszAppName = _T("SimpleAp"); // Define application name.
  info.pszAppVersion = _T("1.0.0"); // Define application version.
  // URL for sending error reports over HTTP.
  info.pszUrl = _T("http://someserver.com/crashrpt.php");                    
  // Install all available exception handlers.
  info.dwFlags |= CR_INST_ALL_POSSIBLE_HANDLERS; 
  // Use binary encoding for HTTP uploads (recommended).
  info.dwFlags |= CR_INST_HTTP_BINARY_ENCODING;     
  // Provide privacy policy URL
  info.pszPrivacyPolicyURL = _T("http://someserver.com/privacy.html");

  int nResult = crInstall(&info);
  if(nResult!=0)
  {
    TCHAR buff[256];
    crGetLastErrorMsg(buff, 256);
    MessageBox(NULL, buff, _T("crInstall error"), MB_OK);
    return 1;
  }

  // Take screenshot of the app window at the moment of crash
  crAddScreenshot2(CR_AS_MAIN_WINDOW|CR_AS_USE_JPEG_FORMAT, 95);

  BOOL bRun;
  BOOL bExit=FALSE;
  while(!bExit)
  {
    bRun= CWinApp::Run();
    bExit=TRUE;
  }

  // Uninstall crash reporting
  crUninstall();

  return bRun;
} 

In the code above, we install all available exception handlers into the application. We specify the application name and version, because this information is needed to identify the application that sends the report. We provide an URL for transferring the error report to an HTTP server using the binary transfer encoding. We also provide a privacy policy URL.

We also call the crAddScreenshot2() function. We tell it to add a screenshot of the application window to the error report. The screenshot image will use compressed JPEG format with 95% quality to reduce image size.

Finally, we call crUninstall() function before exiting from Run() method to deinitialize the library.

Ok, now we need to add CrashRpt1300.lib to the list of input libraries for the project. In the Solution Explorer window, right-click the project node and choose Properties item from the context menu. Then open Configuration Properties->Linker->Input->Additional Dependencies and then add CrashRpt1300.lib to the list of libraries.

Select the Release build configuration and press F7 to build the project.

Running the Application

We are almost ready to run the SimpleApp application. But before we do this, we should copy the following files from C:\CrashRpt\bin folder to the folder where the application executable file is located:

CrashRpt1300.dll
CrashSender1300.exe
dbghelp.dll
crashrpt_lang.ini  

These files are required for CrashRpt to work properly. The files CrashRpt1300.dll and CrashSender1300.exe are core CrashRpt modules. The dbghelp.dll file is the Microsoft Debug Help Library, CrashRpt depends on this module. The crashrpt_lang.ini file contains localized strings for CrashRpt dialogs, so you can localize it to your favourite language.

When files have been copied, run the SimpleApp.exe file. In the appeared SimpleApp window, open menu File and choose Save from the menu. Enter some file name and press the Save button. When the access violation happens, you should see a nice-looking CrashRpt Error Report window as shown in the figure below.

CrashRptTutorial/errorreport.PNG

Figure 3 – Error Report Window

Let's review what is displayed on the Error Report window.

The Privacy Policy link allows to see the privacy policy we use when collecting data from user. The privacy policy typically states we use the data to improve the software and we do not sell or otherwise transfer the data to third parties.

We see that the report contains 165 KB of data. This is rather small and acceptable for transferring over the Internet. CrashRpt library can transfer the data as a request to HTTP server or as an e-mail message with attachments. The recipient receives the error report as a compressed ZIP archive containing several files.

To send the generated error report to the HTTP server you have specified, press the Send report button. If you do not want to send the report, press Close the program button. Note that in this tutorial, I do not show how to send error report over the Internet, you should provide a real recipient's address to send error reports as E-mail and/or configure a server-side script to send error reports over HTTP connection.

By clicking the What does this report contain? link, you may review the contents of the generated error report. In the figure below, you can see that the report we’ve generated contains three files: crashdump.dmp (crash minidump), crashrpt.xml (crash description XML) and screenshot0.jpg (desktop screenshot).

CrashRptTutorial/details.png

Figure 4 – Error Report Details Dialog

The crash minidump file can be used to debug the crash. You can double-click the crashdump.dmp file to open it in Visual Studio and see the line of the code where exception had happened.

There is also a nice-looking HEX, text or image preview for each file in the error report. The figure below displays a preview of the JPEG screenshot of our app's window that may be useful to reproduce the crash.

CrashRptTutorial/details_screenshot.PNG

Figure 5 - Desktop Screenshot Preview

Conclusion

Crash reporting allows you to automatically collect technical information about errors in your software to later postprocess the information on the developer’s side. In this tutorial, I’ve demonstrated how to integrate the CrashRpt crash reporting library into an MFC application.

This tutorial is very simple, and intended for beginners. In this tutorial, I haven’t covered the advanced topics of installing CrashRpt into a multi-threaded application, adding custom files to the error report, sending error reports over the Internet as an E-mail message or as a request to an HTTP server and analyzing arriving error reports using a command-line tool. An interested reader may find more information on these and other topics in CrashRpt online documentation.

For those who want to better understand exception handling in Visual C++, I would recommend the article Effective Exception Handling in Visual C++, where I describe in detail how CrashRpt catches exceptions in a C++ program. If you are interested to learn how the HEX file preview shown in the figure above works, you can refer to the article FilePreviewCtrl – Preview Files in Text, HEX and Image Format.

History

  • 1st January, 2012 - Initial release

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here