1 // Copyright 2012, 2014-2015 Idol Software, Inc.
3 // This file is part of Doctor Dump SDK.
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.
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/>.
20 #include "CrashHandlerExport.h"
21 #include "..\SendRpt\Config.h"
22 #include "..\SendRpt\Serializer.h"
23 #include "..\..\CommonLibs\Log\synchro.h"
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
53 Error(const char* format
, ...)
57 m_description
.FormatV(format
, ap
);
61 const char* what() const { return m_description
; }
64 CStringA m_description
;
67 DWORD WINAPI
SendReportThread(LPVOID lpParameter
)
69 InterlockedIncrement(&g_insideCrashHandler
);
71 MINIDUMP_EXCEPTION_INFORMATION
* pExceptInfo
= (MINIDUMP_EXCEPTION_INFORMATION
*)lpParameter
;
75 cmd
.Format(L
"\"%ls\" ", (LPCWSTR
)g_pConfig
->SendRptPath
);
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
;
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]);
97 CriticalSection::SyncLock
lock(g_configCS
);
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
);
117 catch (std::exception
& ex
)
119 OutputDebugStringA(ex
.what());
122 InterlockedDecrement(&g_insideCrashHandler
);
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
);
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()
197 // In Windows 8 SetUnhandledExceptionFilter implementation is in kernelbase
198 if (HMODULE kernelbase
= GetModuleHandle(_T("kernelbase")))
199 suef
= GetProcAddress(kernelbase
, "SetUnhandledExceptionFilter");
202 if (HMODULE kernel32
= GetModuleHandle(_T("kernel32")))
203 suef
= GetProcAddress(kernel32
, "SetUnhandledExceptionFilter");
208 void SwitchSetUnhandledExceptionFilter(bool enable
)
210 FARPROC suef
= GetSetUnhandledExceptionFilterPointer();
214 // newBody is something like that:
216 // LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER)
221 static const BYTE newBody
[] =
223 0x33, 0xC0, // xor eax,eax
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
234 # error Unsupported architecture
236 const SIZE_T bodySize
= sizeof(newBody
);
238 static BYTE oldBody
[bodySize
] = { 0 };
241 if (!VirtualProtect(suef
, bodySize
, PAGE_EXECUTE_READWRITE
, &oldProtection
))
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
));
280 if (!g_pConfig
->UseWER
)
284 void SkipDoctorDump_PureCallHandler()
286 SendReportWithCode(DOCTORDUMP_EXCEPTION_CPP_PURE_CALL
);
290 void SkipDoctorDump_InvalidParameterHandler(const wchar_t *, const wchar_t *, const wchar_t *, unsigned int, uintptr_t)
292 SendReportWithCode(DOCTORDUMP_EXCEPTION_CPP_INVALID_PARAMETER
);
296 void SkipDoctorDump_SigAbrtHandler(int)
298 SendReportWithCode(DOCTORDUMP_EXCEPTION_CPP_TERMINATE
);
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
]);
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");
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();
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.");
396 memcpy(g_pConfig
->V
, applicationInfo
->V
, sizeof(applicationInfo
->V
));
398 memset(g_pConfig
->V
, 0, sizeof(g_pConfig
->V
));
399 if (IS_EXIST(Hotfix
))
400 g_pConfig
->Hotfix
= applicationInfo
->Hotfix
;
402 g_pConfig
->Hotfix
= 0;
403 if (IS_EXIST(PrivacyPolicyUrl
) && applicationInfo
->PrivacyPolicyUrl
!= NULL
)
404 g_pConfig
->PrivacyPolicyUrl
= applicationInfo
->PrivacyPolicyUrl
;
406 g_pConfig
->PrivacyPolicyUrl
.Format(L
"http://www.drdump.com/AppPrivacyPolicy.aspx?AppID=%s", (LPCWSTR
)g_pConfig
->ApplicationGUID
);
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
;
422 g_pConfig
->ServiceMode
= 0;
423 g_pConfig
->LeaveDumpFilesInTempFolder
= FALSE
;
425 if (IS_EXIST(OpenProblemInBrowser
))
426 g_pConfig
->OpenProblemInBrowser
= handlerSettings
->OpenProblemInBrowser
;
428 g_pConfig
->OpenProblemInBrowser
= FALSE
;
429 if (IS_EXIST(UseWER
))
430 g_pConfig
->UseWER
= handlerSettings
->UseWER
;
432 g_pConfig
->UseWER
= FALSE
;
433 if (IS_EXIST(SubmitterID
))
434 g_pConfig
->SubmitterID
= handlerSettings
->SubmitterID
;
436 g_pConfig
->SubmitterID
= 0;
437 if (IS_EXIST(SendAdditionalDataWithoutApproval
))
438 g_pConfig
->SendAdditionalDataWithoutApproval
= handlerSettings
->SendAdditionalDataWithoutApproval
;
440 g_pConfig
->SendAdditionalDataWithoutApproval
= FALSE
;
441 if (IS_EXIST(OverrideDefaultFullDumpType
) && IS_EXIST(FullDumpType
) && handlerSettings
->OverrideDefaultFullDumpType
)
442 g_pConfig
->FullDumpType
= handlerSettings
->FullDumpType
;
444 g_pConfig
->FullDumpType
= MiniDumpWithFullMemory
;
445 if (IS_EXIST(LangFilePath
))
446 g_pConfig
->LangFilePath
= handlerSettings
->LangFilePath
;
448 g_pConfig
->LangFilePath
= L
"";
449 if (IS_EXIST(SendRptPath
))
450 g_pConfig
->SendRptPath
= handlerSettings
->SendRptPath
;
452 g_pConfig
->SendRptPath
= L
"";
453 if (IS_EXIST(DbgHelpPath
))
454 g_pConfig
->DbgHelpPath
= handlerSettings
->DbgHelpPath
;
456 g_pConfig
->DbgHelpPath
= L
"";
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;
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
);
521 catch (std::exception
& ex
)
523 OutputDebugStringA(ex
.what());
524 ::MessageBoxA(0, ex
.what(), "CrashHandler initialization error", MB_ICONERROR
);
525 SetLastError(ERROR_INVALID_PARAMETER
);
530 void SetCustomInfo(LPCWSTR text
)
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
)
545 CriticalSection::SyncLock
lock(g_configCS
);
546 g_pConfig
->UserInfo
[key
] = value
;
549 void RemoveUserInfoFromReport(LPCWSTR key
)
553 CriticalSection::SyncLock
lock(g_configCS
);
554 g_pConfig
->UserInfo
.erase(key
);
557 void AddFileToReport(LPCWSTR path
, LPCWSTR 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
;
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
)
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
)
597 DWORD size
= GetFileVersionInfoSize(path
, NULL
);
600 LPVOID pVerInfo
= HeapAlloc(GetProcessHeap(), 0, size
);
601 if (!GetFileVersionInfo(path
, 0, size
, pVerInfo
))
603 HeapFree(GetProcessHeap(), 0, pVerInfo
);
606 VS_FIXEDFILEINFO
* lpFileinfo
= NULL
;
608 if (!VerQueryValue(pVerInfo
, _T("\\"), (LPVOID
*)&lpFileinfo
, &uLen
))
610 HeapFree(GetProcessHeap(), 0, pVerInfo
);
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
);
622 BOOL
GetVersionFromApp(ApplicationInfo
* appInfo
)
632 TCHAR path
[MAX_PATH
];
633 if (!GetModuleFileName(NULL
, path
, _countof(path
)))
636 return GetVersionFromFile(path
, appInfo
);
641 return g_insideCrashHandler
== 0 ? TRUE
: FALSE
;
644 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
648 case DLL_PROCESS_ATTACH
:
649 g_hThisDLL
= hinstDLL
;
650 g_tlsPrevTerminatePtr
= TlsAlloc();
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
);
666 case DLL_THREAD_ATTACH
:
669 MakePerThreadInitialization();