Sync DrDump crash handler with TortoiseSVN codebase
[TortoiseGit.git] / ext / CrashServer / CrashHandler / CrashHandler / CrashHandler.h
blob85f767a198f282e277c4683d7bb02794de13fa21
1 // Copyright 2014 Idol Software, Inc.
2 //
3 // This file is part of Doctor Dump SDK.
4 //
5 // Doctor Dump SDK is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Lesser General Public License for more details.
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #ifndef __CRASH_HANDLER_H__
19 #define __CRASH_HANDLER_H__
21 #include <windows.h>
23 #if defined(CRASHHANDLER_ENABLE_RELEASE_ASSERTS)
24 # include <assert.h>
25 # ifndef _DEBUG
26 # undef assert
27 //! When _DEBUG macro is defined works as standard assert macro from assert.h header.
28 //! When _DEBUG macro is not defined evaluates an expression and, when the result is false, sends report and continues execution.
29 //! To enable this redefined assert behavior define project wide \b CRASHHANDLER_ENABLE_RELEASE_ASSERTS macro and include CrashHandler.h in each translation unit as soon as possible.
30 //! \note All assert calls before CrashHandler.h inclusion would work as standard asserts.
31 # define assert(expr) ((void) (!(expr) && (SkipDoctorDump_ReportAssertionViolation<__COUNTER__>(__FUNCTION__ ": "#expr " is false" ), true)))
32 # endif // !_DEBUG
33 #endif // CRASHHANDLER_ENABLE_RELEASE_ASSERTS
35 namespace {
37 // This template should be in anonymous namespace since __COUNTER__ is unique only for a single translation unit (as anonymous namespace items)
38 template<unsigned uniqueAssertId>
39 __forceinline static void SkipDoctorDump_ReportAssertionViolation(LPCSTR dumpGroup)
41 static LONG volatile isAlreadyReported = FALSE;
42 if (TRUE == InterlockedCompareExchange(&isAlreadyReported, TRUE, FALSE))
43 return;
44 ::RaiseException(CrashHandler::ExceptionAssertionViolated, 0, 1, reinterpret_cast<ULONG_PTR*>(&dumpGroup));
47 } // namespace {
49 //! Contains data that identifies your application.
50 struct ApplicationInfo
52 DWORD ApplicationInfoSize; //!< Size of this structure. Should be set to sizeof(ApplicationInfo).
53 LPCSTR ApplicationGUID; //!< GUID assigned to this application in form 00000000-0000-0000-0000-000000000000.
54 LPCSTR Prefix; //!< Prefix that will be used with the dump name: YourPrefix_v1.v2.v3.v4_YYYYMMDD_HHMMSS.mini.dmp.
55 LPCWSTR AppName; //!< Application name that will be shown in message box.
56 LPCWSTR Company; //!< Company name that will be shown in message box.
57 USHORT V[4]; //!< Version of this application.
58 USHORT Hotfix; //!< Version of hotfix for this application (reserved for future use, should be 0).
59 LPCWSTR PrivacyPolicyUrl; //!< URL to privacy policy. If NULL default privacy policy is used.
62 //! \brief Contains crash handling behavior customization parameters.
63 //!
64 //! Default values for all parameters is 0/FALSE.
65 struct HandlerSettings
67 DWORD HandlerSettingsSize; //!< Size of this structure. Should be set to sizeof(HandlerSettings).
68 BOOL LeaveDumpFilesInTempFolder; //!< To leave error reports in temp folder you should set this member to TRUE. Your support or test lab teams can use that reports later.
69 BOOL OpenProblemInBrowser; //!< To open Web-page belonging to the uploaded report after it was uploaded set this member to TRUE. It is useful for test lab to track the bug or write some comments.
70 BOOL UseWER; //!< To continue use Microsoft Windows Error Reporting (WER) set this member to TRUE. In that case after Doctor Dump send report dialog Microsoft send report dialog also will be shown. This can be necessary in case of Windows Logo program.
71 DWORD SubmitterID; //!< Doctor Dump user ID. Uploaded report will be marked as uploaded by this user. This is useful for Doctor Dump and bug tracking system integration. Set to \b 0 if user using this application is anonymous.
72 BOOL SendAdditionalDataWithoutApproval; //!< To automatically accepted the question "Do you want to send more information about the problem?" set this member to TRUE .
73 BOOL OverrideDefaultFullDumpType;//!< To override default type of data gathered by the library set this member to TRUE and set required type of data in \a FullDumpType.
74 DWORD FullDumpType; //!< The type of information to be generated when full dump is requested by Doctor Dump. This parameter can be one or more of the values from the MINIDUMP_TYPE enumeration.
75 LPCWSTR LangFilePath; //!< To customize localization set this member to the path to the language file (including file name).
76 LPCWSTR SendRptPath; //!< Set this member to NULL to use default behavior when SendRpt is named sendrpt.exe and exist in same folder with crshhndl.dll. Set full path in other cases.
77 LPCWSTR DbgHelpPath; //!< Set this member to NULL to use default behavior when DbgHelp is named dbghelp.dll and exist in same folder with crshhndl.dll. Set full path in other cases.
78 //!< \note You should use dbghelp.dll that distributed with crshhndl.dll and not the one in Windows\\System32 folder, because only that dll supports all needed functionality. See <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms679294(v=vs.85).aspx">DbgHelp Versions</a> for more information.
81 //! \brief To enable crash processing you should create an instance of this class.
82 //!
83 //! It should be created as global static object and correctly initialized.
84 //! Also you may instantiate it in your main() or WinMain() function as soon as possible.
85 class CrashHandler
87 public:
88 //! \example Sample.cpp
89 //! This is an example of how to use the CrashHandler class.
91 //! CrashHandler constructor. Loads crshhndl.dll and initializes crash handling.
92 //! \note The crshhndl.dll is allowed to be missing. In that case there will be no crash handling.
93 CrashHandler(
94 LPCSTR applicationGUID, //!< [in] GUID assigned to this application.
95 LPCWSTR appName, //!< [in] Application name that will be shown in message box.
96 LPCWSTR company //!< [in] Company name that will be shown in message box.
97 ) throw()
99 if (!LoadDll())
100 return;
102 InitCrashHandler(applicationGUID, NULL, appName, company, TRUE);
105 //! CrashHandler constructor. Loads crshhndl.dll and initializes crash handling.
106 //! \note The crshhndl.dll is allowed to be missing. In that case there will be no crash handling.
107 CrashHandler(
108 LPCSTR applicationGUID, //!< [in] GUID assigned to this application.
109 LPCSTR prefix, //!< [in] Prefix that will be used with the dump name: YourPrefix_v1.v2.v3.v4_YYYYMMDD_HHMMSS.mini.dmp.
110 LPCWSTR appName, //!< [in] Application name that will be shown in message box.
111 LPCWSTR company, //!< [in] Company name that will be shown in message box.
112 BOOL ownProcess = TRUE //!< [in] If you own the process your code running in set this option to \b TRUE. If don't (for example you write
113 //!< a plugin to some external application) set this option to \b FALSE. In that case you need to explicitly
114 //!< catch exceptions. See \ref SendReport for more information.
115 ) throw()
117 if (!LoadDll())
118 return;
120 InitCrashHandler(applicationGUID, prefix, appName, company, ownProcess);
123 //! CrashHandler constructor. Loads crshhndl.dll and initializes crash handling.
124 //! \note The crshhndl.dll is allowed to be missing. In that case there will be no crash handling.
125 CrashHandler(
126 LPCWSTR crashHandlerPath, //!< [in] Path to crshhndl.dll file. File may be renamed.
127 LPCSTR applicationGUID, //!< [in] GUID assigned to this application.
128 LPCSTR prefix, //!< [in] Prefix that will be used with the dump name: YourPrefix_v1.v2.v3.v4_YYYYMMDD_HHMMSS.mini.dmp.
129 LPCWSTR appName, //!< [in] Application name that will be shown in message box.
130 LPCWSTR company, //!< [in] Company name that will be shown in message box.
131 BOOL ownProcess = TRUE //!< [in] If you own the process your code running in set this option to \b TRUE. If don't (for example you write
132 //!< a plugin to some external application) set this option to \b FALSE. In that case you need to explicitly
133 //!< catch exceptions. See \ref SendReport for more information.
134 ) throw()
136 if (!LoadDll(crashHandlerPath))
137 return;
139 InitCrashHandler(applicationGUID, prefix, appName, company, ownProcess);
142 //! CrashHandler constructor. Loads crshhndl.dll and initializes crash handling.
143 //! \note The crshhndl.dll is allowed to be missing. In that case there will be no crash handling.
144 CrashHandler(
145 ApplicationInfo* applicationInfo, //!< [in] Pointer to the ApplicationInfo structure that identifies your application.
146 HandlerSettings* handlerSettings, //!< [in] Pointer to the HandlerSettings structure that customizes crash handling behavior. This parameter can be \b NULL.
147 BOOL ownProcess = TRUE //!< [in] If you own the process your code running in set this option to \b TRUE. If don't (for example you write
148 //!< a plugin to some external application) set this option to \b FALSE. In that case you need to explicitly
149 //!< catch exceptions. See \ref SendReport for more information.
150 ) throw()
152 if (!LoadDll())
153 return;
155 InitCrashHandler(applicationInfo, handlerSettings, ownProcess);
158 //! CrashHandler constructor. Loads crshhndl.dll and initializes crash handling.
159 //! \note The crshhndl.dll is allowed to be missing. In that case there will be no crash handling.
160 CrashHandler(
161 LPCWSTR crashHandlerPath, //!< [in] Path to crshhndl.dll file. File may be renamed.
162 ApplicationInfo* applicationInfo, //!< [in] Pointer to the ApplicationInfo structure that identifies your application.
163 HandlerSettings* handlerSettings, //!< [in] Pointer to the HandlerSettings structure that customizes crash handling behavior. This parameter can be \b NULL.
164 BOOL ownProcess = TRUE //!< [in] If you own the process your code running in set this option to \b TRUE. If don't (for example you write
165 //!< a plugin to some external application) set this option to \b FALSE. In that case you need to explicitly
166 //!< catch exceptions. See \ref SendReport for more information.
167 ) throw()
169 if (!LoadDll(crashHandlerPath))
170 return;
172 InitCrashHandler(applicationInfo, handlerSettings, ownProcess);
176 //! CrashHandler constructor. Loads crshhndl.dll. You should call \ref InitCrashHandler to turn on crash handling.
177 //! \note The crshhndl.dll is allowed to be missing. In that case there will be no crash handling.
178 CrashHandler(
179 LPCWSTR crashHandlerPath = NULL //!< [in] Path to crshhndl.dll file. File may be renamed.
180 ) throw()
182 LoadDll(crashHandlerPath);
185 //! CrashHandler destructor.
186 //! \note It doesn't unload crshhndl.dll and doesn't disable crash handling since crash may appear on very late phase of application exit.
187 //! For example destructor of some static variable that is called after return from main() may crash.
188 ~CrashHandler()
190 if (!m_IsReadyToExit)
191 return;
193 // If crash has happen not in main thread we should wait here until report will be sent
194 // or else program will be terminated after return from main() and report sending will be halted.
195 while (!m_IsReadyToExit())
196 ::Sleep(100);
198 #if _WIN32_WINNT >= 0x0501 /*_WIN32_WINNT_WINXP*/
199 if (m_bSkipAssertsAdded)
200 RemoveVectoredExceptionHandler(SkipAsserts);
201 #endif
204 //! Checks that crash handling was enabled.
205 //! \return Return \b true if crash handling was enabled.
206 bool IsCrashHandlingEnabled() const
208 return m_bWorking;
211 //! Initializes crash handler.
212 //! \note You may call this function multiple times if some data has changed.
213 //! \return Return \b true if crash handling was enabled.
214 bool InitCrashHandler(
215 ApplicationInfo* applicationInfo, //!< [in] Pointer to the ApplicationInfo structure that identifies your application.
216 HandlerSettings* handlerSettings, //!< [in] Pointer to the HandlerSettings structure that customizes crash handling behavior. This parameter can be \b NULL.
217 BOOL ownProcess = TRUE //!< [in] If you own the process your code running in set this option to \b TRUE. If don't (for example you write
218 //!< a plugin to some external application) set this option to \b FALSE. In that case you need to explicitly
219 //!< catch exceptions. See \ref SendReport for more information.
220 ) throw()
222 if (!m_InitCrashHandler)
223 return false;
225 m_bWorking = m_InitCrashHandler(applicationInfo, handlerSettings, ownProcess) != FALSE;
227 return m_bWorking;
230 //! Initializes crash handler.
231 //! \note You may call this function multiple times if some data has changed.
232 //! \return Return \b true if crash handling was enabled.
233 bool InitCrashHandler(
234 LPCSTR applicationGUID, //!< [in] GUID assigned to this application.
235 LPCSTR prefix, //!< [in] Prefix that will be used with the dump name: YourPrefix_v1.v2.v3.v4_YYYYMMDD_HHMMSS.mini.dmp.
236 LPCWSTR appName, //!< [in] Application name that will be shown in message box.
237 LPCWSTR company, //!< [in] Company name that will be shown in message box.
238 BOOL ownProcess = TRUE //!< [in] If you own the process your code running in set this option to \b TRUE. If don't (for example you write
239 //!< a plugin to some external application) set this option to \b FALSE. In that case you need to explicitly
240 //!< catch exceptions. See \ref SendReport for more information.
241 ) throw()
243 if (!m_GetVersionFromApp)
244 return false;
246 ApplicationInfo appInfo;
247 memset(&appInfo, 0, sizeof(appInfo));
248 appInfo.ApplicationInfoSize = sizeof(appInfo);
249 appInfo.ApplicationGUID = applicationGUID;
250 appInfo.Prefix = prefix;
251 appInfo.AppName = appName;
252 appInfo.Company = company;
253 if (!m_GetVersionFromApp(&appInfo))
254 appInfo.V[0] = 1;
256 HandlerSettings handlerSettings;
257 memset(&handlerSettings, 0, sizeof(handlerSettings));
258 handlerSettings.HandlerSettingsSize = sizeof(handlerSettings);
259 handlerSettings.OpenProblemInBrowser = TRUE;
261 return InitCrashHandler(&appInfo, &handlerSettings, ownProcess);
264 //! \note This function is experimental and may not be available and may not be support by Doctor Dump in the future.
265 //! You may set custom information for your possible report.
266 //! This text will be available on Doctor Dump dumps page.
267 //! The text should not contain private information.
268 //! \return If the function succeeds, the return value is \b true.
269 bool SetCustomInfo(
270 LPCWSTR text //!< [in] custom info for the report. The text will be cut to 100 characters.
273 if (!m_SetCustomInfo)
274 return false;
275 m_SetCustomInfo(text);
276 return true;
279 //! You may add any key/value pair to crash report.
280 //! \return If the function succeeds, the return value is \b true.
281 //! \note This function is thread safe.
282 bool AddUserInfoToReport(
283 LPCWSTR key, //!< [in] key string that will be added to the report.
284 LPCWSTR value //!< [in] value for the key.
285 ) throw()
287 if (!m_AddUserInfoToReport)
288 return false;
289 m_AddUserInfoToReport(key, value);
290 return true;
293 //! You may remove any key that was added previously to crash report by \a AddUserInfoToReport.
294 //! \return If the function succeeds, the return value is \b true.
295 //! \note This function is thread safe.
296 bool RemoveUserInfoFromReport(
297 LPCWSTR key //!< [in] key string that will be removed from the report.
300 if (!m_RemoveUserInfoFromReport)
301 return false;
302 m_RemoveUserInfoFromReport(key);
303 return true;
306 //! You may add any file to crash report. This file will be read when crash appears and will be sent within the report.
307 //! Multiple files may be added. Filename of the file in the report may be changed to any name.
308 //! \return If the function succeeds, the return value is \b true.
309 //! \note This function is thread safe.
310 bool AddFileToReport(
311 LPCWSTR path, //!< [in] Path to the file, that will be added to the report.
312 LPCWSTR reportFileName /* = NULL */ //!< [in] Filename that will be used in report for this file. If parameter is \b NULL, original name from path will be used.
313 ) throw()
315 if (!m_AddFileToReport)
316 return false;
317 m_AddFileToReport(path, reportFileName);
318 return true;
321 //! Remove from report the file that was registered earlier to be sent within report.
322 //! \return If the function succeeds, the return value is \b true.
323 //! \note This function is thread safe.
324 bool RemoveFileFromReport(
325 LPCWSTR path //!< [in] Path to the file, that will be removed from the report.
326 ) throw()
328 if (!m_RemoveFileFromReport)
329 return false;
330 m_RemoveFileFromReport(path);
331 return true;
334 //! Fills version field (V) of ApplicationInfo with product version
335 //! found in the executable file of the current process.
336 //! \return If the function succeeds, the return value is \b true.
337 bool GetVersionFromApp(
338 ApplicationInfo* appInfo //!< [out] Pointer to ApplicationInfo structure. Its version field (V) will be set to product version.
339 ) throw()
341 if (!m_GetVersionFromApp)
342 return false;
343 return m_GetVersionFromApp(appInfo) != FALSE;
346 //! Fill version field (V) of ApplicationInfo with product version found in the file specified.
347 //! \return If the function succeeds, the return value is \b true.
348 bool GetVersionFromFile(
349 LPCWSTR path, //!< [in] Path to the file product version will be extracted from.
350 ApplicationInfo* appInfo //!< [out] Pointer to ApplicationInfo structure. Its version field (V) will be set to product version.
351 ) throw()
353 if (!m_GetVersionFromFile)
354 return false;
355 return m_GetVersionFromFile(path, appInfo) != FALSE;
358 //! If you do not own the process your code running in (for example you write a plugin to some
359 //! external application) you need to properly initialize CrashHandler using \b ownProcess option.
360 //! Also you need to explicitly catch all exceptions in all entry points to your code and in all
361 //! threads you create. To do so use this construction:
362 //! \code
363 //! bool SomeEntryPoint(PARAM p)
364 //! {
365 //! __try
366 //! {
367 //! return YouCode(p);
368 //! }
369 //! __except (CrashHandler::SendReport(GetExceptionInformation()))
370 //! {
371 //! ::ExitProcess(0); // It is better to stop the process here or else corrupted data may incomprehensibly crash it later.
372 //! return false;
373 //! }
374 //! }
375 //! \endcode
376 LONG SendReport(
377 EXCEPTION_POINTERS* exceptionPointers //!< [in] Pointer to EXCEPTION_POINTERS structure. You should get it using GetExceptionInformation()
378 //!< function inside __except keyword.
381 if (!m_SendReport)
382 return EXCEPTION_CONTINUE_SEARCH;
383 // There is no crash handler but asserts should continue anyway
384 if (exceptionPointers->ExceptionRecord->ExceptionCode == ExceptionAssertionViolated)
385 return EXCEPTION_CONTINUE_EXECUTION;
386 return m_SendReport(exceptionPointers);
389 //! To send a report about violated assertion you can throw exception with this exception code
390 //! using: \code RaiseException(CrashHandler::ExceptionAssertionViolated, 0, 0, NULL); \endcode
391 //! Execution will continue after report will be sent (EXCEPTION_CONTINUE_EXECUTION would be used).
392 //! You may pass grouping string as first parameter (see \a SkipDoctorDump_SendAssertionViolated).
393 //! \note If you called CrashHandler constructor and crshhndl.dll was missing you still may using this exception.
394 //! It will be catched, ignored and execution will continue. \ref SendReport function also works safely
395 //! when crshhndl.dll was missing.
396 static const DWORD ExceptionAssertionViolated = ((DWORD)0xCCE17000);
398 //! Sends assertion violation report from this point and continue execution.
399 //! \sa ExceptionAssertionViolated
400 //! \note Functions containing "SkipDoctorDump" will be ignored in stack parsing.
401 void SkipDoctorDump_SendAssertionViolated(
402 LPCSTR dumpGroup = NULL //!< [in] All dumps with that group will be separated from dumps with same stack but another group. Set parameter to \b NULL if no grouping is required.
403 ) const
405 if (!m_bWorking)
406 return;
407 if (dumpGroup)
408 ::RaiseException(CrashHandler::ExceptionAssertionViolated, 0, 1, reinterpret_cast<ULONG_PTR*>(&dumpGroup));
409 else
410 ::RaiseException(CrashHandler::ExceptionAssertionViolated, 0, 0, NULL);
413 private:
414 bool LoadDll(LPCWSTR crashHandlerPath = NULL) throw()
416 m_bLoaded = false;
417 m_bWorking = false;
418 m_bSkipAssertsAdded = false;
419 m_InitCrashHandler = NULL;
420 m_SendReport = NULL;
421 m_IsReadyToExit = NULL;
422 m_SetCustomInfo = NULL;
423 m_AddUserInfoToReport = NULL;
424 m_RemoveUserInfoFromReport = NULL;
425 m_AddFileToReport = NULL;
426 m_RemoveFileFromReport = NULL;
427 m_GetVersionFromApp = NULL;
428 m_GetVersionFromFile = NULL;
430 // hCrashHandlerDll should not be unloaded, crash may appear even after return from main().
431 // So hCrashHandlerDll is not saved after construction.
432 HMODULE hCrashHandlerDll = ::LoadLibraryW(crashHandlerPath ? crashHandlerPath : L"crshhndl.dll");
433 if (hCrashHandlerDll != NULL)
435 m_InitCrashHandler = (pfnInitCrashHandler) GetProcAddress(hCrashHandlerDll, "InitCrashHandler");
436 m_SendReport = (pfnSendReport) GetProcAddress(hCrashHandlerDll, "SendReport");
437 m_IsReadyToExit = (pfnIsReadyToExit) GetProcAddress(hCrashHandlerDll, "IsReadyToExit");
438 m_SetCustomInfo = (pfnSetCustomInfo) GetProcAddress(hCrashHandlerDll, "SetCustomInfo");
439 m_AddUserInfoToReport = (pfnAddUserInfoToReport) GetProcAddress(hCrashHandlerDll, "AddUserInfoToReport");
440 m_RemoveUserInfoFromReport = (pfnRemoveUserInfoFromReport) GetProcAddress(hCrashHandlerDll, "RemoveUserInfoFromReport");
441 m_AddFileToReport = (pfnAddFileToReport) GetProcAddress(hCrashHandlerDll, "AddFileToReport");
442 m_RemoveFileFromReport = (pfnRemoveFileFromReport) GetProcAddress(hCrashHandlerDll, "RemoveFileFromReport");
443 m_GetVersionFromApp = (pfnGetVersionFromApp) GetProcAddress(hCrashHandlerDll, "GetVersionFromApp");
444 m_GetVersionFromFile = (pfnGetVersionFromFile) GetProcAddress(hCrashHandlerDll, "GetVersionFromFile");
446 m_bLoaded = m_InitCrashHandler
447 && m_SendReport
448 && m_IsReadyToExit
449 && m_SetCustomInfo
450 && m_AddUserInfoToReport
451 && m_RemoveUserInfoFromReport
452 && m_AddFileToReport
453 && m_RemoveFileFromReport
454 && m_GetVersionFromApp
455 && m_GetVersionFromFile;
458 #if _WIN32_WINNT >= 0x0501 /*_WIN32_WINNT_WINXP*/
459 // if no crash processing was started, we need to ignore ExceptionAssertionViolated exceptions.
460 if (!m_bLoaded)
462 ::AddVectoredExceptionHandler(TRUE, SkipAsserts);
463 m_bSkipAssertsAdded = true;
465 #endif
467 return m_bLoaded;
470 static LONG CALLBACK SkipAsserts(EXCEPTION_POINTERS* pExceptionInfo)
472 if (pExceptionInfo->ExceptionRecord->ExceptionCode == ExceptionAssertionViolated)
473 return EXCEPTION_CONTINUE_EXECUTION;
474 return EXCEPTION_CONTINUE_SEARCH;
477 bool m_bLoaded;
478 bool m_bWorking;
479 bool m_bSkipAssertsAdded;
481 typedef BOOL (*pfnInitCrashHandler)(ApplicationInfo* applicationInfo, HandlerSettings* handlerSettings, BOOL ownProcess);
482 typedef LONG (*pfnSendReport)(EXCEPTION_POINTERS* exceptionPointers);
483 typedef BOOL (*pfnIsReadyToExit)();
484 typedef void (*pfnSetCustomInfo)(LPCWSTR text);
485 typedef void (*pfnAddUserInfoToReport)(LPCWSTR key, LPCWSTR value);
486 typedef void (*pfnRemoveUserInfoFromReport)(LPCWSTR key);
487 typedef void (*pfnAddFileToReport)(LPCWSTR path, LPCWSTR reportFileName /* = NULL */);
488 typedef void (*pfnRemoveFileFromReport)(LPCWSTR path);
489 typedef BOOL (*pfnGetVersionFromApp)(ApplicationInfo* appInfo);
490 typedef BOOL (*pfnGetVersionFromFile)(LPCWSTR path, ApplicationInfo* appInfo);
492 pfnInitCrashHandler m_InitCrashHandler;
493 pfnSendReport m_SendReport;
494 pfnIsReadyToExit m_IsReadyToExit;
495 pfnSetCustomInfo m_SetCustomInfo;
496 pfnAddUserInfoToReport m_AddUserInfoToReport;
497 pfnRemoveUserInfoFromReport m_RemoveUserInfoFromReport;
498 pfnAddFileToReport m_AddFileToReport;
499 pfnRemoveFileFromReport m_RemoveFileFromReport;
500 pfnGetVersionFromApp m_GetVersionFromApp;
501 pfnGetVersionFromFile m_GetVersionFromFile;
504 #endif // __CRASH_HANDLER_H__