1 // Copyright 2014 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"),
321 HMODULE hMsvcrDll
= NULL
;
322 for (size_t i
= 0; !hMsvcrDll
&& i
< _countof(crtModules
); ++i
)
323 hMsvcrDll
= GetModuleHandle(crtModules
[i
]);
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");
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();
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.");
395 memcpy(g_pConfig
->V
, applicationInfo
->V
, sizeof(applicationInfo
->V
));
397 memset(g_pConfig
->V
, 0, sizeof(g_pConfig
->V
));
398 if (IS_EXIST(Hotfix
))
399 g_pConfig
->Hotfix
= applicationInfo
->Hotfix
;
401 g_pConfig
->Hotfix
= 0;
402 if (IS_EXIST(PrivacyPolicyUrl
) && applicationInfo
->PrivacyPolicyUrl
!= NULL
)
403 g_pConfig
->PrivacyPolicyUrl
= applicationInfo
->PrivacyPolicyUrl
;
405 g_pConfig
->PrivacyPolicyUrl
.Format(L
"http://www.drdump.com/AppPrivacyPolicy.aspx?AppID=%s", (LPCWSTR
)g_pConfig
->ApplicationGUID
);
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
;
421 g_pConfig
->ServiceMode
= 0;
422 g_pConfig
->LeaveDumpFilesInTempFolder
= FALSE
;
424 if (IS_EXIST(OpenProblemInBrowser
))
425 g_pConfig
->OpenProblemInBrowser
= handlerSettings
->OpenProblemInBrowser
;
427 g_pConfig
->OpenProblemInBrowser
= FALSE
;
428 if (IS_EXIST(UseWER
))
429 g_pConfig
->UseWER
= handlerSettings
->UseWER
;
431 g_pConfig
->UseWER
= FALSE
;
432 if (IS_EXIST(SubmitterID
))
433 g_pConfig
->SubmitterID
= handlerSettings
->SubmitterID
;
435 g_pConfig
->SubmitterID
= 0;
436 if (IS_EXIST(SendAdditionalDataWithoutApproval
))
437 g_pConfig
->SendAdditionalDataWithoutApproval
= handlerSettings
->SendAdditionalDataWithoutApproval
;
439 g_pConfig
->SendAdditionalDataWithoutApproval
= FALSE
;
440 if (IS_EXIST(OverrideDefaultFullDumpType
) && IS_EXIST(FullDumpType
) && handlerSettings
->OverrideDefaultFullDumpType
)
441 g_pConfig
->FullDumpType
= handlerSettings
->FullDumpType
;
443 g_pConfig
->FullDumpType
= MiniDumpWithFullMemory
;
444 if (IS_EXIST(LangFilePath
))
445 g_pConfig
->LangFilePath
= handlerSettings
->LangFilePath
;
447 g_pConfig
->LangFilePath
= L
"";
448 if (IS_EXIST(SendRptPath
))
449 g_pConfig
->SendRptPath
= handlerSettings
->SendRptPath
;
451 g_pConfig
->SendRptPath
= L
"";
452 if (IS_EXIST(DbgHelpPath
))
453 g_pConfig
->DbgHelpPath
= handlerSettings
->DbgHelpPath
;
455 g_pConfig
->DbgHelpPath
= L
"";
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;
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
);
520 catch (std::exception
& ex
)
522 OutputDebugStringA(ex
.what());
523 ::MessageBoxA(0, ex
.what(), "CrashHandler initialization error", MB_ICONERROR
);
524 SetLastError(ERROR_INVALID_PARAMETER
);
529 void SetCustomInfo(LPCWSTR text
)
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
)
544 CriticalSection::SyncLock
lock(g_configCS
);
545 g_pConfig
->UserInfo
[key
] = value
;
548 void RemoveUserInfoFromReport(LPCWSTR key
)
552 CriticalSection::SyncLock
lock(g_configCS
);
553 g_pConfig
->UserInfo
.erase(key
);
556 void AddFileToReport(LPCWSTR path
, LPCWSTR 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
;
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
)
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
)
596 DWORD size
= GetFileVersionInfoSize(path
, NULL
);
599 LPVOID pVerInfo
= HeapAlloc(GetProcessHeap(), 0, size
);
600 if (!GetFileVersionInfo(path
, 0, size
, pVerInfo
))
602 HeapFree(GetProcessHeap(), 0, pVerInfo
);
605 VS_FIXEDFILEINFO
* lpFileinfo
= NULL
;
607 if (!VerQueryValue(pVerInfo
, _T("\\"), (LPVOID
*)&lpFileinfo
, &uLen
))
609 HeapFree(GetProcessHeap(), 0, pVerInfo
);
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
);
621 BOOL
GetVersionFromApp(ApplicationInfo
* appInfo
)
631 TCHAR path
[MAX_PATH
];
632 if (!GetModuleFileName(NULL
, path
, _countof(path
)))
635 return GetVersionFromFile(path
, appInfo
);
640 return g_insideCrashHandler
== 0 ? TRUE
: FALSE
;
643 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
647 case DLL_PROCESS_ATTACH
:
648 g_hThisDLL
= hinstDLL
;
649 g_tlsPrevTerminatePtr
= TlsAlloc();
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
);
665 case DLL_THREAD_ATTACH
:
668 MakePerThreadInitialization();