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