PageRenderTime 24ms CodeModel.GetById 10ms app.highlight 6ms RepoModel.GetById 1ms app.codeStats 0ms

/docs/dox/simple_example.dox

http://crashrpt.googlecode.com/
Unknown | 419 lines | 330 code | 89 blank | 0 comment | 0 complexity | 7c71dd3d64e7da0fa7734dfa9469c9e8 MD5 | raw file
  1/*!
  2
  3\page simple_example An Example of Using CrashRpt API
  4
  5The following example shows how to use CrashRpt API functions and structures 
  6to enable crash reporting support in a console C++ application. We use console 
  7application for simplicity, but in general the application may be WinAPI/MFC/ATL/WTL 
  8based, as well. For additional information on CrashRpt API functions and structures, 
  9please refer to \ref using_crashrpt_api.
 10
 11First create a console Win32 application and call it MyApp. Then configure the MyApp application
 12as described in \ref configuring_project.
 13
 14Let's assume the case when MyApp application has two threads. The first thread, the application thread,
 15will be the main one. The \b main() function will be executed in this thread and interaction with user
 16will also be performed in this thread. The second thread, the worker thread, is 
 17typically used when some time-consuming computational work is to be done without blocking the application thread.
 18
 19The MyApp application will create a log file that will be included in error report on crash. The
 20log file is typically helpful when debugging a crash.
 21
 22Let's create the code template.
 23
 24\code
 25
 26#include <windows.h>
 27#include <stdio.h>
 28#include <tchar.h>
 29
 30FILE* g_hLog = NULL; // Global handle to the application log file
 31
 32// The following function writes an entry to the log file
 33void log_write(LPCTSTR szFormat, ...)
 34{
 35  if (g_hLog == NULL) 
 36    return; // Log file seems to be closed
 37
 38  va_list args;
 39  va_start(args); 
 40  _vftprintf_s(g_hLog, szFormat, args);
 41  fflush(g_hLog);
 42}
 43
 44// Thread procedure
 45DWORD WINAPI ThreadProc(LPVOID lpParam)
 46{
 47  log_write(_T("Entering the thread proc\n"));
 48
 49  // Define the infinite loop where some processing will be done 
 50  for(;;)
 51  {
 52    // There is a hidden error somewhere inside of the loop...
 53    int* p = NULL;
 54    *p = 13; // This results in Access Violation
 55  }    
 56   
 57  log_write(_T("Leaving the thread proc\n"));
 58
 59  return 0;
 60}
 61
 62int _tmain(int argc, _TCHAR* argv[])
 63{
 64  // Open log file
 65  errno_t err = _tfopen_s(&g_hLog, _T("log.txt"), _T("wt"));
 66  if(err!=0 || g_hLog==NULL)
 67  {
 68    _tprintf_s(_T("Error opening log.txt\n"));
 69    return 1; // Couldn't open log file
 70  }
 71
 72  log_write(_T("Started successfully\n"));
 73
 74  // Create the worker thread
 75  HANDLE hWorkingThread = CreateThread(NULL, 0, 
 76           ThreadProc, (LPVOID)NULL, 0, NULL);
 77
 78  log_write(_T("Created working thread\n"));
 79
 80  // There is a hidden error in the main() function
 81  // Call of _tprintf_s with NULL parameter
 82  TCHAR* szFormatString = NULL;
 83  _tprintf_s(szFormatString);
 84
 85  // Wait until the worker thread is exited
 86  WaitForSingleObject(hWorkingThread, INFINITE);
 87
 88  log_write(_T("Working thread has exited\n"));
 89
 90  // Close the log file
 91  if(g_hLog!=NULL)
 92  {
 93    fclose(g_hLog);
 94    g_hLog = NULL;// Clean up handle
 95  }
 96
 97  // Exit
 98  return 0;
 99}
100
101\endcode
102
103We intentionally inserted the code that would cause an exception in both threads. In real-life
104programs such a code always exists, even when you test your application very carefully.
105
106To enable crash reporting support in the application, we need to include CrashRpt 
107header in the beginning of the code:
108
109\code
110// Include CrashRpt Header 
111#include "CrashRpt.h"
112\endcode
113
114Next, we define the crash callback function and call it \b CrashCallback().
115The crash callback function will be called by CrashRpt when crash occurs, so we will
116be able to close the handle to log file.
117For more information on crash callback, see the the \ref PFNCRASHCALLBACK()
118prototype.
119
120\code
121// Define the callback function that will be called on crash
122int CALLBACK CrashCallback(CR_CRASH_CALLBACK_INFO* pInfo)
123{  
124  // The application has crashed!
125
126  // Close the log file here
127  // to ensure CrashRpt is able to include it into error report
128  if(g_hLog!=NULL)
129  {
130    fclose(g_hLog);
131    g_hLog = NULL;// Clean up handle
132  }
133
134  // Return CR_CB_DODEFAULT to generate error report
135  return CR_CB_DODEFAULT;
136}
137\endcode
138
139Because we have a multi-threaded application, we need to use some \ref CrashRptAPI
140to set exception handlers for the worker thread. In this example, we use the \ref
141crInstallToCurrentThread2() and \ref crUninstallFromCurrentThread() functions to
142set exception handlers in the beginning of the thread procedure and unset them
143in the end of the thread procedure, respectively.
144
145\code
146// Thread procedure
147DWORD WINAPI ThreadProc(LPVOID lpParam)
148{
149  // Install exception handlers for this thread
150  crInstallToCurrentThread2(0);
151
152  ...
153
154  // Unset exception handlers before exiting the thread
155  crUninstallFromCurrentThread();    
156
157  return 0;
158}    
159\endcode
160
161Next, in the beginning of the \b main() function, we initialize the CrashRpt library    
162and install the exception handlers for the entire process with the help of crInstall()
163function and pass configuration information to it through the \ref CR_INSTALL_INFO structure.
164If something goes wrong, we can check the last error message with the \ref crGetLastErrorMsg()
165function.
166
167\code
168int _tmain(int argc, _TCHAR* argv[])
169{  
170  // Define CrashRpt configuration parameters
171  CR_INSTALL_INFO info;  
172  memset(&info, 0, sizeof(CR_INSTALL_INFO));  
173  info.cb = sizeof(CR_INSTALL_INFO);    
174  info.pszAppName = _T("MyApp");  
175  info.pszAppVersion = _T("1.0.0");  
176  info.pszEmailSubject = _T("MyApp 1.0.0 Error Report");  
177  info.pszEmailTo = _T("myapp_support@hotmail.com");    
178  info.pszUrl = _T("http://myapp.com/tools/crashrpt.php");  
179  info.uPriorities[CR_HTTP] = 3;  // First try send report over HTTP 
180  info.uPriorities[CR_SMTP] = 2;  // Second try send report over SMTP  
181  info.uPriorities[CR_SMAPI] = 1; // Third try send report over Simple MAPI    
182  // Install all available exception handlers
183  info.dwFlags |= CR_INST_ALL_POSSIBLE_HANDLERS;
184  // Restart the app on crash 
185  info.dwFlags |= CR_INST_APP_RESTART; 
186  info.dwFlags |= CR_INST_SEND_QUEUED_REPORTS; 
187  info.pszRestartCmdLine = _T("/restart");
188  // Define the Privacy Policy URL 
189  info.pszPrivacyPolicyURL = _T("http://myapp.com/privacypolicy.html"); 
190  
191  // Install crash reporting
192  int nResult = crInstall(&info);    
193  if(nResult!=0)  
194  {    
195    // Something goes wrong. Get error message.
196    TCHAR szErrorMsg[512] = _T("");        
197    crGetLastErrorMsg(szErrorMsg, 512);    
198    _tprintf_s(_T("%s\n"), szErrorMsg);    
199    return 1;
200  } 
201
202\endcode
203
204Next, we want to set the crash callback function by calling crSetCrashCallback().
205
206\code
207  // Set crash callback function
208  crSetCrashCallback(CrashCallback, NULL);
209\endcode
210
211Next, we want to add our error log file to the crash report. We do this
212with the crAddFile2() function.
213
214\code
215  // Add our log file to the error report
216  crAddFile2(_T("log.txt"), NULL, _T("Log File"), CR_AF_MAKE_FILE_COPY);    
217\endcode
218
219When the app crashes, we can include the screen shot to the crash report.
220We do this with the crAddScreenshot2() function.
221
222\code
223  // We want the screenshot of the entire desktop is to be added on crash
224  crAddScreenshot2(CR_AS_VIRTUAL_SCREEN, 0);   
225\endcode
226
227The following code adds a named property to the crash description XML file
228(see the crAddProperty() function). The property tells what graphics adapter
229is installed on end user's computer (for simplicity, it is hardcoded, but
230you usually determine adapter's model dynamically using Windows Management 
231Instrumentation, shortly WMI).
232
233\code
234  // Add a named property that means what graphics adapter is
235  // installed on end user's machine
236  crAddProperty(_T("VideoCard"), _T("nVidia GeForce 8600 GTS"));
237\endcode
238
239In the end of the \b main() function, we uninitialize CrashRpt and
240unset the exception handlers using the crUninstall() function.
241
242\code
243  // Uninitialize CrashRpt before exiting the main function
244  crUninstall();
245
246\endcode
247
248Below we have it all in one piece of code:
249
250\code
251#include <windows.h>
252#include <stdio.h>
253#include <tchar.h>
254// Include CrashRpt Header 
255#include "CrashRpt.h"
256
257FILE* g_hLog = NULL; // Global handle to the application log file
258
259// Define the callback function that will be called on crash
260int CALLBACK CrashCallback(CR_CRASH_CALLBACK_INFO* pInfo)
261{  
262  // The application has crashed!
263
264  // Close the log file here
265  // to ensure CrashRpt is able to include it into error report
266  if(g_hLog!=NULL)
267  {
268    fclose(g_hLog);
269    g_hLog = NULL;// Clean up handle
270  }
271
272  // Return CR_CB_DODEFAULT to generate error report
273  return CR_CB_DODEFAULT;
274}
275
276// The following function writes an entry to the log file
277void log_write(LPCTSTR szFormat, ...)
278{
279  if (g_hLog == NULL) 
280    return; // Log file seems to be closed
281
282  va_list args; 
283  va_start(args); 
284  _vftprintf_s(g_hLog, szFormat, args);
285  fflush(g_hLog);
286}
287
288// Thread procedure
289DWORD WINAPI ThreadProc(LPVOID lpParam)
290{
291  // Install exception handlers for this thread
292  crInstallToCurrentThread2(0);
293
294  log_write(_T("Entering the thread proc\n"));
295
296  // Define the infinite loop where some processing will be done 
297  for(;;)
298  {
299    // There is a hidden error somewhere inside of the loop...
300    int* p = NULL;
301    *p = 13; // This results in Access Violation
302  }    
303   
304  log_write(_T("Leaving the thread proc\n"));
305
306  // Unset exception handlers before exiting the thread
307  crUninstallFromCurrentThread();    
308
309  return 0;
310}
311
312int _tmain(int argc, _TCHAR* argv[])
313{  
314  // Define CrashRpt configuration parameters
315  CR_INSTALL_INFO info;  
316  memset(&info, 0, sizeof(CR_INSTALL_INFO));  
317  info.cb = sizeof(CR_INSTALL_INFO);    
318  info.pszAppName = _T("MyApp");  
319  info.pszAppVersion = _T("1.0.0");  
320  info.pszEmailSubject = _T("MyApp 1.0.0 Error Report");  
321  info.pszEmailTo = _T("myapp_support@hotmail.com");    
322  info.pszUrl = _T("http://myapp.com/tools/crashrpt.php");  
323  info.uPriorities[CR_HTTP] = 3;  // First try send report over HTTP 
324  info.uPriorities[CR_SMTP] = 2;  // Second try send report over SMTP  
325  info.uPriorities[CR_SMAPI] = 1; // Third try send report over Simple MAPI    
326  // Install all available exception handlers
327  info.dwFlags |= CR_INST_ALL_POSSIBLE_HANDLERS;
328  // Restart the app on crash 
329  info.dwFlags |= CR_INST_APP_RESTART; 
330  info.dwFlags |= CR_INST_SEND_QUEUED_REPORTS; 
331  info.pszRestartCmdLine = _T("/restart");
332  // Define the Privacy Policy URL 
333  info.pszPrivacyPolicyURL = _T("http://myapp.com/privacypolicy.html"); 
334  
335  // Install crash reporting
336  int nResult = crInstall(&info);    
337  if(nResult!=0)  
338  {    
339    // Something goes wrong. Get error message.
340    TCHAR szErrorMsg[512] = _T("");        
341    crGetLastErrorMsg(szErrorMsg, 512);    
342    _tprintf_s(_T("%s\n"), szErrorMsg);    
343    return 1;
344  } 
345
346  // Set crash callback function
347  crSetCrashCallback(CrashCallback, NULL);
348
349  // Add our log file to the error report
350  crAddFile2(_T("log.txt"), NULL, _T("Log File"), CR_AF_MAKE_FILE_COPY);    
351
352  // We want the screenshot of the entire desktop is to be added on crash
353  crAddScreenshot2(CR_AS_VIRTUAL_SCREEN, 0);   
354
355  // Add a named property that means what graphics adapter is
356  // installed on user's machine
357  crAddProperty(_T("VideoCard"), _T("nVidia GeForce 8600 GTS"));
358
359  // The main code follows...
360
361  // Open log file
362  errno_t err = _tfopen_s(&g_hLog, _T("log.txt"), _T("wt"));
363  if(err!=0 || g_hLog==NULL)
364  {
365    _tprintf_s(_T("Error opening log.txt\n"));
366    return 1; // Couldn't open log file
367  }
368
369  log_write(_T("Started successfully\n"));
370
371  // Create the worker thread
372  HANDLE hWorkingThread = CreateThread(NULL, 0, 
373           ThreadProc, (LPVOID)NULL, 0, NULL);
374
375  log_write(_T("Created working thread\n"));
376
377  // There is a hidden error in the main() function
378  // Call of _tprintf_s with NULL parameter
379  TCHAR* szFormatString = NULL;
380  _tprintf_s(szFormatString);
381
382  // Wait until the worker thread is exited
383  WaitForSingleObject(hWorkingThread, INFINITE);
384
385  log_write(_T("Working thread has exited\n"));
386
387  // Close the log file
388  if(g_hLog!=NULL)
389  {
390    fclose(g_hLog);
391    g_hLog = NULL;// Clean up handle
392  }
393
394  // Uninitialize CrashRpt before exiting the main function
395  crUninstall();
396
397  // Exit
398  return 0;
399}
400\endcode
401
402Do not forget to add <b>CrashRptXXXX.lib</b> file to the list of input libraries of your project 
403(XXXX is the placeholder for the version of CrashRpt). For additional info, see \ref configuring_project.
404
405Before running the application, you should place the following files to the directory 
406where your application executable file is located (for additional information, 
407see \ref preparing_to_software_release):
408                                                                              
409- \b CrashRptXXXX.dll (here and below XXXX should be replaced with the actual version of CrashRpt)
410- \b CrashSenderXXXX.exe
411- \b dbghelp.dll
412- \b crashrpt_lang.ini 
413
414When files have been copied, run the application. As error occurs, you should be able to see an
415error report window (for additional information, see \ref error_report)
416
417<i>Further reading:</i> \ref internationalization_support.
418
419*/