Click here to Skip to main content
Click here to Skip to main content

Integrating Crash Reporting into Your Application - A Beginners Tutorial

, 5 Feb 2012
Rate this:
Please Sign up or sign in to vote.
This article shows how to use CrashRpt error reporting library with an MFC application

errorreport.PNG

Introduction

If you are a software vendor, you might have faced with 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 comptetitor’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 Wizard – SimpleApp 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 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 rise an access violation exception.

Note: If you are interested to know what else 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).

Figure 1 – SimpleApp MFC Application Window

image001.png

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 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.

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

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 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 in 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 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 info 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 it the figure below.

Figure 3 – Error Report Window

errorreport.PNG

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 recieves 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).

Figure 4 – Error Report Details Dialog

details.png

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.

Figure 5 - Desktop Screenshot Preview

details_screenshot.PNG

Conclusion

Crash reporting allows you to automatically collect technical information about errors in your software to later postprocess the info on 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 details how CrashRpt catches exceptions in a C++ program. If you are interested to learn how the HEX file preview shown on the figure above works, you can refer to the article FilePreviewCtrl – Preview Files in Text, HEX and Image Format.

History

January 1st 2012 - Initial release

License

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

Share

About the Author

OlegKrivtsov

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.
Follow on   Twitter

Comments and Discussions

 
Question5 star PinmemberReturnVoid28-Jul-14 18:51 
GeneralMy vote of 3 PinmemberThomas Mielke13-May-14 1:18 
QuestionHats Off Pinmembervaibhavbvp21-Mar-14 19:19 
Questionunresolved external symbol __imp__MessageBoxA@16 referenced in function _main PinmemberMartin.Cheng31-Oct-13 22:47 
QuestionGreat Pinmemberfulminatorz12-Feb-13 4:28 
GeneralMy vote of 5 PinmemberJai Deo Tiwari18-Oct-12 1:57 
QuestionWont catch errors outside my main MFC project PinmemberMarkoAP3-Aug-12 3:16 
AnswerRe: Wont catch errors outside my main MFC project PinmemberMarkoAP6-Aug-12 3:01 
GeneralRe: Wont catch errors outside my main MFC project PinmemberThomas Mielke13-May-14 1:12 
QuestionNow it support SMTP authentication, Pinmembermaplewang6-Apr-12 1:17 
BugVery nice, but does not always work PinmemberIgor Okulist13-Mar-12 20:53 
GeneralRe: Very nice, but does not always work Pinmembernamezero1111111-Oct-12 23:28 
GeneralMy vote of 5 PinmemberMihai MOGA8-Feb-12 6:47 
Questiongood Pinmemberstonexin30-Jan-12 14:09 
GeneralMy vote of 5 PinmemberShahin Khorshidnia2-Jan-12 22:46 
QuestionSimilar tutorial Pinmemberbalexandre1-Jan-12 23:11 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140821.2 | Last Updated 5 Feb 2012
Article Copyright 2012 by OlegKrivtsov
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid