Migrated projects to VS2012
[TortoiseGit.git] / ext / CrashServer / CrashHandler / CrashHandler / CrashHandler.cpp
blob7bdd4a2da63d85b2fb43323ba29a167b21e5a6fd
1 // Copyright 2012 Idol Software, Inc.
2 //
3 // This file is part of CrashHandler library.
4 //
5 // CrashHandler library 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 <signal.h>
24 #include <algorithm>
26 HINSTANCE g_hThisDLL = NULL;
27 bool g_applicationVerifierPresent = false;
28 bool g_ownProcess = false;
29 volatile LONG g_insideCrashHandler = 0;
30 LPTOP_LEVEL_EXCEPTION_FILTER g_prevTopLevelExceptionFilter = NULL;
32 // It should not be destroyed on PROCESS_DETACH, because it may be used later if someone will crash on deinitialization
33 // so it is on heap, but not static (runtime destroy static objects on PROCESS_DETACH)
34 Config* g_pConfig = new Config();
36 DWORD g_tlsPrevTerminatePtr = TLS_OUT_OF_INDEXES;
37 typedef terminate_function (__cdecl *pfn_set_terminate)(terminate_function);
38 pfn_set_terminate g_set_terminate = NULL;
40 enum CrashServerCustomExceptionCodes
42 CRASHSERVER_EXCEPTION_ASSERTION_VIOLATED = CrashHandler::ExceptionAssertionViolated, // 0xCCE17000
43 CRASHSERVER_EXCEPTION_CPP_TERMINATE = 0xCCE17001,
44 CRASHSERVER_EXCEPTION_CPP_PURE_CALL = 0xCCE17002,
45 CRASHSERVER_EXCEPTION_CPP_INVALID_PARAMETER = 0xCCE17003,
48 void ExtractFileFromResource(HMODULE hModule, DWORD resId, LPCTSTR path)
50 HRSRC hDbghelpRes = FindResource(hModule, MAKEINTRESOURCE(resId), RT_RCDATA);
51 if (!hDbghelpRes)
52 throw runtime_error("failed to find file in resources");
54 HGLOBAL hDbghelpGlobal = LoadResource(hModule, hDbghelpRes);
55 if (!hDbghelpGlobal)
56 throw runtime_error("failed to load file from resources");
58 CAtlFile hFile(CreateFile(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL));
59 if (hFile == INVALID_HANDLE_VALUE)
60 throw runtime_error("failed to create file");
62 if (FAILED(hFile.Write(LockResource(hDbghelpGlobal), SizeofResource(hModule, hDbghelpRes))))
63 throw runtime_error("failed to write file");
66 DWORD WINAPI SendReportThread(LPVOID lpParameter)
68 InterlockedIncrement(&g_insideCrashHandler);
70 //::MessageBoxA(0, "SendReportThread", "SendReportThread", 0);
71 MINIDUMP_EXCEPTION_INFORMATION* pExceptInfo = (MINIDUMP_EXCEPTION_INFORMATION*)lpParameter;
72 try
74 WCHAR sendRptExe[MAX_PATH], drive[4], dir[MAX_PATH], fname[MAX_PATH], ext[MAX_PATH];
75 GetModuleFileNameW(NULL, sendRptExe, _countof(sendRptExe));
76 _wsplitpath_s(sendRptExe, drive, dir, fname, ext);
77 _wmakepath_s(sendRptExe, drive, dir, L"SendRpt", L".exe");
78 bool localSendRpt = 0 == _waccess_s(sendRptExe, 00/* Existence only */);
79 if (!localSendRpt)
81 GetTempPathW(_countof(sendRptExe), sendRptExe);
82 wcscat_s(sendRptExe, L"SendRpt.exe");
84 ExtractFileFromResource(g_hThisDLL, IDR_SENDRPT, sendRptExe);
87 CString cmd;
88 cmd.Format(_T("\"%s\" "), sendRptExe);
90 CHandle hProcess;
91 DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &hProcess.m_h, PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | THREAD_ALL_ACCESS, TRUE, 0);
93 CHandle hReportReady(CreateEvent(NULL, TRUE, FALSE, NULL));
94 SetHandleInformation(hReportReady, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
96 Params param;
97 param.Process = hProcess;
98 param.ProcessId = GetCurrentProcessId();
99 param.ExceptInfo = *pExceptInfo;
100 param.WasAssert = pExceptInfo->ExceptionPointers->ExceptionRecord->ExceptionCode == CRASHSERVER_EXCEPTION_ASSERTION_VIOLATED;
101 param.ReportReady = hReportReady;
103 Serializer ser;
104 ser << param << *g_pConfig;
105 cmd.Append(ser.GetHex());
107 STARTUPINFO si = {sizeof(si)};
108 PROCESS_INFORMATION pi;
109 if (!CreateProcess(NULL, cmd.GetBuffer(), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
110 throw std::runtime_error("failed to start SendRpt");
111 CloseHandle(pi.hThread);
113 HANDLE handles[] = { pi.hProcess, hReportReady.m_h };
114 DWORD res = WaitForMultipleObjects(_countof(handles), handles, FALSE, INFINITE);
116 CloseHandle(pi.hProcess);
118 // if hReportReady event signaled, SendRpt is still working, so delete only when SendRpt has finished.
119 if (!localSendRpt && handles[res - WAIT_OBJECT_0] == pi.hProcess)
120 DeleteFileW(sendRptExe);
122 InterlockedDecrement(&g_insideCrashHandler);
124 return TRUE;
126 catch (std::exception& ex)
128 OutputDebugStringA(ex.what());
131 InterlockedDecrement(&g_insideCrashHandler);
133 return FALSE;
136 LONG SendReport(EXCEPTION_POINTERS* pExceptionPointers)
138 if (IsDebuggerPresent())
139 return EXCEPTION_CONTINUE_SEARCH;
141 // We can enter here because of stack overflow, so lets all local variables
142 // be static, because variables on stack can lead to second stack overflow.
143 static DWORD dwThreadId;
144 static HANDLE hThread;
145 static MINIDUMP_EXCEPTION_INFORMATION exceptInfo;
146 exceptInfo.ThreadId = GetCurrentThreadId();
147 exceptInfo.ExceptionPointers = pExceptionPointers;
148 exceptInfo.ClientPointers = FALSE;
150 // If stack overflow, do all processing in another thread
151 if (pExceptionPointers != NULL
152 && pExceptionPointers->ExceptionRecord != NULL
153 && pExceptionPointers->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW
154 && (hThread = CreateThread(NULL, 0, SendReportThread, &exceptInfo, 0, &dwThreadId)) != NULL)
156 WaitForSingleObject(hThread, INFINITE);
158 else
160 SendReportThread(&exceptInfo);
163 if (pExceptionPointers->ExceptionRecord->ExceptionCode == CRASHSERVER_EXCEPTION_ASSERTION_VIOLATED)
164 return EXCEPTION_CONTINUE_EXECUTION;
166 return g_pConfig->UseWER ? EXCEPTION_CONTINUE_SEARCH : EXCEPTION_EXECUTE_HANDLER;
169 LONG WINAPI TopLevelExceptionFilter(EXCEPTION_POINTERS* pExceptionPointers)
171 if (pExceptionPointers->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT
172 && g_applicationVerifierPresent)
174 // This crash has been processed in VectoredExceptionHandler and if we here we want WinQual
175 return EXCEPTION_CONTINUE_SEARCH;
178 return SendReport(pExceptionPointers);
181 LONG CALLBACK VectoredExceptionHandler(EXCEPTION_POINTERS* pExceptionPointers)
183 // Probably this is Application Verifier stop
184 if (pExceptionPointers->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT
185 && g_applicationVerifierPresent)
187 LONG res = SendReport(pExceptionPointers);
188 if (res == EXCEPTION_EXECUTE_HANDLER)
189 ExitProcess(0); // we don't want WinQual from Application Verifier
192 // Asserts should be handled in VectoredExceptionHandler since EXCEPTION_CONTINUE_EXECUTION is used
193 // and __try { ... } __except(EXCEPTION_EXECUTE_HANDLER) { ... } in the way to TopLevelExceptionFilter
194 // may break this logic.
195 if (pExceptionPointers->ExceptionRecord->ExceptionCode == CRASHSERVER_EXCEPTION_ASSERTION_VIOLATED)
196 return SendReport(pExceptionPointers);
198 return EXCEPTION_CONTINUE_SEARCH;
201 FARPROC GetSetUnhandledExceptionFilterPointer()
203 FARPROC suef = NULL;
204 // In Windows 8 SetUnhandledExceptionFilter implementation is in kernelbase
205 if (HMODULE kernelbase = GetModuleHandle(_T("kernelbase")))
206 suef = GetProcAddress(kernelbase, "SetUnhandledExceptionFilter");
207 if (!suef)
209 if (HMODULE kernel32 = GetModuleHandle(_T("kernel32")))
210 suef = GetProcAddress(kernel32, "SetUnhandledExceptionFilter");
212 return suef;
215 void SwitchSetUnhandledExceptionFilter(bool enable)
217 FARPROC suef = GetSetUnhandledExceptionFilterPointer();
218 if (!suef)
219 return;
221 // newBody is something like that:
223 // LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER)
224 // {
225 // return NULL;
226 // }
227 #if defined(_M_X64)
228 static const BYTE newBody[] =
230 0x33, 0xC0, // xor eax,eax
231 0xC3 // ret
233 #elif defined(_M_IX86)
234 static const BYTE newBody[] =
236 0x8B, 0xFF, // mov edi,edi <- for hotpatching
237 0x33, 0xC0, // xor eax,eax
238 0xC2, 0x04, 0x00 // ret 4
240 #else
241 # error Unsupported architecture
242 #endif
243 const SIZE_T bodySize = sizeof(newBody);
245 static BYTE oldBody[bodySize] = { 0 };
247 DWORD oldProtection;
248 if (!VirtualProtect(suef, bodySize, PAGE_EXECUTE_READWRITE, &oldProtection))
249 return;
250 if (!enable)
252 memcpy(oldBody, suef, bodySize);
253 memcpy(suef, newBody, bodySize);
255 else if (oldBody[0] != 0)
257 memcpy(suef, oldBody, bodySize);
260 VirtualProtect(suef, bodySize, oldProtection, &oldProtection);
263 void DisableSetUnhandledExceptionFilter()
265 SwitchSetUnhandledExceptionFilter(false);
268 void ReenableSetUnhandledExceptionFilter()
270 SwitchSetUnhandledExceptionFilter(true);
273 // This code should be inplace, so it is a macro
274 #define SendReportWithCode(code) __try { RaiseException(code, EXCEPTION_NONCONTINUABLE, 0, NULL); } __except(TopLevelExceptionFilter(GetExceptionInformation())) {}
276 void CrashServer_SendAssertionViolated()
278 RaiseException(CRASHSERVER_EXCEPTION_ASSERTION_VIOLATED, 0, 0, NULL);
281 void CrashServer_TerminateHandler()
283 SendReportWithCode(CRASHSERVER_EXCEPTION_CPP_TERMINATE);
285 if (g_tlsPrevTerminatePtr != TLS_OUT_OF_INDEXES)
287 terminate_function prev_terminate = static_cast<terminate_function>(TlsGetValue(g_tlsPrevTerminatePtr));
288 if (prev_terminate)
289 prev_terminate();
292 if (!g_pConfig->UseWER)
293 ExitProcess(0);
296 void CrashServer_PureCallHandler()
298 SendReportWithCode(CRASHSERVER_EXCEPTION_CPP_PURE_CALL);
299 ExitProcess(0);
302 void CrashServer_InvalidParameterHandler(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t)
304 SendReportWithCode(CRASHSERVER_EXCEPTION_CPP_INVALID_PARAMETER);
305 ExitProcess(0);
308 void CrashServer_SigAbrtHandler(int)
310 SendReportWithCode(CRASHSERVER_EXCEPTION_CPP_TERMINATE);
311 ExitProcess(0);
314 void MakePerThreadInitialization()
316 if (g_tlsPrevTerminatePtr != TLS_OUT_OF_INDEXES && g_set_terminate)
317 TlsSetValue(g_tlsPrevTerminatePtr, g_set_terminate(CrashServer_TerminateHandler));
320 void InitCrtErrorHandlers()
322 LPCTSTR crtModules[] = {
323 _T("msvcr70"), _T("msvcr70d"),
324 _T("msvcr71"), _T("msvcr71d"),
325 _T("msvcr80"), _T("msvcr80d"),
326 _T("msvcr90"), _T("msvcr90d"),
327 _T("msvcr100"), _T("msvcr100d"),
328 _T("msvcr110"), _T("msvcr110d"),
329 _T("msvcr120"), _T("msvcr120d"),
332 HMODULE hMsvcrDll = NULL;
333 for (size_t i = 0; !hMsvcrDll && i < _countof(crtModules); ++i)
334 hMsvcrDll = GetModuleHandle(crtModules[i]);
336 if (!hMsvcrDll)
337 return;
339 g_set_terminate = (pfn_set_terminate) GetProcAddress(hMsvcrDll, "?set_terminate@@YAP6AXXZP6AXXZ@Z");
341 typedef _purecall_handler (__cdecl *pfn_set_purecall_handler)(_purecall_handler);
342 pfn_set_purecall_handler l_set_purecall_handler = (pfn_set_purecall_handler) GetProcAddress(hMsvcrDll, "_set_purecall_handler");
343 if (l_set_purecall_handler)
344 l_set_purecall_handler(CrashServer_PureCallHandler);
346 typedef _invalid_parameter_handler (__cdecl *pfn_set_invalid_parameter_handler)(_invalid_parameter_handler);
347 pfn_set_invalid_parameter_handler l_set_invalid_parameter_handler = (pfn_set_invalid_parameter_handler) GetProcAddress(hMsvcrDll, "_set_invalid_parameter_handler");
348 if (l_set_invalid_parameter_handler)
349 l_set_invalid_parameter_handler(CrashServer_InvalidParameterHandler);
351 typedef void (__cdecl *pfn_signal)(int sig, void (__cdecl *func)(int));
352 pfn_signal l_signal = (pfn_signal) GetProcAddress(hMsvcrDll, "signal");
353 if (l_signal)
354 l_signal(SIGABRT, CrashServer_SigAbrtHandler);
357 BOOL InitCrashHandler(ApplicationInfo* applicationInfo, HandlerSettings* handlerSettings, BOOL ownProcess)
359 #define IS_EXIST(field) (FIELD_OFFSET(ApplicationInfo, field) < applicationInfo->ApplicationInfoSize)
360 if (applicationInfo == NULL
361 || applicationInfo->ApplicationInfoSize == 0
362 || applicationInfo->ApplicationInfoSize > sizeof(ApplicationInfo)
363 || !IS_EXIST(ApplicationGUID) || applicationInfo->ApplicationGUID == NULL
364 || !IS_EXIST(Prefix) || applicationInfo->Prefix == NULL
365 || !IS_EXIST(AppName) || applicationInfo->AppName == NULL
366 || !IS_EXIST(Company) || applicationInfo->Company == NULL)
368 SetLastError(ERROR_INVALID_PARAMETER);
369 return FALSE;
372 g_pConfig->ApplicationGUID = applicationInfo->ApplicationGUID;
373 g_pConfig->Prefix = applicationInfo->Prefix;
374 g_pConfig->AppName = applicationInfo->AppName;
375 g_pConfig->Company = applicationInfo->Company;
376 if (IS_EXIST(V))
377 memcpy(g_pConfig->V, applicationInfo->V, sizeof(applicationInfo->V));
378 else
379 memset(g_pConfig->V, 0, sizeof(g_pConfig->V));
380 if (IS_EXIST(Hotfix))
381 g_pConfig->Hotfix = applicationInfo->Hotfix;
382 else
383 g_pConfig->Hotfix = 0;
384 if (IS_EXIST(PrivacyPolicyUrl) && applicationInfo->PrivacyPolicyUrl != NULL)
385 g_pConfig->PrivacyPolicyUrl = applicationInfo->PrivacyPolicyUrl;
386 else
387 g_pConfig->PrivacyPolicyUrl.Format(L"http://www.crash-server.com/AppPrivacyPolicy.aspx?AppID=%s", (LPCWSTR)g_pConfig->ApplicationGUID);
388 #undef IS_EXIST
390 #define IS_EXIST(field) (handlerSettings != NULL && (FIELD_OFFSET(HandlerSettings, field) < handlerSettings->HandlerSettingsSize))
392 if (handlerSettings != NULL
393 && (handlerSettings->HandlerSettingsSize == 0 || handlerSettings->HandlerSettingsSize > sizeof(HandlerSettings)))
395 SetLastError(ERROR_INVALID_PARAMETER);
396 return FALSE;
399 if (IS_EXIST(LeaveDumpFilesInTempFolder))
401 g_pConfig->ServiceMode = handlerSettings->LeaveDumpFilesInTempFolder == 2; // hidden behavior (used for dumpparser)
402 g_pConfig->LeaveDumpFilesInTempFolder = handlerSettings->LeaveDumpFilesInTempFolder != FALSE;
404 else
406 g_pConfig->ServiceMode = 0;
407 g_pConfig->LeaveDumpFilesInTempFolder = FALSE;
409 if (IS_EXIST(OpenProblemInBrowser))
410 g_pConfig->OpenProblemInBrowser = handlerSettings->OpenProblemInBrowser;
411 else
412 g_pConfig->OpenProblemInBrowser = FALSE;
413 if (IS_EXIST(UseWER))
414 g_pConfig->UseWER = handlerSettings->UseWER;
415 else
416 g_pConfig->UseWER = FALSE;
417 if (IS_EXIST(SubmitterID))
418 g_pConfig->SubmitterID = handlerSettings->SubmitterID;
419 else
420 g_pConfig->SubmitterID = 0;
421 #undef IS_EXIST
423 WCHAR path[MAX_PATH], drive[MAX_PATH], dir[MAX_PATH], fname[MAX_PATH], ext[MAX_PATH];
424 GetModuleFileNameW(NULL, path, _countof(path));
425 _wsplitpath_s(path, drive, dir, fname, ext);
426 g_pConfig->ProcessName = CStringW(fname) + ext;
427 g_pConfig->ProcessName.MakeLower();
429 g_ownProcess = ownProcess != FALSE;
431 static bool inited = false;
432 if (!inited)
434 if (g_ownProcess)
436 // Application verifier sets its own VectoredExceptionHandler
437 // and Application verifier breaks redirected to WinQual.
438 // After that TopLevelExceptionFilter works.
439 // This behavior looks bad and anyway we don't need WinQual.
440 // So we set our VectoredExceptionHandler before AppVerifier and
441 // catch problems first.
442 g_applicationVerifierPresent = GetModuleHandle(_T("verifier.dll")) != NULL;
443 if (g_applicationVerifierPresent)
444 AddVectoredExceptionHandler(TRUE, VectoredExceptionHandler);
446 g_prevTopLevelExceptionFilter = SetUnhandledExceptionFilter(TopLevelExceptionFilter);
447 // There is a lot of libraries that want to set their own wrong UnhandledExceptionFilter in our application.
448 // One of these is MSVCRT with __report_gsfailure and _call_reportfault leading to many
449 // of MSVCRT error reports to be redirected to Dr. Watson.
450 DisableSetUnhandledExceptionFilter();
452 InitCrtErrorHandlers();
453 MakePerThreadInitialization();
456 // Need to lock library in process.
457 // Since some crashes appears on process deinitialization and we should be ready to handle it.
458 LoadLibrary(_T("crshhndl.dll"));
459 inited = true;
462 return TRUE;
465 void AddUserInfoToReport(LPCWSTR key, LPCWSTR value)
467 if (!g_pConfig)
468 return;
469 g_pConfig->UserInfo.push_back(make_pair(CStringW(key), value));
472 void AddFileToReport(LPCWSTR path, LPCWSTR reportFileName)
474 if (!g_pConfig)
475 return;
476 CStringW fileName;
477 if (!reportFileName)
479 WCHAR drive[MAX_PATH], dir[MAX_PATH], fname[MAX_PATH], ext[MAX_PATH];
480 _wsplitpath_s(path, drive, dir, fname, ext);
481 fileName = CStringW(fname) + ext;
483 else
485 fileName = reportFileName;
487 g_pConfig->FilesToAttach.push_back(make_pair(CStringW(path), fileName));
490 void RemoveFileFromReport(LPCWSTR path)
492 if (!g_pConfig)
493 return;
494 /* TODO: needs to be converted to work with VS2008, but atm it's never called */
495 #if _MSC_VER >= 1600
496 auto it = std::find_if(g_pConfig->FilesToAttach.begin(), g_pConfig->FilesToAttach.end(),
497 [path](std::pair<CStringW, CStringW>& x){ return x.first == path; });
498 if (it != g_pConfig->FilesToAttach.end())
499 g_pConfig->FilesToAttach.erase(it);
500 #endif
503 BOOL GetVersionFromFile(LPCWSTR path, ApplicationInfo* appInfo)
505 if (!path || !appInfo)
506 return FALSE;
508 appInfo->V[0] = 0;
509 appInfo->V[1] = 0;
510 appInfo->V[2] = 0;
511 appInfo->V[3] = 0;
513 DWORD size = GetFileVersionInfoSize(path, NULL);
514 if (size == 0)
515 return FALSE;
516 LPVOID pVerInfo = HeapAlloc(GetProcessHeap(), 0, size);
517 if (!GetFileVersionInfo(path, 0, size, pVerInfo))
519 HeapFree(GetProcessHeap(), 0, pVerInfo);
520 return FALSE;
522 VS_FIXEDFILEINFO* lpFileinfo = NULL;
523 UINT uLen;
524 if (!VerQueryValue(pVerInfo, _T("\\"), (LPVOID*)&lpFileinfo, &uLen))
526 HeapFree(GetProcessHeap(), 0, pVerInfo);
527 return FALSE;
529 appInfo->V[0] = HIWORD(lpFileinfo->dwProductVersionMS);
530 appInfo->V[1] = LOWORD(lpFileinfo->dwProductVersionMS);
531 appInfo->V[2] = HIWORD(lpFileinfo->dwProductVersionLS);
532 appInfo->V[3] = LOWORD(lpFileinfo->dwProductVersionLS);
533 HeapFree(GetProcessHeap(), 0, pVerInfo);
535 return TRUE;
538 BOOL GetVersionFromApp(ApplicationInfo* appInfo)
540 if (!appInfo)
541 return FALSE;
543 appInfo->V[0] = 0;
544 appInfo->V[1] = 0;
545 appInfo->V[2] = 0;
546 appInfo->V[3] = 0;
548 TCHAR path[MAX_PATH];
549 if (!GetModuleFileName(NULL, path, _countof(path)))
550 return FALSE;
552 return GetVersionFromFile(path, appInfo);
555 BOOL IsReadyToExit()
557 return g_insideCrashHandler == 0 ? TRUE : FALSE;
560 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
562 switch (fdwReason)
564 case DLL_PROCESS_ATTACH:
565 g_hThisDLL = hinstDLL;
566 g_tlsPrevTerminatePtr = TlsAlloc();
567 break;
568 case DLL_PROCESS_DETACH:
569 if (g_tlsPrevTerminatePtr != TLS_OUT_OF_INDEXES)
571 TlsFree(g_tlsPrevTerminatePtr);
572 g_tlsPrevTerminatePtr = TLS_OUT_OF_INDEXES;
574 if (g_prevTopLevelExceptionFilter)
576 ReenableSetUnhandledExceptionFilter();
577 SetUnhandledExceptionFilter(g_prevTopLevelExceptionFilter);
579 if (g_applicationVerifierPresent)
580 RemoveVectoredExceptionHandler(VectoredExceptionHandler);
581 break;
582 case DLL_THREAD_ATTACH:
583 if (g_ownProcess)
585 MakePerThreadInitialization();
587 break;
589 return TRUE;