1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2013 - TortoiseGit
4 // Copyright (C) 2012 - 2013 - TortoiseSVN
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "../../ext/CrashServer/CrashHandler/CrashHandler/CrashHandler.h"
26 // dummy define, needed only when we use crashrpt instead of this.
27 #define CR_AF_MAKE_FILE_COPY 0
31 * helper class for the CrashServerSDK
46 static CCrashReport
& Instance()
48 static CCrashReport instance
;
52 int Uninstall(void) { return FALSE
; }
53 int AddFile2(LPCTSTR pszFile
,LPCTSTR pszDestFile
,LPCTSTR
/*pszDesc*/,DWORD
/*dwFlags*/)
55 return AddFileToReport(pszFile
, pszDestFile
) ? 1 : 0;
59 //! Initializes crash handler.
60 //! \note You may call this function multiple times if some data has changed.
61 //! \return Return \b true if crash handling was enabled.
62 bool InitCrashHandler(
63 ApplicationInfo
* applicationInfo
, //!< [in] Pointer to the ApplicationInfo structure that identifies your application.
64 HandlerSettings
* handlerSettings
, //!< [in] Pointer to the HandlerSettings structure that customizes crash handling behavior. This paramenter can be \b NULL.
65 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
66 //!< a plugin to some external application) set this option to \b FALSE. In that case you need to explicitly
67 //!< catch exceptions. See \ref SendReport for more information.
70 if (!m_InitCrashHandler
)
73 return m_InitCrashHandler(applicationInfo
, handlerSettings
, ownProcess
) != FALSE
;
76 //! You may add any key/value pair to crash report.
77 //! \return If the function succeeds, the return value is \b true.
78 bool AddUserInfoToReport(
79 LPCWSTR key
, //!< [in] key string that will be added to the report.
80 LPCWSTR value
//!< [in] value for the key.
83 if (!m_AddUserInfoToReport
)
85 m_AddUserInfoToReport(key
, value
);
89 //! You may add any file to crash report. This file will be read when crash appears and will be sent within the report.
90 //! Multiple files may be added. Filename of the file in the report may be changed to any name.
91 //! \return If the function succeeds, the return value is \b true.
93 LPCWSTR path
, //!< [in] Path to the file, that will be added to the report.
94 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.
97 if (!m_AddFileToReport
)
99 m_AddFileToReport(path
, reportFileName
);
103 //! Remove from report the file that was registered earlier to be sent within report.
104 //! \return If the function succeeds, the return value is \b true.
105 bool RemoveFileFromReport(
106 LPCWSTR path
//!< [in] Path to the file, that will be removed from the report.
109 if (!m_RemoveFileFromReport
)
111 m_RemoveFileFromReport(path
);
115 //! Fills version field (V) of ApplicationInfo with product version
116 //! found in the executable file of the current process.
117 //! \return If the function succeeds, the return value is \b true.
118 bool GetVersionFromApp(
119 ApplicationInfo
* appInfo
//!< [out] Pointer to ApplicationInfo structure. Its version field (V) will be set to product version.
122 if (!m_GetVersionFromApp
)
124 return m_GetVersionFromApp(appInfo
) != FALSE
;
127 //! Fill version field (V) of ApplicationInfo with product version found in the file specified.
128 //! \return If the function succeeds, the return value is \b true.
129 bool GetVersionFromFile(
130 LPCWSTR path
, //!< [in] Path to the file product version will be extracted from.
131 ApplicationInfo
* appInfo
//!< [out] Pointer to ApplicationInfo structure. Its version field (V) will be set to product version.
134 if (!m_GetVersionFromFile
)
136 return m_GetVersionFromFile(path
, appInfo
) != FALSE
;
139 //! If you do not own the process your code running in (for example you write a plugin to some
140 //! external application) you need to properly initialize CrashHandler using \b ownProcess option.
141 //! Also you need to explicitly catch all exceptions in all entry points to your code and in all
142 //! threads you create. To do so use this construction:
144 //! bool SomeEntryPoint(PARAM p)
148 //! return YouCode(p);
150 //! __except (CrashHandler::SendReport(GetExceptionInformation()))
152 //! ::ExitProcess(0); // It is better to stop the process here or else corrupted data may incomprehensibly crash it later.
158 EXCEPTION_POINTERS
* exceptionPointers
//!< [in] Pointer to EXCEPTION_POINTERS structure. You should get it using GetExceptionInformation()
159 //!< function inside __except keyword.
163 return EXCEPTION_CONTINUE_SEARCH
;
164 // There is no crash handler but asserts should continue anyway
165 if (exceptionPointers
->ExceptionRecord
->ExceptionCode
== ExceptionAssertionViolated
)
166 return EXCEPTION_CONTINUE_EXECUTION
;
167 return m_SendReport(exceptionPointers
);
170 //! To send a report about violated assertion you can throw exception with this exception code
171 //! using: \code RaiseException(CrashHandler::ExceptionAssertionViolated, 0, 0, NULL); \endcode
172 //! Execution will continue after report will be sent (EXCEPTION_CONTINUE_EXECUTION would be used).
173 //! \note If you called CrashHandler constructor and crshhdnl.dll was missing you still may using this exception.
174 //! It will be catched, ignored and execution will continue. \ref SendReport function also works safely
175 //! when crshhdnl.dll was missing.
176 static const DWORD ExceptionAssertionViolated
= ((DWORD
)0xCCE17000);
178 //! Sends assertion violation report from this point and continue execution.
179 //! \sa ExceptionAssertionViolated
180 //! \note Functions prefixed with "CrashServer_" will be ignored in stack parsing.
181 void CrashServer_SendAssertionViolated() const
183 if (!m_InitCrashHandler
)
185 ::RaiseException(CrashHandler::ExceptionAssertionViolated
, 0, 0, NULL
);
189 bool LoadDll() throw()
193 // hCrshhndlDll should not be unloaded, crash may appear even after return from main().
194 // So hCrshhndlDll is not saved after construction.
195 HMODULE hCrshhndlDll
= ::LoadLibraryW(L
"crshhndl.dll");
196 if (hCrshhndlDll
!= NULL
)
198 m_InitCrashHandler
= (pfnInitCrashHandler
) GetProcAddress(hCrshhndlDll
, "InitCrashHandler");
199 m_SendReport
= (pfnSendReport
) GetProcAddress(hCrshhndlDll
, "SendReport");
200 m_IsReadyToExit
= (pfnIsReadyToExit
) GetProcAddress(hCrshhndlDll
, "IsReadyToExit");
201 m_AddUserInfoToReport
= (pfnAddUserInfoToReport
) GetProcAddress(hCrshhndlDll
, "AddUserInfoToReport");
202 m_AddFileToReport
= (pfnAddFileToReport
) GetProcAddress(hCrshhndlDll
, "AddFileToReport");
203 m_RemoveFileFromReport
= (pfnRemoveFileFromReport
) GetProcAddress(hCrshhndlDll
, "RemoveFileFromReport");
204 m_GetVersionFromApp
= (pfnGetVersionFromApp
) GetProcAddress(hCrshhndlDll
, "GetVersionFromApp");
205 m_GetVersionFromFile
= (pfnGetVersionFromFile
) GetProcAddress(hCrshhndlDll
, "GetVersionFromFile");
207 result
= m_InitCrashHandler
210 && m_AddUserInfoToReport
212 && m_RemoveFileFromReport
213 && m_GetVersionFromApp
214 && m_GetVersionFromFile
;
220 static LONG CALLBACK
SkipAsserts(EXCEPTION_POINTERS
* pExceptionInfo
)
222 if (pExceptionInfo
->ExceptionRecord
->ExceptionCode
== ExceptionAssertionViolated
)
223 return EXCEPTION_CONTINUE_EXECUTION
;
224 return EXCEPTION_CONTINUE_SEARCH
;
227 typedef BOOL (*pfnInitCrashHandler
)(ApplicationInfo
* applicationInfo
, HandlerSettings
* handlerSettings
, BOOL ownProcess
);
228 typedef LONG (*pfnSendReport
)(EXCEPTION_POINTERS
* exceptionPointers
);
229 typedef BOOL (*pfnIsReadyToExit
)();
230 typedef void (*pfnAddUserInfoToReport
)(LPCWSTR key
, LPCWSTR value
);
231 typedef void (*pfnAddFileToReport
)(LPCWSTR path
, LPCWSTR reportFileName
/* = NULL */);
232 typedef void (*pfnRemoveFileFromReport
)(LPCWSTR path
);
233 typedef BOOL (*pfnGetVersionFromApp
)(ApplicationInfo
* appInfo
);
234 typedef BOOL (*pfnGetVersionFromFile
)(LPCWSTR path
, ApplicationInfo
* appInfo
);
236 pfnInitCrashHandler m_InitCrashHandler
;
237 pfnSendReport m_SendReport
;
238 pfnIsReadyToExit m_IsReadyToExit
;
239 pfnAddUserInfoToReport m_AddUserInfoToReport
;
240 pfnAddFileToReport m_AddFileToReport
;
241 pfnRemoveFileFromReport m_RemoveFileFromReport
;
242 pfnGetVersionFromApp m_GetVersionFromApp
;
243 pfnGetVersionFromFile m_GetVersionFromFile
;
247 class CCrashReportTGit
251 //! Installs exception handlers to the caller process
252 CCrashReportTGit(LPCTSTR appname
, USHORT versionMajor
, USHORT versionMinor
, USHORT versionMicro
, USHORT versionBuild
, const char * buildDate
, bool bOwnProcess
= true)
253 : m_nInstallStatus(0)
256 int month
, day
, year
;
258 static const char month_names
[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
259 sscanf_s(buildDate
, "%s %d %d", s_month
, _countof(s_month
) - 1, &day
, &year
);
260 month
= (int)((strstr(month_names
, s_month
)-month_names
))/3;
264 t
.tm_year
= year
- 1900;
266 __time64_t compiletime
= _mktime64(&t
);
271 if ((now
- compiletime
)<(60*60*24*31*4))
273 ApplicationInfo appInfo
;
274 memset(&appInfo
, 0, sizeof(appInfo
));
275 appInfo
.ApplicationInfoSize
= sizeof(ApplicationInfo
);
276 appInfo
.ApplicationGUID
= "7fbde3fc-94e9-408b-b5c8-62bd4e203570";
277 appInfo
.Prefix
= "tgit";
278 appInfo
.AppName
= appname
;
279 appInfo
.Company
= L
"TortoiseGit";
282 appInfo
.V
[0] = versionMajor
;
283 appInfo
.V
[1] = versionMinor
;
284 appInfo
.V
[2] = versionMicro
;
285 appInfo
.V
[3] = versionBuild
;
287 HandlerSettings handlerSettings
;
288 memset(&handlerSettings
, 0, sizeof(handlerSettings
));
289 handlerSettings
.HandlerSettingsSize
= sizeof(handlerSettings
);
290 handlerSettings
.LeaveDumpFilesInTempFolder
= FALSE
;
291 handlerSettings
.UseWER
= FALSE
;
292 handlerSettings
.OpenProblemInBrowser
= TRUE
;
293 handlerSettings
.SubmitterID
= 0;
295 CCrashReport::Instance().InitCrashHandler(&appInfo
, &handlerSettings
, bOwnProcess
);
300 //! Deinstalls exception handlers from the caller process
303 CCrashReport::Instance().Uninstall();
307 int m_nInstallStatus
;