diff --git a/rehlds/HLTV/Console/build.gradle b/rehlds/HLTV/Console/build.gradle
index 5649284..7d07df5 100644
--- a/rehlds/HLTV/Console/build.gradle
+++ b/rehlds/HLTV/Console/build.gradle
@@ -116,6 +116,7 @@ model {
include "ObjectList.cpp"
include "TokenLine.cpp"
include "textconsole.cpp"
+ include "minidump.cpp"
if (GradleCppUtils.windows) {
include "TextConsoleWin32.cpp"
}
diff --git a/rehlds/HLTV/Console/msvc/Console.vcxproj b/rehlds/HLTV/Console/msvc/Console.vcxproj
index 380c0e1..cdeb0e3 100644
--- a/rehlds/HLTV/Console/msvc/Console.vcxproj
+++ b/rehlds/HLTV/Console/msvc/Console.vcxproj
@@ -19,6 +19,7 @@
+
@@ -60,6 +61,11 @@
Use
Use
+
+ Use
+ Use
+ Use
+
Use
@@ -252,4 +258,4 @@
-
\ No newline at end of file
+
diff --git a/rehlds/HLTV/Console/msvc/Console.vcxproj.filters b/rehlds/HLTV/Console/msvc/Console.vcxproj.filters
index 0bc41ab..715f2ca 100644
--- a/rehlds/HLTV/Console/msvc/Console.vcxproj.filters
+++ b/rehlds/HLTV/Console/msvc/Console.vcxproj.filters
@@ -58,6 +58,9 @@
engine
+
+ common
+
@@ -96,6 +99,9 @@
engine
+
+ common
+
diff --git a/rehlds/HLTV/Console/src/System.cpp b/rehlds/HLTV/Console/src/System.cpp
index 9f70cdc..54db254 100644
--- a/rehlds/HLTV/Console/src/System.cpp
+++ b/rehlds/HLTV/Console/src/System.cpp
@@ -1092,8 +1092,15 @@ unsigned char *System::LoadFile(const char *name, int *length)
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
- gSystem.BuildCommandLine(lpCmdLine);
- return gSystem.Run();
+#ifdef HLTV_FIXES
+ return CatchAndWriteMiniDump([=]()
+ {
+#endif
+ gSystem.BuildCommandLine(lpCmdLine);
+ return gSystem.Run();
+#ifdef HLTV_FIXES
+ }, lpCmdLine);
+#endif
}
void System::BuildCommandLine(char *argv)
diff --git a/rehlds/HLTV/Console/src/precompiled.h b/rehlds/HLTV/Console/src/precompiled.h
index 828c1ff..438bae6 100644
--- a/rehlds/HLTV/Console/src/precompiled.h
+++ b/rehlds/HLTV/Console/src/precompiled.h
@@ -1,5 +1,7 @@
#pragma once
+#include "version/appversion.h"
+
#include "basetypes.h"
#include "FileSystem.h"
#include "strtools.h"
@@ -16,3 +18,7 @@
// Console stuff
#include "System.h"
#include "common/random.h"
+
+#ifdef _WIN32
+#include "minidump.h"
+#endif
diff --git a/rehlds/common/minidump.cpp b/rehlds/common/minidump.cpp
new file mode 100644
index 0000000..f1ee969
--- /dev/null
+++ b/rehlds/common/minidump.cpp
@@ -0,0 +1,203 @@
+#include "precompiled.h"
+
+#if defined(HLTV_FIXES) || defined(LAUNCHER_FIXES)
+#ifdef _WIN32
+
+#if defined(_MSC_VER) && !defined(_IMAGEHLP_)
+#pragma warning(push)
+#pragma warning(disable:4091) // A microsoft header has warnings. Very nice.
+#include
+#pragma warning(pop)
+#endif
+
+// Gets last error.
+static inline HRESULT GetLastHresult()
+{
+ return HRESULT_FROM_WIN32(GetLastError());
+}
+
+#define WIDE_TEXT_HELPER_(quote) L##quote
+#define WIDE_TEXT(quote) WIDE_TEXT_HELPER_(quote)
+
+// Gets application version which is safe for use in minidump file name. Can be entirely constexpr with C++17 and std::array.
+template
+static wchar_t* GetAppVersionForMiniDumpName(wchar_t (&appVersion)[appVersionSize]) {
+ constexpr wchar_t rawAppVersion[]{WIDE_TEXT(APP_VERSION "-" APP_COMMIT_SHA)};
+
+ static_assert(appVersionSize >= ARRAYSIZE(rawAppVersion), "App version buffer size should be enough to store app version.");
+
+ // See https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-pathcleanupspec#remarks for details.
+ constexpr wchar_t invalidPathChars[]{L'\\', L'/', L':', L'*', L'?', L'"', L'<', L'>', L'|', L';', L','};
+
+ size_t outIt{0};
+ for (size_t rawIt{0}; rawIt < ARRAYSIZE(rawAppVersion); ++rawIt)
+ {
+ const wchar_t currentRawIt{rawAppVersion[rawIt]};
+ bool isValidRaw{true};
+
+ for (size_t invalidIt{0}; invalidIt < ARRAYSIZE(invalidPathChars); ++invalidIt)
+ {
+ isValidRaw = invalidPathChars[invalidIt] != currentRawIt;
+
+ if (!isValidRaw)
+ {
+ break;
+ }
+ }
+
+ if (isValidRaw) {
+ appVersion[outIt++] = currentRawIt;
+ }
+ }
+
+ return appVersion;
+}
+
+// Creates a new minidump file and dumps the exception info into it.
+static HRESULT WriteMiniDumpUsingExceptionInfo(unsigned int exceptionCode,
+ struct _EXCEPTION_POINTERS *exceptionInfo, MINIDUMP_TYPE minidumpType)
+{
+ // Counter used to make sure minidump names are unique.
+ static int minidumpsWrittenCount{0};
+
+ HMODULE dbghelpModule{LoadLibraryW(L"DbgHelp.dll")};
+ HRESULT errorCode{dbghelpModule ? S_OK : GetLastHresult()};
+
+ using MiniDumpWriteDumpFn = decltype(&MiniDumpWriteDump);
+ MiniDumpWriteDumpFn miniDumpWriteDump{nullptr};
+ if (SUCCEEDED(errorCode))
+ {
+ miniDumpWriteDump = reinterpret_cast(GetProcAddress(
+ dbghelpModule, "MiniDumpWriteDump"));
+ errorCode = miniDumpWriteDump ? S_OK : GetLastHresult();
+ }
+
+ // Creates a unique filename for the minidump based on the current time and
+ // module name.
+ const time_t timeNow{time(nullptr)};
+ tm *localTimeNow{localtime(&timeNow)};
+ if (localTimeNow == nullptr)
+ {
+ errorCode = E_INVALIDARG;
+ }
+
+ // Strip off the rest of the path from the .exe name.
+ wchar_t moduleName[MAX_PATH];
+ if (SUCCEEDED(errorCode))
+ {
+ ::SetLastError(NOERROR);
+ ::GetModuleFileNameW(nullptr, moduleName, static_cast(ARRAYSIZE(moduleName)));
+
+ errorCode = GetLastHresult();
+ }
+
+ wchar_t fileName[MAX_PATH];
+ HANDLE minidumpFile{nullptr};
+
+ if (SUCCEEDED(errorCode))
+ {
+ wchar_t *strippedModuleName{wcsrchr(moduleName, L'.')};
+ if (strippedModuleName) *strippedModuleName = L'\0';
+
+ strippedModuleName = wcsrchr(moduleName, L'\\');
+ // Move past the last slash.
+ if (strippedModuleName) ++strippedModuleName;
+
+ wchar_t appVersion[ARRAYSIZE(APP_VERSION) + ARRAYSIZE(APP_COMMIT_SHA) + 2];
+ // __crash__