Sync DrDump crash handler with TortoiseSVN codebase
[TortoiseGit.git] / ext / CrashServer / CrashHandler / CrashHandler / CrashHandler.cpp
blobdb115a2e5ea19cf4f32f98ba7cdd27bb2765e14c
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 #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"),
321 HMODULE hMsvcrDll = NULL;
322 for (size_t i = 0; !hMsvcrDll && i < _countof(crtModules); ++i)
323 hMsvcrDll = GetModuleHandle(crtModules[i]);
325 if (!hMsvcrDll)
326 return;
328 g_set_terminate = (pfn_set_terminate) GetProcAddress(hMsvcrDll, "?set_terminate@@YAP6AXXZP6AXXZ@Z");
330 typedef _purecall_handler (__cdecl *pfn_set_purecall_handler)(_purecall_handler);
331 pfn_set_purecall_handler l_set_purecall_handler = (pfn_set_purecall_handler) GetProcAddress(hMsvcrDll, "_set_purecall_handler");
332 if (l_set_purecall_handler)
333 l_set_purecall_handler(SkipDoctorDump_PureCallHandler);
335 typedef _invalid_parameter_handler (__cdecl *pfn_set_invalid_parameter_handler)(_invalid_parameter_handler);
336 pfn_set_invalid_parameter_handler l_set_invalid_parameter_handler = (pfn_set_invalid_parameter_handler) GetProcAddress(hMsvcrDll, "_set_invalid_parameter_handler");
337 if (l_set_invalid_parameter_handler)
338 l_set_invalid_parameter_handler(SkipDoctorDump_InvalidParameterHandler);
340 typedef void (__cdecl *pfn_signal)(int sig, void (__cdecl *func)(int));
341 pfn_signal l_signal = (pfn_signal) GetProcAddress(hMsvcrDll, "signal");
342 if (l_signal)
343 l_signal(SIGABRT, SkipDoctorDump_SigAbrtHandler);
346 CStringW GetProcessName()
348 WCHAR path[MAX_PATH], drive[MAX_PATH], dir[MAX_PATH], fname[MAX_PATH], ext[MAX_PATH];
349 GetModuleFileNameW(NULL, path, _countof(path));
350 _wsplitpath_s(path, drive, dir, fname, ext);
351 CStringW processName = CStringW(fname) + ext;
352 processName.MakeLower();
353 return processName;
356 BOOL InitCrashHandler(ApplicationInfo* applicationInfo, HandlerSettings* handlerSettings, BOOL ownProcess)
360 CriticalSection::SyncLock lock(g_configCS);
362 CStringW processName = GetProcessName();
364 #define IS_EXIST(field) (FIELD_OFFSET(ApplicationInfo, field) < applicationInfo->ApplicationInfoSize)
365 if (applicationInfo == NULL || applicationInfo->ApplicationInfoSize == 0)
367 throw Error("Wrong ApplicationInfo size.");
370 if (applicationInfo->ApplicationInfoSize > sizeof(ApplicationInfo))
372 throw Error("Wrong ApplicationInfo size, should be no more than %d bytes.", sizeof(ApplicationInfo));
375 if (!IS_EXIST(ApplicationGUID) || applicationInfo->ApplicationGUID == NULL
376 || !IS_EXIST(AppName) || applicationInfo->AppName == NULL
377 || !IS_EXIST(Company) || applicationInfo->Company == NULL)
379 throw Error("Some parameters missing in ApplicationInfo.");
382 g_pConfig->ApplicationGUID = applicationInfo->ApplicationGUID;
383 g_pConfig->Prefix = applicationInfo->Prefix ? CStringW(CA2W(applicationInfo->Prefix)) : processName;
384 g_pConfig->AppName = applicationInfo->AppName;
385 g_pConfig->Company = applicationInfo->Company;
387 if (g_pConfig->ApplicationGUID == "00000000-0000-0000-0000-000000000000")
388 throw Error("Generate new GUID for ApplicationGUID.");
389 if (g_pConfig->AppName == "{AppName}")
390 throw Error("Set correct application name.");
391 if (g_pConfig->Company == "{Company}")
392 throw Error("Set correct company name.");
394 if (IS_EXIST(V))
395 memcpy(g_pConfig->V, applicationInfo->V, sizeof(applicationInfo->V));
396 else
397 memset(g_pConfig->V, 0, sizeof(g_pConfig->V));
398 if (IS_EXIST(Hotfix))
399 g_pConfig->Hotfix = applicationInfo->Hotfix;
400 else
401 g_pConfig->Hotfix = 0;
402 if (IS_EXIST(PrivacyPolicyUrl) && applicationInfo->PrivacyPolicyUrl != NULL)
403 g_pConfig->PrivacyPolicyUrl = applicationInfo->PrivacyPolicyUrl;
404 else
405 g_pConfig->PrivacyPolicyUrl.Format(L"http://www.drdump.com/AppPrivacyPolicy.aspx?AppID=%s", (LPCWSTR)g_pConfig->ApplicationGUID);
406 #undef IS_EXIST
408 #define IS_EXIST(field) (handlerSettings != NULL && (FIELD_OFFSET(HandlerSettings, field) < handlerSettings->HandlerSettingsSize))
409 if (handlerSettings != NULL && handlerSettings->HandlerSettingsSize > sizeof(HandlerSettings))
411 throw Error("Wrong HandlerSettings size, should be no more than %d.", sizeof(HandlerSettings));
414 if (IS_EXIST(LeaveDumpFilesInTempFolder))
416 g_pConfig->ServiceMode = handlerSettings->LeaveDumpFilesInTempFolder == 2; // hidden behavior (used for dumpparser)
417 g_pConfig->LeaveDumpFilesInTempFolder = handlerSettings->LeaveDumpFilesInTempFolder != FALSE;
419 else
421 g_pConfig->ServiceMode = 0;
422 g_pConfig->LeaveDumpFilesInTempFolder = FALSE;
424 if (IS_EXIST(OpenProblemInBrowser))
425 g_pConfig->OpenProblemInBrowser = handlerSettings->OpenProblemInBrowser;
426 else
427 g_pConfig->OpenProblemInBrowser = FALSE;
428 if (IS_EXIST(UseWER))
429 g_pConfig->UseWER = handlerSettings->UseWER;
430 else
431 g_pConfig->UseWER = FALSE;
432 if (IS_EXIST(SubmitterID))
433 g_pConfig->SubmitterID = handlerSettings->SubmitterID;
434 else
435 g_pConfig->SubmitterID = 0;
436 if (IS_EXIST(SendAdditionalDataWithoutApproval))
437 g_pConfig->SendAdditionalDataWithoutApproval = handlerSettings->SendAdditionalDataWithoutApproval;
438 else
439 g_pConfig->SendAdditionalDataWithoutApproval = FALSE;
440 if (IS_EXIST(OverrideDefaultFullDumpType) && IS_EXIST(FullDumpType) && handlerSettings->OverrideDefaultFullDumpType)
441 g_pConfig->FullDumpType = handlerSettings->FullDumpType;
442 else
443 g_pConfig->FullDumpType = MiniDumpWithFullMemory;
444 if (IS_EXIST(LangFilePath))
445 g_pConfig->LangFilePath = handlerSettings->LangFilePath;
446 else
447 g_pConfig->LangFilePath = L"";
448 if (IS_EXIST(SendRptPath))
449 g_pConfig->SendRptPath = handlerSettings->SendRptPath;
450 else
451 g_pConfig->SendRptPath = L"";
452 if (IS_EXIST(DbgHelpPath))
453 g_pConfig->DbgHelpPath = handlerSettings->DbgHelpPath;
454 else
455 g_pConfig->DbgHelpPath = L"";
456 #undef IS_EXIST
458 g_pConfig->ProcessName = processName;
460 WCHAR path[MAX_PATH], drive[MAX_PATH], dir[MAX_PATH], fname[MAX_PATH], ext[MAX_PATH];
461 GetModuleFileNameW(g_hThisDLL, path, _countof(path));
462 _wsplitpath_s(path, drive, dir, fname, ext);
464 if (g_pConfig->SendRptPath.IsEmpty())
466 WCHAR sendRptExe[MAX_PATH];
467 _wmakepath_s(sendRptExe, drive, dir, L"SendRpt", L".exe");
468 g_pConfig->SendRptPath = sendRptExe;
471 if (g_pConfig->DbgHelpPath.IsEmpty())
473 WCHAR dbgHelpDll[MAX_PATH];
474 _wmakepath_s(dbgHelpDll, drive, dir, L"dbghelp", L".dll");
475 g_pConfig->DbgHelpPath = dbgHelpDll;
477 if (0 != _waccess_s(g_pConfig->DbgHelpPath, 00/* Existence only */))
479 throw Error("%ls not found.", (LPCWSTR)g_pConfig->SendRptPath);
482 g_ownProcess = ownProcess != FALSE;
484 static bool inited = false;
485 if (!inited)
487 if (g_ownProcess)
489 // Application verifier sets its own VectoredExceptionHandler
490 // and Application verifier breaks redirected to WinQual.
491 // After that TopLevelExceptionFilter works.
492 // This behavior looks bad and anyway we don't need WinQual.
493 // So we set our VectoredExceptionHandler before AppVerifier and
494 // catch problems first.
495 g_applicationVerifierPresent = GetModuleHandle(_T("verifier.dll")) != NULL;
496 if (g_applicationVerifierPresent)
497 AddVectoredExceptionHandler(TRUE, VectoredExceptionHandler);
499 g_prevTopLevelExceptionFilter = SetUnhandledExceptionFilter(TopLevelExceptionFilter);
500 // There is a lot of libraries that want to set their own wrong UnhandledExceptionFilter in our application.
501 // One of these is MSVCRT with __report_gsfailure and _call_reportfault leading to many
502 // of MSVCRT error reports to be redirected to Dr. Watson.
503 DisableSetUnhandledExceptionFilter();
505 InitCrtErrorHandlers();
506 MakePerThreadInitialization();
509 // Need to lock library in process.
510 // Since some crashes appears on process deinitialization and we should be ready to handle it.
511 WCHAR pathToSelf[MAX_PATH];
512 if (0 != GetModuleFileNameW(g_hThisDLL, pathToSelf, _countof(pathToSelf)))
513 LoadLibraryW(pathToSelf);
515 inited = true;
518 return TRUE;
520 catch (std::exception& ex)
522 OutputDebugStringA(ex.what());
523 ::MessageBoxA(0, ex.what(), "CrashHandler initialization error", MB_ICONERROR);
524 SetLastError(ERROR_INVALID_PARAMETER);
525 return FALSE;
529 void SetCustomInfo(LPCWSTR text)
531 if (!g_pConfig)
532 return;
533 CriticalSection::SyncLock lock(g_configCS);
534 g_pConfig->CustomInfo = text;
535 const int Limit = 100;
536 if (g_pConfig->CustomInfo.GetLength() > Limit)
537 g_pConfig->CustomInfo = g_pConfig->CustomInfo.Left(Limit);
540 void AddUserInfoToReport(LPCWSTR key, LPCWSTR value)
542 if (!g_pConfig)
543 return;
544 CriticalSection::SyncLock lock(g_configCS);
545 g_pConfig->UserInfo[key] = value;
548 void RemoveUserInfoFromReport(LPCWSTR key)
550 if (!g_pConfig)
551 return;
552 CriticalSection::SyncLock lock(g_configCS);
553 g_pConfig->UserInfo.erase(key);
556 void AddFileToReport(LPCWSTR path, LPCWSTR reportFileName)
558 if (!g_pConfig)
559 return;
560 CStringW fileName;
561 if (!reportFileName)
563 WCHAR drive[MAX_PATH], dir[MAX_PATH], fname[MAX_PATH], ext[MAX_PATH];
564 _wsplitpath_s(path, drive, dir, fname, ext);
565 fileName = CStringW(fname) + ext;
567 else
569 fileName = reportFileName;
571 CriticalSection::SyncLock lock(g_configCS);
572 g_pConfig->FilesToAttach.push_back(make_pair(CStringW(path), fileName));
575 void RemoveFileFromReport(LPCWSTR path)
577 if (!g_pConfig)
578 return;
579 CriticalSection::SyncLock lock(g_configCS);
580 auto it = std::find_if(g_pConfig->FilesToAttach.begin(), g_pConfig->FilesToAttach.end(),
581 [path](std::pair<CStringW, CStringW>& x){ return x.first == path; });
582 if (it != g_pConfig->FilesToAttach.end())
583 g_pConfig->FilesToAttach.erase(it);
586 BOOL GetVersionFromFile(LPCWSTR path, ApplicationInfo* appInfo)
588 if (!path || !appInfo)
589 return FALSE;
591 appInfo->V[0] = 0;
592 appInfo->V[1] = 0;
593 appInfo->V[2] = 0;
594 appInfo->V[3] = 0;
596 DWORD size = GetFileVersionInfoSize(path, NULL);
597 if (size == 0)
598 return FALSE;
599 LPVOID pVerInfo = HeapAlloc(GetProcessHeap(), 0, size);
600 if (!GetFileVersionInfo(path, 0, size, pVerInfo))
602 HeapFree(GetProcessHeap(), 0, pVerInfo);
603 return FALSE;
605 VS_FIXEDFILEINFO* lpFileinfo = NULL;
606 UINT uLen;
607 if (!VerQueryValue(pVerInfo, _T("\\"), (LPVOID*)&lpFileinfo, &uLen))
609 HeapFree(GetProcessHeap(), 0, pVerInfo);
610 return FALSE;
612 appInfo->V[0] = HIWORD(lpFileinfo->dwProductVersionMS);
613 appInfo->V[1] = LOWORD(lpFileinfo->dwProductVersionMS);
614 appInfo->V[2] = HIWORD(lpFileinfo->dwProductVersionLS);
615 appInfo->V[3] = LOWORD(lpFileinfo->dwProductVersionLS);
616 HeapFree(GetProcessHeap(), 0, pVerInfo);
618 return TRUE;
621 BOOL GetVersionFromApp(ApplicationInfo* appInfo)
623 if (!appInfo)
624 return FALSE;
626 appInfo->V[0] = 0;
627 appInfo->V[1] = 0;
628 appInfo->V[2] = 0;
629 appInfo->V[3] = 0;
631 TCHAR path[MAX_PATH];
632 if (!GetModuleFileName(NULL, path, _countof(path)))
633 return FALSE;
635 return GetVersionFromFile(path, appInfo);
638 BOOL IsReadyToExit()
640 return g_insideCrashHandler == 0 ? TRUE : FALSE;
643 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
645 switch (fdwReason)
647 case DLL_PROCESS_ATTACH:
648 g_hThisDLL = hinstDLL;
649 g_tlsPrevTerminatePtr = TlsAlloc();
650 break;
651 case DLL_PROCESS_DETACH:
652 if (g_tlsPrevTerminatePtr != TLS_OUT_OF_INDEXES)
654 TlsFree(g_tlsPrevTerminatePtr);
655 g_tlsPrevTerminatePtr = TLS_OUT_OF_INDEXES;
657 if (g_prevTopLevelExceptionFilter)
659 ReenableSetUnhandledExceptionFilter();
660 SetUnhandledExceptionFilter(g_prevTopLevelExceptionFilter);
662 if (g_applicationVerifierPresent)
663 RemoveVectoredExceptionHandler(VectoredExceptionHandler);
664 break;
665 case DLL_THREAD_ATTACH:
666 if (g_ownProcess)
668 MakePerThreadInitialization();
670 break;
672 return TRUE;