Fixed issue #4126: Capitalize the first letter in the Push dialog
[TortoiseGit.git] / ext / CrashServer / CrashHandler / CrashHandler / CrashHandler.cpp
blob0df311ad07db8174e77023ec55ceeda61ed5d007
1 // Copyright 2012, 2014-2015 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 #include "stdafx.h"
19 #include "resource.h"
20 #include "CrashHandlerExport.h"
21 #include "..\SendRpt\Config.h"
22 #include "..\SendRpt\Serializer.h"
23 #include "..\..\CommonLibs\Log\synchro.h"
24 #include <signal.h>
25 #include <algorithm>
27 HINSTANCE g_hThisDLL = NULL;
28 bool g_applicationVerifierPresent = false;
29 bool g_ownProcess = false;
30 volatile LONG g_insideCrashHandler = 0;
31 LPTOP_LEVEL_EXCEPTION_FILTER g_prevTopLevelExceptionFilter = NULL;
33 // It should not be destroyed on PROCESS_DETACH, because it may be used later if someone will crash on deinitialization
34 // so it is on heap, but not static (runtime destroy static objects on PROCESS_DETACH)
35 Config* g_pConfig = new Config();
36 CriticalSection g_configCS;
38 DWORD g_tlsPrevTerminatePtr = TLS_OUT_OF_INDEXES;
39 typedef terminate_function (__cdecl *pfn_set_terminate)(terminate_function);
40 pfn_set_terminate g_set_terminate = NULL;
42 enum DoctorDumpCustomExceptionCodes
44 DOCTORDUMP_EXCEPTION_ASSERTION_VIOLATED = CrashHandler::ExceptionAssertionViolated, // 0xCCE17000
45 DOCTORDUMP_EXCEPTION_CPP_TERMINATE = 0xCCE17001,
46 DOCTORDUMP_EXCEPTION_CPP_PURE_CALL = 0xCCE17002,
47 DOCTORDUMP_EXCEPTION_CPP_INVALID_PARAMETER = 0xCCE17003,
50 class Error: public std::exception
52 public:
53 Error(const char* format, ...)
55 va_list ap;
56 va_start(ap, format);
57 m_description.FormatV(format, ap);
58 va_end(ap);
61 const char* what() const { return m_description; }
63 private:
64 CStringA m_description;
67 DWORD WINAPI SendReportThread(LPVOID lpParameter)
69 InterlockedIncrement(&g_insideCrashHandler);
71 MINIDUMP_EXCEPTION_INFORMATION* pExceptInfo = (MINIDUMP_EXCEPTION_INFORMATION*)lpParameter;
72 try
74 CStringW cmd;
75 cmd.Format(L"\"%ls\" ", (LPCWSTR)g_pConfig->SendRptPath);
77 CHandle hProcess;
78 DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &hProcess.m_h, PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | THREAD_ALL_ACCESS, TRUE, 0);
80 CHandle hReportReady(CreateEvent(NULL, TRUE, FALSE, NULL));
81 SetHandleInformation(hReportReady, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
83 auto er = pExceptInfo->ExceptionPointers->ExceptionRecord;
85 Params param;
86 param.Process = hProcess;
87 param.ProcessId = GetCurrentProcessId();
88 param.ExceptInfo = *pExceptInfo;
89 param.WasAssert = er->ExceptionCode == DOCTORDUMP_EXCEPTION_ASSERTION_VIOLATED;
90 param.ReportReady = hReportReady;
91 if (param.WasAssert && er->NumberParameters == 1 && er->ExceptionInformation[0])
92 param.Group = reinterpret_cast<LPCSTR>(er->ExceptionInformation[0]);
94 Serializer ser;
95 ser << param;
97 CriticalSection::SyncLock lock(g_configCS);
98 ser << *g_pConfig;
100 cmd.Append(ser.GetHex());
102 STARTUPINFO si = {sizeof(si)};
103 PROCESS_INFORMATION pi;
104 if (!CreateProcessW(NULL, cmd.GetBuffer(), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
105 throw std::runtime_error("failed to start SendRpt");
106 CloseHandle(pi.hThread);
108 HANDLE handles[] = { pi.hProcess, hReportReady.m_h };
109 DWORD res = WaitForMultipleObjects(_countof(handles), handles, FALSE, INFINITE);
111 CloseHandle(pi.hProcess);
113 InterlockedDecrement(&g_insideCrashHandler);
115 return TRUE;
117 catch (std::exception& ex)
119 OutputDebugStringA(ex.what());
122 InterlockedDecrement(&g_insideCrashHandler);
124 return FALSE;
127 LONG SendReport(EXCEPTION_POINTERS* pExceptionPointers)
129 if (IsDebuggerPresent())
130 return EXCEPTION_CONTINUE_SEARCH;
132 // We can enter here because of stack overflow, so lets all local variables
133 // be static, because variables on stack can lead to second stack overflow.
134 static DWORD dwThreadId;
135 static HANDLE hThread;
136 static MINIDUMP_EXCEPTION_INFORMATION exceptInfo;
137 exceptInfo.ThreadId = GetCurrentThreadId();
138 exceptInfo.ExceptionPointers = pExceptionPointers;
139 exceptInfo.ClientPointers = FALSE;
141 // If stack overflow, do all processing in another thread
142 if (pExceptionPointers != NULL
143 && pExceptionPointers->ExceptionRecord != NULL
144 && pExceptionPointers->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW
145 && (hThread = CreateThread(NULL, 0, SendReportThread, &exceptInfo, 0, &dwThreadId)) != NULL)
147 WaitForSingleObject(hThread, INFINITE);
149 else
151 SendReportThread(&exceptInfo);
154 if (pExceptionPointers->ExceptionRecord->ExceptionCode == DOCTORDUMP_EXCEPTION_ASSERTION_VIOLATED)
155 return EXCEPTION_CONTINUE_EXECUTION;
157 return g_pConfig->UseWER ? EXCEPTION_CONTINUE_SEARCH : EXCEPTION_EXECUTE_HANDLER;
160 LONG WINAPI TopLevelExceptionFilter(EXCEPTION_POINTERS* pExceptionPointers)
162 if (pExceptionPointers->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT
163 && g_applicationVerifierPresent)
165 // This crash has been processed in VectoredExceptionHandler and if we here we want WinQual
166 return EXCEPTION_CONTINUE_SEARCH;
169 DisableProcessWindowsGhosting();
171 return SendReport(pExceptionPointers);
174 LONG CALLBACK VectoredExceptionHandler(EXCEPTION_POINTERS* pExceptionPointers)
176 // Probably this is Application Verifier stop
177 if (pExceptionPointers->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT
178 && g_applicationVerifierPresent)
180 LONG res = SendReport(pExceptionPointers);
181 if (res == EXCEPTION_EXECUTE_HANDLER)
182 ExitProcess(0); // we don't want WinQual from Application Verifier
185 // Asserts should be handled in VectoredExceptionHandler since EXCEPTION_CONTINUE_EXECUTION is used
186 // and __try { ... } __except(EXCEPTION_EXECUTE_HANDLER) { ... } in the way to TopLevelExceptionFilter
187 // may break this logic.
188 if (pExceptionPointers->ExceptionRecord->ExceptionCode == DOCTORDUMP_EXCEPTION_ASSERTION_VIOLATED)
189 return SendReport(pExceptionPointers);
191 return EXCEPTION_CONTINUE_SEARCH;
194 FARPROC GetSetUnhandledExceptionFilterPointer()
196 FARPROC suef = NULL;
197 // In Windows 8 SetUnhandledExceptionFilter implementation is in kernelbase
198 if (HMODULE kernelbase = GetModuleHandle(_T("kernelbase")))
199 suef = GetProcAddress(kernelbase, "SetUnhandledExceptionFilter");
200 if (!suef)
202 if (HMODULE kernel32 = GetModuleHandle(_T("kernel32")))
203 suef = GetProcAddress(kernel32, "SetUnhandledExceptionFilter");
205 return suef;
208 void SwitchSetUnhandledExceptionFilter(bool enable)
210 FARPROC suef = GetSetUnhandledExceptionFilterPointer();
211 if (!suef)
212 return;
214 // newBody is something like that:
216 // LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER)
217 // {
218 // return NULL;
219 // }
220 #if defined(_M_X64)
221 static const BYTE newBody[] =
223 0x33, 0xC0, // xor eax,eax
224 0xC3 // ret
226 #elif defined(_M_IX86)
227 static const BYTE newBody[] =
229 0x8B, 0xFF, // mov edi,edi <- for hotpatching
230 0x33, 0xC0, // xor eax,eax
231 0xC2, 0x04, 0x00 // ret 4
233 #else
234 # error Unsupported architecture
235 #endif
236 const SIZE_T bodySize = sizeof(newBody);
238 static BYTE oldBody[bodySize] = { 0 };
240 DWORD oldProtection;
241 if (!VirtualProtect(suef, bodySize, PAGE_EXECUTE_READWRITE, &oldProtection))
242 return;
243 if (!enable)
245 memcpy(oldBody, suef, bodySize);
246 memcpy(suef, newBody, bodySize);
248 else if (oldBody[0] != 0)
250 memcpy(suef, oldBody, bodySize);
253 VirtualProtect(suef, bodySize, oldProtection, &oldProtection);
256 void DisableSetUnhandledExceptionFilter()
258 SwitchSetUnhandledExceptionFilter(false);
261 void ReenableSetUnhandledExceptionFilter()
263 SwitchSetUnhandledExceptionFilter(true);
266 // This code should be inplace, so it is a macro
267 #define SendReportWithCode(code) __try { RaiseException(code, EXCEPTION_NONCONTINUABLE, 0, NULL); } __except(TopLevelExceptionFilter(GetExceptionInformation())) {}
269 void SkipDoctorDump_TerminateHandler()
271 SendReportWithCode(DOCTORDUMP_EXCEPTION_CPP_TERMINATE);
273 if (g_tlsPrevTerminatePtr != TLS_OUT_OF_INDEXES)
275 terminate_function prev_terminate = static_cast<terminate_function>(TlsGetValue(g_tlsPrevTerminatePtr));
276 if (prev_terminate)
277 prev_terminate();
280 if (!g_pConfig->UseWER)
281 ExitProcess(0);
284 void SkipDoctorDump_PureCallHandler()
286 SendReportWithCode(DOCTORDUMP_EXCEPTION_CPP_PURE_CALL);
287 ExitProcess(0);
290 void SkipDoctorDump_InvalidParameterHandler(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t)
292 SendReportWithCode(DOCTORDUMP_EXCEPTION_CPP_INVALID_PARAMETER);
293 ExitProcess(0);
296 void SkipDoctorDump_SigAbrtHandler(int)
298 SendReportWithCode(DOCTORDUMP_EXCEPTION_CPP_TERMINATE);
299 ExitProcess(0);
302 void MakePerThreadInitialization()
304 if (g_tlsPrevTerminatePtr != TLS_OUT_OF_INDEXES && g_set_terminate)
305 TlsSetValue(g_tlsPrevTerminatePtr, g_set_terminate(SkipDoctorDump_TerminateHandler));
308 void InitCrtErrorHandlers()
310 LPCTSTR crtModules[] = {
311 _T("msvcr70"), _T("msvcr70d"),
312 _T("msvcr71"), _T("msvcr71d"),
313 _T("msvcr80"), _T("msvcr80d"),
314 _T("msvcr90"), _T("msvcr90d"),
315 _T("msvcr100"), _T("msvcr100d"),
316 _T("msvcr110"), _T("msvcr110d"),
317 _T("msvcr120"), _T("msvcr120d"),
318 _T("msvcr130"), _T("msvcr130d"),
319 _T("vcruntime140"), _T("vcruntime140d"),
322 HMODULE hMsvcrDll = NULL;
323 for (size_t i = 0; !hMsvcrDll && i < _countof(crtModules); ++i)
324 hMsvcrDll = GetModuleHandle(crtModules[i]);
326 if (!hMsvcrDll)
327 return;
329 g_set_terminate = (pfn_set_terminate) GetProcAddress(hMsvcrDll, "?set_terminate@@YAP6AXXZP6AXXZ@Z");
331 typedef _purecall_handler (__cdecl *pfn_set_purecall_handler)(_purecall_handler);
332 pfn_set_purecall_handler l_set_purecall_handler = (pfn_set_purecall_handler) GetProcAddress(hMsvcrDll, "_set_purecall_handler");
333 if (l_set_purecall_handler)
334 l_set_purecall_handler(SkipDoctorDump_PureCallHandler);
336 typedef _invalid_parameter_handler (__cdecl *pfn_set_invalid_parameter_handler)(_invalid_parameter_handler);
337 pfn_set_invalid_parameter_handler l_set_invalid_parameter_handler = (pfn_set_invalid_parameter_handler) GetProcAddress(hMsvcrDll, "_set_invalid_parameter_handler");
338 if (l_set_invalid_parameter_handler)
339 l_set_invalid_parameter_handler(SkipDoctorDump_InvalidParameterHandler);
341 typedef void (__cdecl *pfn_signal)(int sig, void (__cdecl *func)(int));
342 pfn_signal l_signal = (pfn_signal) GetProcAddress(hMsvcrDll, "signal");
343 if (l_signal)
344 l_signal(SIGABRT, SkipDoctorDump_SigAbrtHandler);
347 CStringW GetProcessName()
349 WCHAR path[MAX_PATH], drive[MAX_PATH], dir[MAX_PATH], fname[MAX_PATH], ext[MAX_PATH];
350 GetModuleFileNameW(NULL, path, _countof(path));
351 _wsplitpath_s(path, drive, dir, fname, ext);
352 CStringW processName = CStringW(fname) + ext;
353 processName.MakeLower();
354 return processName;
357 BOOL InitCrashHandler(ApplicationInfo* applicationInfo, HandlerSettings* handlerSettings, BOOL ownProcess)
361 CriticalSection::SyncLock lock(g_configCS);
363 CStringW processName = GetProcessName();
365 #define IS_EXIST(field) (FIELD_OFFSET(ApplicationInfo, field) < applicationInfo->ApplicationInfoSize)
366 if (applicationInfo == NULL || applicationInfo->ApplicationInfoSize == 0)
368 throw Error("Wrong ApplicationInfo size.");
371 if (applicationInfo->ApplicationInfoSize > sizeof(ApplicationInfo))
373 throw Error("Wrong ApplicationInfo size, should be no more than %d bytes.", sizeof(ApplicationInfo));
376 if (!IS_EXIST(ApplicationGUID) || applicationInfo->ApplicationGUID == NULL
377 || !IS_EXIST(AppName) || applicationInfo->AppName == NULL
378 || !IS_EXIST(Company) || applicationInfo->Company == NULL)
380 throw Error("Some parameters missing in ApplicationInfo.");
383 g_pConfig->ApplicationGUID = applicationInfo->ApplicationGUID;
384 g_pConfig->Prefix = applicationInfo->Prefix ? CStringW(CA2W(applicationInfo->Prefix)) : processName;
385 g_pConfig->AppName = applicationInfo->AppName;
386 g_pConfig->Company = applicationInfo->Company;
388 if (g_pConfig->ApplicationGUID == "00000000-0000-0000-0000-000000000000")
389 throw Error("Generate new GUID for ApplicationGUID.");
390 if (g_pConfig->AppName == "{AppName}")
391 throw Error("Set correct application name.");
392 if (g_pConfig->Company == "{Company}")
393 throw Error("Set correct company name.");
395 if (IS_EXIST(V))
396 memcpy(g_pConfig->V, applicationInfo->V, sizeof(applicationInfo->V));
397 else
398 memset(g_pConfig->V, 0, sizeof(g_pConfig->V));
399 if (IS_EXIST(Hotfix))
400 g_pConfig->Hotfix = applicationInfo->Hotfix;
401 else
402 g_pConfig->Hotfix = 0;
403 if (IS_EXIST(PrivacyPolicyUrl) && applicationInfo->PrivacyPolicyUrl != NULL)
404 g_pConfig->PrivacyPolicyUrl = applicationInfo->PrivacyPolicyUrl;
405 else
406 g_pConfig->PrivacyPolicyUrl.Format(L"http://www.drdump.com/AppPrivacyPolicy.aspx?AppID=%s", (LPCWSTR)g_pConfig->ApplicationGUID);
407 #undef IS_EXIST
409 #define IS_EXIST(field) (handlerSettings != NULL && (FIELD_OFFSET(HandlerSettings, field) < handlerSettings->HandlerSettingsSize))
410 if (handlerSettings != NULL && handlerSettings->HandlerSettingsSize > sizeof(HandlerSettings))
412 throw Error("Wrong HandlerSettings size, should be no more than %d.", sizeof(HandlerSettings));
415 if (IS_EXIST(LeaveDumpFilesInTempFolder))
417 g_pConfig->ServiceMode = handlerSettings->LeaveDumpFilesInTempFolder == 2; // hidden behavior (used for dumpparser)
418 g_pConfig->LeaveDumpFilesInTempFolder = handlerSettings->LeaveDumpFilesInTempFolder != FALSE;
420 else
422 g_pConfig->ServiceMode = 0;
423 g_pConfig->LeaveDumpFilesInTempFolder = FALSE;
425 if (IS_EXIST(OpenProblemInBrowser))
426 g_pConfig->OpenProblemInBrowser = handlerSettings->OpenProblemInBrowser;
427 else
428 g_pConfig->OpenProblemInBrowser = FALSE;
429 if (IS_EXIST(UseWER))
430 g_pConfig->UseWER = handlerSettings->UseWER;
431 else
432 g_pConfig->UseWER = FALSE;
433 if (IS_EXIST(SubmitterID))
434 g_pConfig->SubmitterID = handlerSettings->SubmitterID;
435 else
436 g_pConfig->SubmitterID = 0;
437 if (IS_EXIST(SendAdditionalDataWithoutApproval))
438 g_pConfig->SendAdditionalDataWithoutApproval = handlerSettings->SendAdditionalDataWithoutApproval;
439 else
440 g_pConfig->SendAdditionalDataWithoutApproval = FALSE;
441 if (IS_EXIST(OverrideDefaultFullDumpType) && IS_EXIST(FullDumpType) && handlerSettings->OverrideDefaultFullDumpType)
442 g_pConfig->FullDumpType = handlerSettings->FullDumpType;
443 else
444 g_pConfig->FullDumpType = MiniDumpWithFullMemory;
445 if (IS_EXIST(LangFilePath))
446 g_pConfig->LangFilePath = handlerSettings->LangFilePath;
447 else
448 g_pConfig->LangFilePath = L"";
449 if (IS_EXIST(SendRptPath))
450 g_pConfig->SendRptPath = handlerSettings->SendRptPath;
451 else
452 g_pConfig->SendRptPath = L"";
453 if (IS_EXIST(DbgHelpPath))
454 g_pConfig->DbgHelpPath = handlerSettings->DbgHelpPath;
455 else
456 g_pConfig->DbgHelpPath = L"";
457 #undef IS_EXIST
459 g_pConfig->ProcessName = processName;
461 WCHAR path[MAX_PATH], drive[MAX_PATH], dir[MAX_PATH], fname[MAX_PATH], ext[MAX_PATH];
462 GetModuleFileNameW(g_hThisDLL, path, _countof(path));
463 _wsplitpath_s(path, drive, dir, fname, ext);
465 if (g_pConfig->SendRptPath.IsEmpty())
467 WCHAR sendRptExe[MAX_PATH];
468 _wmakepath_s(sendRptExe, drive, dir, L"SendRpt", L".exe");
469 g_pConfig->SendRptPath = sendRptExe;
472 if (g_pConfig->DbgHelpPath.IsEmpty())
474 WCHAR dbgHelpDll[MAX_PATH];
475 _wmakepath_s(dbgHelpDll, drive, dir, L"dbghelp", L".dll");
476 g_pConfig->DbgHelpPath = dbgHelpDll;
478 if (0 != _waccess_s(g_pConfig->DbgHelpPath, 00/* Existence only */))
480 throw Error("%ls not found.", (LPCWSTR)g_pConfig->DbgHelpPath);
483 g_ownProcess = ownProcess != FALSE;
485 static bool inited = false;
486 if (!inited)
488 if (g_ownProcess)
490 // Application verifier sets its own VectoredExceptionHandler
491 // and Application verifier breaks redirected to WinQual.
492 // After that TopLevelExceptionFilter works.
493 // This behavior looks bad and anyway we don't need WinQual.
494 // So we set our VectoredExceptionHandler before AppVerifier and
495 // catch problems first.
496 g_applicationVerifierPresent = GetModuleHandle(_T("verifier.dll")) != NULL;
497 if (g_applicationVerifierPresent)
498 AddVectoredExceptionHandler(TRUE, VectoredExceptionHandler);
500 g_prevTopLevelExceptionFilter = SetUnhandledExceptionFilter(TopLevelExceptionFilter);
501 // There is a lot of libraries that want to set their own wrong UnhandledExceptionFilter in our application.
502 // One of these is MSVCRT with __report_gsfailure and _call_reportfault leading to many
503 // of MSVCRT error reports to be redirected to Dr. Watson.
504 DisableSetUnhandledExceptionFilter();
506 InitCrtErrorHandlers();
507 MakePerThreadInitialization();
510 // Need to lock library in process.
511 // Since some crashes appears on process deinitialization and we should be ready to handle it.
512 WCHAR pathToSelf[MAX_PATH];
513 if (0 != GetModuleFileNameW(g_hThisDLL, pathToSelf, _countof(pathToSelf)))
514 LoadLibraryW(pathToSelf);
516 inited = true;
519 return TRUE;
521 catch (std::exception& ex)
523 OutputDebugStringA(ex.what());
524 ::MessageBoxA(0, ex.what(), "CrashHandler initialization error", MB_ICONERROR);
525 SetLastError(ERROR_INVALID_PARAMETER);
526 return FALSE;
530 void SetCustomInfo(LPCWSTR text)
532 if (!g_pConfig)
533 return;
534 CriticalSection::SyncLock lock(g_configCS);
535 g_pConfig->CustomInfo = text;
536 const int Limit = 100;
537 if (g_pConfig->CustomInfo.GetLength() > Limit)
538 g_pConfig->CustomInfo = g_pConfig->CustomInfo.Left(Limit);
541 void AddUserInfoToReport(LPCWSTR key, LPCWSTR value)
543 if (!g_pConfig)
544 return;
545 CriticalSection::SyncLock lock(g_configCS);
546 g_pConfig->UserInfo[key] = value;
549 void RemoveUserInfoFromReport(LPCWSTR key)
551 if (!g_pConfig)
552 return;
553 CriticalSection::SyncLock lock(g_configCS);
554 g_pConfig->UserInfo.erase(key);
557 void AddFileToReport(LPCWSTR path, LPCWSTR reportFileName)
559 if (!g_pConfig)
560 return;
561 CStringW fileName;
562 if (!reportFileName)
564 WCHAR drive[MAX_PATH], dir[MAX_PATH], fname[MAX_PATH], ext[MAX_PATH];
565 _wsplitpath_s(path, drive, dir, fname, ext);
566 fileName = CStringW(fname) + ext;
568 else
570 fileName = reportFileName;
572 CriticalSection::SyncLock lock(g_configCS);
573 g_pConfig->FilesToAttach.push_back(make_pair(CStringW(path), fileName));
576 void RemoveFileFromReport(LPCWSTR path)
578 if (!g_pConfig)
579 return;
580 CriticalSection::SyncLock lock(g_configCS);
581 auto it = std::find_if(g_pConfig->FilesToAttach.begin(), g_pConfig->FilesToAttach.end(),
582 [path](std::pair<CStringW, CStringW>& x){ return x.first == path; });
583 if (it != g_pConfig->FilesToAttach.end())
584 g_pConfig->FilesToAttach.erase(it);
587 BOOL GetVersionFromFile(LPCWSTR path, ApplicationInfo* appInfo)
589 if (!path || !appInfo)
590 return FALSE;
592 appInfo->V[0] = 0;
593 appInfo->V[1] = 0;
594 appInfo->V[2] = 0;
595 appInfo->V[3] = 0;
597 DWORD size = GetFileVersionInfoSize(path, NULL);
598 if (size == 0)
599 return FALSE;
600 LPVOID pVerInfo = HeapAlloc(GetProcessHeap(), 0, size);
601 if (!GetFileVersionInfo(path, 0, size, pVerInfo))
603 HeapFree(GetProcessHeap(), 0, pVerInfo);
604 return FALSE;
606 VS_FIXEDFILEINFO* lpFileinfo = NULL;
607 UINT uLen;
608 if (!VerQueryValue(pVerInfo, _T("\\"), (LPVOID*)&lpFileinfo, &uLen))
610 HeapFree(GetProcessHeap(), 0, pVerInfo);
611 return FALSE;
613 appInfo->V[0] = HIWORD(lpFileinfo->dwProductVersionMS);
614 appInfo->V[1] = LOWORD(lpFileinfo->dwProductVersionMS);
615 appInfo->V[2] = HIWORD(lpFileinfo->dwProductVersionLS);
616 appInfo->V[3] = LOWORD(lpFileinfo->dwProductVersionLS);
617 HeapFree(GetProcessHeap(), 0, pVerInfo);
619 return TRUE;
622 BOOL GetVersionFromApp(ApplicationInfo* appInfo)
624 if (!appInfo)
625 return FALSE;
627 appInfo->V[0] = 0;
628 appInfo->V[1] = 0;
629 appInfo->V[2] = 0;
630 appInfo->V[3] = 0;
632 TCHAR path[MAX_PATH];
633 if (!GetModuleFileName(NULL, path, _countof(path)))
634 return FALSE;
636 return GetVersionFromFile(path, appInfo);
639 BOOL IsReadyToExit()
641 return g_insideCrashHandler == 0 ? TRUE : FALSE;
644 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
646 switch (fdwReason)
648 case DLL_PROCESS_ATTACH:
649 g_hThisDLL = hinstDLL;
650 g_tlsPrevTerminatePtr = TlsAlloc();
651 break;
652 case DLL_PROCESS_DETACH:
653 if (g_tlsPrevTerminatePtr != TLS_OUT_OF_INDEXES)
655 TlsFree(g_tlsPrevTerminatePtr);
656 g_tlsPrevTerminatePtr = TLS_OUT_OF_INDEXES;
658 if (g_prevTopLevelExceptionFilter)
660 ReenableSetUnhandledExceptionFilter();
661 SetUnhandledExceptionFilter(g_prevTopLevelExceptionFilter);
663 if (g_applicationVerifierPresent)
664 RemoveVectoredExceptionHandler(VectoredExceptionHandler);
665 break;
666 case DLL_THREAD_ATTACH:
667 if (g_ownProcess)
669 MakePerThreadInitialization();
671 break;
673 return TRUE;