Fixed issue #4126: Capitalize the first letter in the Push dialog
[TortoiseGit.git] / ext / CrashServer / CrashHandler / CrashHandler / CrashHandler.h
blobc094fa00b3a1387ab9e3631aa903f52719d8c785
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 //! Contains data that identifies your application.
36 struct ApplicationInfo
38 DWORD ApplicationInfoSize; //!< Size of this structure. Should be set to sizeof(ApplicationInfo).
39 LPCSTR ApplicationGUID; //!< GUID assigned to this application in form 00000000-0000-0000-0000-000000000000.
40 LPCSTR Prefix; //!< Prefix that will be used with the dump name: YourPrefix_v1.v2.v3.v4_YYYYMMDD_HHMMSS.mini.dmp.
41 LPCWSTR AppName; //!< Application name that will be shown in message box.
42 LPCWSTR Company; //!< Company name that will be shown in message box.
43 USHORT V[4]; //!< Version of this application.
44 USHORT Hotfix; //!< Version of hotfix for this application (reserved for future use, should be 0).
45 LPCWSTR PrivacyPolicyUrl; //!< URL to privacy policy. If NULL default privacy policy is used.
48 //! \brief Contains crash handling behavior customization parameters.
49 //!
50 //! Default values for all parameters is 0/FALSE.
51 struct HandlerSettings
53 DWORD HandlerSettingsSize; //!< Size of this structure. Should be set to sizeof(HandlerSettings).
54 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.
55 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.
56 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.
57 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.
58 BOOL SendAdditionalDataWithoutApproval; //!< To automatically accepted the question "Do you want to send more information about the problem?" set this member to TRUE .
59 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.
60 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.
61 LPCWSTR LangFilePath; //!< To customize localization set this member to the path to the language file (including file name).
62 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.
63 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.
64 //!< \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.
67 //! \brief To enable crash processing you should create an instance of this class.
68 //!
69 //! It should be created as global static object and correctly initialized.
70 //! Also you may instantiate it in your main() or WinMain() function as soon as possible.
71 class CrashHandler
73 public:
74 //! \example Sample.cpp
75 //! This is an example of how to use the CrashHandler class.
77 //! CrashHandler constructor. Loads crshhndl.dll and initializes crash handling.
78 //! \note The crshhndl.dll is allowed to be missing. In that case there will be no crash handling.
79 CrashHandler(
80 LPCSTR applicationGUID, //!< [in] GUID assigned to this application.
81 LPCWSTR appName, //!< [in] Application name that will be shown in message box.
82 LPCWSTR company //!< [in] Company name that will be shown in message box.
83 ) throw()
85 if (!LoadDll())
86 return;
88 InitCrashHandler(applicationGUID, NULL, appName, company, TRUE);
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 LPCSTR prefix, //!< [in] Prefix that will be used with the dump name: YourPrefix_v1.v2.v3.v4_YYYYMMDD_HHMMSS.mini.dmp.
96 LPCWSTR appName, //!< [in] Application name that will be shown in message box.
97 LPCWSTR company, //!< [in] Company name that will be shown in message box.
98 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
99 //!< a plugin to some external application) set this option to \b FALSE. In that case you need to explicitly
100 //!< catch exceptions. See \ref SendReport for more information.
101 ) throw()
103 if (!LoadDll())
104 return;
106 InitCrashHandler(applicationGUID, prefix, appName, company, ownProcess);
109 //! CrashHandler constructor. Loads crshhndl.dll and initializes crash handling.
110 //! \note The crshhndl.dll is allowed to be missing. In that case there will be no crash handling.
111 CrashHandler(
112 LPCWSTR crashHandlerPath, //!< [in] Path to crshhndl.dll file. File may be renamed.
113 LPCSTR applicationGUID, //!< [in] GUID assigned to this application.
114 LPCSTR prefix, //!< [in] Prefix that will be used with the dump name: YourPrefix_v1.v2.v3.v4_YYYYMMDD_HHMMSS.mini.dmp.
115 LPCWSTR appName, //!< [in] Application name that will be shown in message box.
116 LPCWSTR company, //!< [in] Company name that will be shown in message box.
117 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
118 //!< a plugin to some external application) set this option to \b FALSE. In that case you need to explicitly
119 //!< catch exceptions. See \ref SendReport for more information.
120 ) throw()
122 if (!LoadDll(crashHandlerPath))
123 return;
125 InitCrashHandler(applicationGUID, prefix, appName, company, ownProcess);
128 //! CrashHandler constructor. Loads crshhndl.dll and initializes crash handling.
129 //! \note The crshhndl.dll is allowed to be missing. In that case there will be no crash handling.
130 CrashHandler(
131 ApplicationInfo* applicationInfo, //!< [in] Pointer to the ApplicationInfo structure that identifies your application.
132 HandlerSettings* handlerSettings, //!< [in] Pointer to the HandlerSettings structure that customizes crash handling behavior. This parameter can be \b NULL.
133 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
134 //!< a plugin to some external application) set this option to \b FALSE. In that case you need to explicitly
135 //!< catch exceptions. See \ref SendReport for more information.
136 ) throw()
138 if (!LoadDll())
139 return;
141 InitCrashHandler(applicationInfo, handlerSettings, ownProcess);
144 //! CrashHandler constructor. Loads crshhndl.dll and initializes crash handling.
145 //! \note The crshhndl.dll is allowed to be missing. In that case there will be no crash handling.
146 CrashHandler(
147 LPCWSTR crashHandlerPath, //!< [in] Path to crshhndl.dll file. File may be renamed.
148 ApplicationInfo* applicationInfo, //!< [in] Pointer to the ApplicationInfo structure that identifies your application.
149 HandlerSettings* handlerSettings, //!< [in] Pointer to the HandlerSettings structure that customizes crash handling behavior. This parameter can be \b NULL.
150 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
151 //!< a plugin to some external application) set this option to \b FALSE. In that case you need to explicitly
152 //!< catch exceptions. See \ref SendReport for more information.
153 ) throw()
155 if (!LoadDll(crashHandlerPath))
156 return;
158 InitCrashHandler(applicationInfo, handlerSettings, ownProcess);
162 //! CrashHandler constructor. Loads crshhndl.dll. You should call \ref InitCrashHandler to turn on crash handling.
163 //! \note The crshhndl.dll is allowed to be missing. In that case there will be no crash handling.
164 CrashHandler(
165 LPCWSTR crashHandlerPath = NULL //!< [in] Path to crshhndl.dll file. File may be renamed.
166 ) throw()
168 LoadDll(crashHandlerPath);
171 //! CrashHandler destructor.
172 //! \note It doesn't unload crshhndl.dll and doesn't disable crash handling since crash may appear on very late phase of application exit.
173 //! For example destructor of some static variable that is called after return from main() may crash.
174 ~CrashHandler()
176 if (!m_IsReadyToExit)
177 return;
179 // If crash has happen not in main thread we should wait here until report will be sent
180 // or else program will be terminated after return from main() and report sending will be halted.
181 while (!m_IsReadyToExit())
182 ::Sleep(100);
184 #if _WIN32_WINNT >= 0x0501 /*_WIN32_WINNT_WINXP*/
185 if (m_bSkipAssertsAdded)
186 RemoveVectoredExceptionHandler(SkipAsserts);
187 #endif
190 //! Checks that crash handling was enabled.
191 //! \return Return \b true if crash handling was enabled.
192 bool IsCrashHandlingEnabled() const
194 return m_bWorking;
197 //! Initializes crash handler.
198 //! \note You may call this function multiple times if some data has changed.
199 //! \return Return \b true if crash handling was enabled.
200 bool InitCrashHandler(
201 ApplicationInfo* applicationInfo, //!< [in] Pointer to the ApplicationInfo structure that identifies your application.
202 HandlerSettings* handlerSettings, //!< [in] Pointer to the HandlerSettings structure that customizes crash handling behavior. This parameter can be \b NULL.
203 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
204 //!< a plugin to some external application) set this option to \b FALSE. In that case you need to explicitly
205 //!< catch exceptions. See \ref SendReport for more information.
206 ) throw()
208 if (!m_InitCrashHandler)
209 return false;
211 m_bWorking = m_InitCrashHandler(applicationInfo, handlerSettings, ownProcess) != FALSE;
213 return m_bWorking;
216 //! Initializes crash handler.
217 //! \note You may call this function multiple times if some data has changed.
218 //! \return Return \b true if crash handling was enabled.
219 bool InitCrashHandler(
220 LPCSTR applicationGUID, //!< [in] GUID assigned to this application.
221 LPCSTR prefix, //!< [in] Prefix that will be used with the dump name: YourPrefix_v1.v2.v3.v4_YYYYMMDD_HHMMSS.mini.dmp.
222 LPCWSTR appName, //!< [in] Application name that will be shown in message box.
223 LPCWSTR company, //!< [in] Company name that will be shown in message box.
224 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
225 //!< a plugin to some external application) set this option to \b FALSE. In that case you need to explicitly
226 //!< catch exceptions. See \ref SendReport for more information.
227 ) throw()
229 if (!m_GetVersionFromApp)
230 return false;
232 ApplicationInfo appInfo;
233 memset(&appInfo, 0, sizeof(appInfo));
234 appInfo.ApplicationInfoSize = sizeof(appInfo);
235 appInfo.ApplicationGUID = applicationGUID;
236 appInfo.Prefix = prefix;
237 appInfo.AppName = appName;
238 appInfo.Company = company;
239 if (!m_GetVersionFromApp(&appInfo))
240 appInfo.V[0] = 1;
242 HandlerSettings handlerSettings;
243 memset(&handlerSettings, 0, sizeof(handlerSettings));
244 handlerSettings.HandlerSettingsSize = sizeof(handlerSettings);
245 handlerSettings.OpenProblemInBrowser = TRUE;
247 return InitCrashHandler(&appInfo, &handlerSettings, ownProcess);
250 //! \note This function is experimental and may not be available and may not be support by Doctor Dump in the future.
251 //! You may set custom information for your possible report.
252 //! This text will be available on Doctor Dump dumps page.
253 //! The text should not contain private information.
254 //! \return If the function succeeds, the return value is \b true.
255 bool SetCustomInfo(
256 LPCWSTR text //!< [in] custom info for the report. The text will be cut to 100 characters.
259 if (!m_SetCustomInfo)
260 return false;
261 m_SetCustomInfo(text);
262 return true;
265 //! You may add any key/value pair to crash report.
266 //! \return If the function succeeds, the return value is \b true.
267 //! \note This function is thread safe.
268 bool AddUserInfoToReport(
269 LPCWSTR key, //!< [in] key string that will be added to the report.
270 LPCWSTR value //!< [in] value for the key.
271 ) throw()
273 if (!m_AddUserInfoToReport)
274 return false;
275 m_AddUserInfoToReport(key, value);
276 return true;
279 //! You may remove any key that was added previously to crash report by \a AddUserInfoToReport.
280 //! \return If the function succeeds, the return value is \b true.
281 //! \note This function is thread safe.
282 bool RemoveUserInfoFromReport(
283 LPCWSTR key //!< [in] key string that will be removed from the report.
286 if (!m_RemoveUserInfoFromReport)
287 return false;
288 m_RemoveUserInfoFromReport(key);
289 return true;
292 //! You may add any file to crash report. This file will be read when crash appears and will be sent within the report.
293 //! Multiple files may be added. Filename of the file in the report may be changed to any name.
294 //! \return If the function succeeds, the return value is \b true.
295 //! \note This function is thread safe.
296 bool AddFileToReport(
297 LPCWSTR path, //!< [in] Path to the file, that will be added to the report.
298 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.
299 ) throw()
301 if (!m_AddFileToReport)
302 return false;
303 m_AddFileToReport(path, reportFileName);
304 return true;
307 //! Remove from report the file that was registered earlier to be sent within report.
308 //! \return If the function succeeds, the return value is \b true.
309 //! \note This function is thread safe.
310 bool RemoveFileFromReport(
311 LPCWSTR path //!< [in] Path to the file, that will be removed from the report.
312 ) throw()
314 if (!m_RemoveFileFromReport)
315 return false;
316 m_RemoveFileFromReport(path);
317 return true;
320 //! Fills version field (V) of ApplicationInfo with product version
321 //! found in the executable file of the current process.
322 //! \return If the function succeeds, the return value is \b true.
323 bool GetVersionFromApp(
324 ApplicationInfo* appInfo //!< [out] Pointer to ApplicationInfo structure. Its version field (V) will be set to product version.
325 ) throw()
327 if (!m_GetVersionFromApp)
328 return false;
329 return m_GetVersionFromApp(appInfo) != FALSE;
332 //! Fill version field (V) of ApplicationInfo with product version found in the file specified.
333 //! \return If the function succeeds, the return value is \b true.
334 bool GetVersionFromFile(
335 LPCWSTR path, //!< [in] Path to the file product version will be extracted from.
336 ApplicationInfo* appInfo //!< [out] Pointer to ApplicationInfo structure. Its version field (V) will be set to product version.
337 ) throw()
339 if (!m_GetVersionFromFile)
340 return false;
341 return m_GetVersionFromFile(path, appInfo) != FALSE;
344 //! If you do not own the process your code running in (for example you write a plugin to some
345 //! external application) you need to properly initialize CrashHandler using \b ownProcess option.
346 //! Also you need to explicitly catch all exceptions in all entry points to your code and in all
347 //! threads you create. To do so use this construction:
348 //! \code
349 //! bool SomeEntryPoint(PARAM p)
350 //! {
351 //! __try
352 //! {
353 //! return YouCode(p);
354 //! }
355 //! __except (CrashHandler::SendReport(GetExceptionInformation()))
356 //! {
357 //! ::ExitProcess(0); // It is better to stop the process here or else corrupted data may incomprehensibly crash it later.
358 //! return false;
359 //! }
360 //! }
361 //! \endcode
362 LONG SendReport(
363 EXCEPTION_POINTERS* exceptionPointers //!< [in] Pointer to EXCEPTION_POINTERS structure. You should get it using GetExceptionInformation()
364 //!< function inside __except keyword.
367 if (!m_SendReport)
368 return EXCEPTION_CONTINUE_SEARCH;
369 // There is no crash handler but asserts should continue anyway
370 if (exceptionPointers->ExceptionRecord->ExceptionCode == ExceptionAssertionViolated)
371 return EXCEPTION_CONTINUE_EXECUTION;
372 return m_SendReport(exceptionPointers);
375 //! To send a report about violated assertion you can throw exception with this exception code
376 //! using: \code RaiseException(CrashHandler::ExceptionAssertionViolated, 0, 0, NULL); \endcode
377 //! Execution will continue after report will be sent (EXCEPTION_CONTINUE_EXECUTION would be used).
378 //! You may pass grouping string as first parameter (see \a SkipDoctorDump_SendAssertionViolated).
379 //! \note If you called CrashHandler constructor and crshhndl.dll was missing you still may using this exception.
380 //! It will be catched, ignored and execution will continue. \ref SendReport function also works safely
381 //! when crshhndl.dll was missing.
382 static const DWORD ExceptionAssertionViolated = ((DWORD)0xCCE17000);
384 //! Sends assertion violation report from this point and continue execution.
385 //! \sa ExceptionAssertionViolated
386 //! \note Functions containing "SkipDoctorDump" will be ignored in stack parsing.
387 void SkipDoctorDump_SendAssertionViolated(
388 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.
389 ) const
391 if (!m_bWorking)
392 return;
393 if (dumpGroup)
394 ::RaiseException(CrashHandler::ExceptionAssertionViolated, 0, 1, reinterpret_cast<ULONG_PTR*>(&dumpGroup));
395 else
396 ::RaiseException(CrashHandler::ExceptionAssertionViolated, 0, 0, NULL);
399 private:
400 bool LoadDll(LPCWSTR crashHandlerPath = NULL) throw()
402 m_bLoaded = false;
403 m_bWorking = false;
404 m_bSkipAssertsAdded = false;
405 m_InitCrashHandler = NULL;
406 m_SendReport = NULL;
407 m_IsReadyToExit = NULL;
408 m_SetCustomInfo = NULL;
409 m_AddUserInfoToReport = NULL;
410 m_RemoveUserInfoFromReport = NULL;
411 m_AddFileToReport = NULL;
412 m_RemoveFileFromReport = NULL;
413 m_GetVersionFromApp = NULL;
414 m_GetVersionFromFile = NULL;
416 // hCrashHandlerDll should not be unloaded, crash may appear even after return from main().
417 // So hCrashHandlerDll is not saved after construction.
418 HMODULE hCrashHandlerDll = ::LoadLibraryW(crashHandlerPath ? crashHandlerPath : L"crshhndl.dll");
419 if (hCrashHandlerDll != NULL)
421 m_InitCrashHandler = (pfnInitCrashHandler) GetProcAddress(hCrashHandlerDll, "InitCrashHandler");
422 m_SendReport = (pfnSendReport) GetProcAddress(hCrashHandlerDll, "SendReport");
423 m_IsReadyToExit = (pfnIsReadyToExit) GetProcAddress(hCrashHandlerDll, "IsReadyToExit");
424 m_SetCustomInfo = (pfnSetCustomInfo) GetProcAddress(hCrashHandlerDll, "SetCustomInfo");
425 m_AddUserInfoToReport = (pfnAddUserInfoToReport) GetProcAddress(hCrashHandlerDll, "AddUserInfoToReport");
426 m_RemoveUserInfoFromReport = (pfnRemoveUserInfoFromReport) GetProcAddress(hCrashHandlerDll, "RemoveUserInfoFromReport");
427 m_AddFileToReport = (pfnAddFileToReport) GetProcAddress(hCrashHandlerDll, "AddFileToReport");
428 m_RemoveFileFromReport = (pfnRemoveFileFromReport) GetProcAddress(hCrashHandlerDll, "RemoveFileFromReport");
429 m_GetVersionFromApp = (pfnGetVersionFromApp) GetProcAddress(hCrashHandlerDll, "GetVersionFromApp");
430 m_GetVersionFromFile = (pfnGetVersionFromFile) GetProcAddress(hCrashHandlerDll, "GetVersionFromFile");
432 m_bLoaded = m_InitCrashHandler
433 && m_SendReport
434 && m_IsReadyToExit
435 && m_SetCustomInfo
436 && m_AddUserInfoToReport
437 && m_RemoveUserInfoFromReport
438 && m_AddFileToReport
439 && m_RemoveFileFromReport
440 && m_GetVersionFromApp
441 && m_GetVersionFromFile;
444 #if _WIN32_WINNT >= 0x0501 /*_WIN32_WINNT_WINXP*/
445 // if no crash processing was started, we need to ignore ExceptionAssertionViolated exceptions.
446 if (!m_bLoaded)
448 ::AddVectoredExceptionHandler(TRUE, SkipAsserts);
449 m_bSkipAssertsAdded = true;
451 #endif
453 return m_bLoaded;
456 static LONG CALLBACK SkipAsserts(EXCEPTION_POINTERS* pExceptionInfo)
458 if (pExceptionInfo->ExceptionRecord->ExceptionCode == ExceptionAssertionViolated)
459 return EXCEPTION_CONTINUE_EXECUTION;
460 return EXCEPTION_CONTINUE_SEARCH;
463 bool m_bLoaded;
464 bool m_bWorking;
465 bool m_bSkipAssertsAdded;
467 typedef BOOL (*pfnInitCrashHandler)(ApplicationInfo* applicationInfo, HandlerSettings* handlerSettings, BOOL ownProcess);
468 typedef LONG (*pfnSendReport)(EXCEPTION_POINTERS* exceptionPointers);
469 typedef BOOL (*pfnIsReadyToExit)();
470 typedef void (*pfnSetCustomInfo)(LPCWSTR text);
471 typedef void (*pfnAddUserInfoToReport)(LPCWSTR key, LPCWSTR value);
472 typedef void (*pfnRemoveUserInfoFromReport)(LPCWSTR key);
473 typedef void (*pfnAddFileToReport)(LPCWSTR path, LPCWSTR reportFileName /* = NULL */);
474 typedef void (*pfnRemoveFileFromReport)(LPCWSTR path);
475 typedef BOOL (*pfnGetVersionFromApp)(ApplicationInfo* appInfo);
476 typedef BOOL (*pfnGetVersionFromFile)(LPCWSTR path, ApplicationInfo* appInfo);
478 pfnInitCrashHandler m_InitCrashHandler;
479 pfnSendReport m_SendReport;
480 pfnIsReadyToExit m_IsReadyToExit;
481 pfnSetCustomInfo m_SetCustomInfo;
482 pfnAddUserInfoToReport m_AddUserInfoToReport;
483 pfnRemoveUserInfoFromReport m_RemoveUserInfoFromReport;
484 pfnAddFileToReport m_AddFileToReport;
485 pfnRemoveFileFromReport m_RemoveFileFromReport;
486 pfnGetVersionFromApp m_GetVersionFromApp;
487 pfnGetVersionFromFile m_GetVersionFromFile;
490 namespace {
492 // This template should be in anonymous namespace since __COUNTER__ is unique only for a single translation unit (as anonymous namespace items)
493 template<unsigned uniqueAssertId>
494 __forceinline static void SkipDoctorDump_ReportAssertionViolation(LPCSTR dumpGroup)
496 static LONG volatile isAlreadyReported = FALSE;
497 if (TRUE == InterlockedCompareExchange(&isAlreadyReported, TRUE, FALSE))
498 return;
499 ::RaiseException(CrashHandler::ExceptionAssertionViolated, 0, 1, reinterpret_cast<ULONG_PTR*>(&dumpGroup));
502 } // namespace {
504 #endif // __CRASH_HANDLER_H__