only set var value once in binds

fix stack trace crashing the game
output current time in crash/fail log
This commit is contained in:
rei-2
2025-11-21 19:36:38 -05:00
parent 68c1d0530f
commit fce4740bf3
20 changed files with 116 additions and 82 deletions
+2 -2
View File
@@ -1078,7 +1078,7 @@
<ClCompile Include="src\SDK\Helpers\TraceFilters\TraceFilters.cpp" />
<ClCompile Include="src\SDK\SDK.cpp" />
<ClCompile Include="src\SDK\Helpers\ConVars\ConVars.cpp" />
<ClCompile Include="src\Utils\CrashLog\CrashLog.cpp" />
<ClCompile Include="src\Utils\ErrorLog\ErrorLog.cpp" />
<ClCompile Include="src\Utils\Hooks\Hooks.cpp" />
<ClCompile Include="src\Utils\Interfaces\Interfaces.cpp" />
<ClCompile Include="src\Utils\KeyHandler\KeyHandler.cpp" />
@@ -1458,7 +1458,7 @@
<ClInclude Include="src\SDK\SDK.h" />
<ClInclude Include="src\SDK\Vars.h" />
<ClInclude Include="src\SDK\Helpers\ConVars\ConVars.h" />
<ClInclude Include="src\Utils\CrashLog\CrashLog.h" />
<ClInclude Include="src\Utils\ErrorLog\ErrorLog.h" />
<ClInclude Include="src\Utils\Macros\Macros.h" />
<ClInclude Include="src\Utils\Hash\FNV1A.h" />
<ClInclude Include="src\Utils\Hooks\Hooks.h" />
+2 -2
View File
@@ -82,7 +82,7 @@
<ClCompile Include="src\SDK\Definitions\Misc\ChecksumCRC.cpp" />
<ClCompile Include="src\Hooks\Direct3DDevice9.cpp" />
<ClCompile Include="src\SDK\Events\Events.cpp" />
<ClCompile Include="src\Utils\CrashLog\CrashLog.cpp" />
<ClCompile Include="src\Utils\ErrorLog\ErrorLog.cpp" />
<ClCompile Include="src\BytePatches\BytePatches.cpp" />
<ClCompile Include="include\ImGui\imgui_freetype.cpp" />
<ClCompile Include="src\Features\Misc\AutoVote\AutoVote.cpp" />
@@ -458,7 +458,7 @@
<ClInclude Include="src\SDK\Definitions\Main\CCaptureFlag.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\IPanel.h" />
<ClInclude Include="src\SDK\Definitions\Interfaces\CTFGCClientSystem.h" />
<ClInclude Include="src\Utils\CrashLog\CrashLog.h" />
<ClInclude Include="src\Utils\ErrorLog\ErrorLog.h" />
<ClInclude Include="src\BytePatches\BytePatches.h" />
<ClInclude Include="include\freetype\config\ftconfig.h" />
<ClInclude Include="include\freetype\config\ftheader.h" />
+17 -5
View File
@@ -31,11 +31,15 @@ static inline bool CheckDXLevel()
auto mat_dxlevel = H::ConVars.FindVar("mat_dxlevel");
if (mat_dxlevel->GetInt() < 90)
{
//const char* sMessage = "You are running with graphics options that Amalgam does not support. -dxlevel must be at least 90.";
const char* sMessage = "You are running with graphics options that Amalgam does not support. It is recommended for -dxlevel to be at least 90.";
/*
const char* sMessage = "You are running with graphics options that Amalgam does not support. -dxlevel must be at least 90.";
U::Core.AppendFailText(sMessage);
SDK::Output("Amalgam", sMessage, { 175, 150, 255 }, OUTPUT_CONSOLE | OUTPUT_DEBUG | OUTPUT_TOAST | OUTPUT_MENU);
//return false;
return false;
*/
const char* sMessage = "You are running with graphics options that Amalgam does not support. It is recommended for -dxlevel to be at least 90.";
SDK::Output("Amalgam", sMessage, { 175, 150, 255 }, OUTPUT_CONSOLE | OUTPUT_DEBUG | OUTPUT_TOAST | OUTPUT_MENU);
}
return true;
@@ -43,20 +47,28 @@ static inline bool CheckDXLevel()
void CCore::AppendFailText(const char* sMessage)
{
if (m_ssFailStream.str().empty())
{
m_ssFailStream << "Built @ " __DATE__ ", " __TIME__ ", " __CONFIGURATION__ "\n";
m_ssFailStream << std::format("Time @ {}, {}\n", SDK::GetDate(), SDK::GetTime());
m_ssFailStream << "\n";
}
m_ssFailStream << std::format("{}\n", sMessage);
OutputDebugStringA(std::format("{}\n", sMessage).c_str());
}
void CCore::LogFailText()
{
m_ssFailStream << "\nBuilt @ " __DATE__ ", " __TIME__ ", " __CONFIGURATION__ "\n";
m_ssFailStream << "Ctrl + C to copy. \n";
try
{
std::ofstream file;
file.open(F::Configs.m_sConfigPath + "fail_log.txt", std::ios_base::app);
file << m_ssFailStream.str() + "\n\n\n";
file.close();
m_ssFailStream << "\n";
m_ssFailStream << "Ctrl + C to copy. \n";
m_ssFailStream << "Logged to Amalgam\\fail_log.txt. ";
}
catch (...) {}
+3 -3
View File
@@ -1,16 +1,16 @@
#include <Windows.h>
#include "Core/Core.h"
#include "Utils/CrashLog/CrashLog.h"
#include "Utils/ErrorLog/ErrorLog.h"
DWORD WINAPI MainThread(LPVOID lpParam)
{
U::CrashLog.Initialize(lpParam);
U::ErrorLog.Initialize(lpParam);
U::Core.Load();
U::Core.Loop();
U::Core.Unload();
U::CrashLog.Unload();
U::ErrorLog.Unload();
FreeLibraryAndExitThread(static_cast<HMODULE>(lpParam), EXIT_SUCCESS);
}
+7 -3
View File
@@ -16,14 +16,17 @@ static inline void SetMain(BaseVar*& pBase, int iBind)
}
#define Set(t, b) if (IsType(t)) SetMain<t>(pBase, b);
static std::unordered_map<BaseVar*, bool> s_mVars = {};
static inline void LoopVars(int iBind, std::vector<BaseVar*>& vVars = G::Vars)
{
const bool bDefault = iBind == DEFAULT_BIND;
for (auto pBase : vVars)
{
if (pBase->m_iFlags & (NOSAVE | NOBIND) && !bDefault)
if (s_mVars.contains(pBase) || pBase->m_iFlags & (NOSAVE | NOBIND) && !bDefault)
continue;
s_mVars[pBase];
Set(bool, iBind)
else Set(int, iBind)
else Set(float, iBind)
@@ -44,7 +47,7 @@ static inline void GetBinds(int iParent, CTFPlayer* pLocal, CTFWeaponBase* pWeap
if (vBinds.empty())
return;
for (int i = int(vBinds.size() - 1); i >= 0; i--) // reverse so higher binds have priority over vars
for (int i = 0; i < vBinds.size(); i++)
{
auto& tBind = vBinds[i];
if (iParent != tBind.m_iParent || !tBind.m_bEnabled)
@@ -130,8 +133,9 @@ static inline void GetBinds(int iParent, CTFPlayer* pLocal, CTFWeaponBase* pWeap
void CBinds::SetVars(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, bool bManage)
{
LoopVars(DEFAULT_BIND);
s_mVars.clear();
GetBinds(DEFAULT_BIND, pLocal, pWeapon, m_vBinds, bManage);
LoopVars(DEFAULT_BIND);
}
void CBinds::Run()
+1 -1
View File
@@ -69,7 +69,7 @@ static std::unordered_map<uint32_t, CommandCallback> s_mCommands = {
}
},
{
FNV1A::Hash32Const("clearchat"),
FNV1A::Hash32Const("clear_chat"),
[](const std::deque<const char*>& vArgs)
{
I::ClientModeShared->m_pChatElement->SetText("");
+6 -4
View File
@@ -1244,7 +1244,7 @@ void CMenu::MenuLogs(int iTab)
{
if (I::EngineClient->IsInGame())
{
std::lock_guard lock(F::PlayerUtils.m_mutex);
std::lock_guard tLock(m_tMutex);
const auto& vPlayers = F::PlayerUtils.m_vPlayerCache;
std::unordered_map<uint64_t, std::vector<const ListPlayer*>> mParties = {};
@@ -2462,9 +2462,11 @@ void CMenu::MenuSettings(int iTab)
drawConfigs(sStaticName);
} EndSection();
SetCursorPosX(GetCursorPosX() + 8);
PushStyleColor(ImGuiCol_Text, F::Render.Inactive.Value);
SetCursorPosX(GetCursorPosX() + GetStyle().WindowPadding.x);
FText("Built @ " __DATE__ ", " __TIME__ ", " __CONFIGURATION__);
//SetCursorPosX(GetCursorPosX() + GetStyle().WindowPadding.x);
//FText(std::format("Time @ {}, {}", SDK::GetDate(), SDK::GetTime()).c_str());
PopStyleColor();
/* Column 2 */
@@ -2585,7 +2587,7 @@ void CMenu::MenuSettings(int iTab)
if (iParent != _tBind.m_iParent || mBinds.contains(_iBind))
continue;
mBinds[_iBind] = true;
mBinds[_iBind];
i++;
//if (iParent == iLayer && iNumber >= i)
@@ -2628,7 +2630,7 @@ void CMenu::MenuSettings(int iTab)
if (iParent != DEFAULT_BIND - 1 && iParent != _tBind.m_iParent || mBinds.contains(_iBind))
continue;
mBinds[_iBind] = true;
mBinds[_iBind];
std::string sType; std::string sInfo;
switch (_tBind.m_iType)
+3
View File
@@ -2,6 +2,7 @@
#include "../../../SDK/SDK.h"
#include "../Render.h"
#include <ImGui/TextEditor.h>
#include <mutex>
struct Output_t
{
@@ -38,6 +39,8 @@ public:
bool m_bIsOpen = false;
bool m_bInKeybind = false;
bool m_bWindowHovered = false;
std::mutex m_tMutex;
};
ADD_FEATURE(CMenu, Menu);
+4 -2
View File
@@ -1,7 +1,8 @@
#include "PlayerUtils.h"
#include "../../SDK/Definitions/Types.h"
#include "../ImGui/Menu/Menu.h"
#include "../Output/Output.h"
#include "../../SDK/Definitions/Types.h"
uint32_t CPlayerlistUtils::GetAccountID(int iIndex)
{
@@ -433,8 +434,9 @@ void CPlayerlistUtils::Store()
if (!tTimer.Run(1.f))
return;
std::lock_guard lock(m_mutex);
std::lock_guard tLock(F::Menu.m_tMutex);
m_vPlayerCache.clear();
auto pResource = H::Entities.GetResource();
if (!pResource)
return;
@@ -1,6 +1,5 @@
#pragma once
#include "../../SDK/SDK.h"
#include <mutex>
#define DEFAULT_TAG 0
#define IGNORED_TAG (DEFAULT_TAG-1)
@@ -60,8 +59,6 @@ public:
bool m_bLoad = true;
bool m_bSave = false;
std::mutex m_mutex;
private:
std::vector<int> m_vDummy = {};
+1 -1
View File
@@ -75,7 +75,7 @@ void CChams::DrawModel(CBaseEntity* pEntity, Chams_t& tChams, IMatRenderContext*
pRenderContext->SetStencilEnable(false);
pRenderContext->DepthRange(0.f, 1.f);
m_mEntities[pEntity->entindex()] = true;
m_mEntities[pEntity->entindex()];
}
I::RenderView->SetColorModulation(m_tOriginalColor);
+1 -1
View File
@@ -332,7 +332,7 @@ void CGlow::Initialize()
{
m_pMatGlowColor = I::MaterialSystem->FindMaterial("dev/glow_color", TEXTURE_GROUP_OTHER);
m_pMatGlowColor->IncrementReferenceCount();
F::Materials.m_mMatList[m_pMatGlowColor] = true;
F::Materials.m_mMatList[m_pMatGlowColor];
}
if (!m_pRenderBuffer1)
@@ -11,7 +11,7 @@
IMaterial* CMaterials::Create(char const* szName, KeyValues* pKV)
{
IMaterial* pMaterial = I::MaterialSystem->CreateMaterial(szName, pKV);
m_mMatList[pMaterial] = true;
m_mMatList[pMaterial];
return pMaterial;
}
@@ -37,7 +37,7 @@ MAKE_HOOK(CHLClient_DispatchUserMessage, U::Memory.GetVirtual(I::Client, 36), bo
int iVoiceMenu = msgData.ReadByte();
int iCommandID = msgData.ReadByte();
if (iVoiceMenu == 1 && iCommandID == 6)
F::AutoHeal.m_mMedicCallers[iEntityID] = true;
F::AutoHeal.m_mMedicCallers[iEntityID];
break;
}
+1 -1
View File
@@ -12,7 +12,7 @@ MAKE_HOOK(CMaterial_Uncache, S::CMaterial_Uncache(), void,
return CALL_ORIGINAL(rcx, bPreserveVars);
#endif
if (rcx && F::Materials.m_mMatList.contains(rcx))
if (F::Materials.m_mMatList.contains(rcx))
return;
CALL_ORIGINAL(rcx, bPreserveVars);
@@ -17,16 +17,6 @@ MAKE_HOOK(IVModelRender_DrawModelExecute, U::Memory.GetVirtual(I::ModelRender, 1
return CALL_ORIGINAL(rcx, pState, pInfo, pBoneToWorld);
#endif
/*
if (!F::Chams.iRendering && !F::Glow.m_bRendering && !I::EngineVGui->IsGameUIVisible())
{
if (const auto& pEntity = I::ClientEntityList->GetClientEntity(pInfo.m_nEntIndex))
Utils::ConLog("Entity", std::format("{}, {}, {}", pInfo.m_nEntIndex, int(pEntity->GetClassID()), I::ModelInfoClient->GetModelName(pInfo.m_pModel)).c_str());
else
Utils::ConLog("Model", std::format("{}, {}", pInfo.m_nEntIndex, I::ModelInfoClient->GetModelName(pInfo.m_pModel)).c_str());
}
*/
if (I::EngineVGui->IsGameUIVisible() || Vars::Visuals::UI::CleanScreenshots.Value && I::EngineClient->IsTakingScreenshot()
|| F::CameraWindow.m_bDrawing || !F::Materials.m_bLoaded || G::Unload)
return CALL_ORIGINAL(rcx, pState, pInfo, pBoneToWorld);
@@ -36,7 +26,7 @@ MAKE_HOOK(IVModelRender_DrawModelExecute, U::Memory.GetVirtual(I::ModelRender, 1
if (F::Glow.m_bRendering)
return F::Glow.RenderHandler(pState, pInfo, pBoneToWorld);
if (F::Chams.m_mEntities[pInfo.entity_index])
if (F::Chams.m_mEntities.contains(pInfo.entity_index))
return;
auto pEntity = I::ClientEntityList->GetClientEntity(pInfo.entity_index);
+16
View File
@@ -110,6 +110,22 @@ std::string SDK::GetClipboard()
return sString;
}
std::string SDK::GetDate()
{
time_t tTime = time(nullptr);
tm timeinfo; localtime_s(&timeinfo, &tTime);
char buffer[16]; strftime(buffer, sizeof(buffer), "%b %e %Y", &timeinfo);
return buffer;
}
std::string SDK::GetTime()
{
time_t tTime = time(nullptr);
tm timeinfo; localtime_s(&timeinfo, &tTime);
char buffer[16]; strftime(buffer, sizeof(buffer), "%T", &timeinfo);
return buffer;
}
HWND SDK::GetTeamFortressWindow()
{
static HWND hWindow = nullptr;
+3
View File
@@ -79,6 +79,9 @@ namespace SDK
void SetClipboard(const std::string& sString);
std::string GetClipboard();
std::string GetDate();
std::string GetTime();
HWND GetTeamFortressWindow();
bool IsGameWindowInFocus();
@@ -1,4 +1,4 @@
#include "CrashLog.h"
#include "ErrorLog.h"
#include "../../Features/Configs/Configs.h"
@@ -10,6 +10,8 @@
#include <format>
#pragma comment(lib, "imagehlp.lib")
#define STATUS_RUNTIME_ERROR ((DWORD)0xE06D7363)
struct Frame_t
{
std::string m_sModule = "";
@@ -27,12 +29,14 @@ static int s_iExceptions = 0;
static inline std::deque<Frame_t> StackTrace(PCONTEXT pContext)
{
std::deque<Frame_t> vTrace = {};
HANDLE hProcess = GetCurrentProcess();
HANDLE hThread = GetCurrentThread();
if (!SymInitialize(hProcess, nullptr, TRUE))
return {};
return vTrace;
SymSetOptions(SYMOPT_LOAD_LINES);
STACKFRAME64 tStackFrame = {};
@@ -43,11 +47,12 @@ static inline std::deque<Frame_t> StackTrace(PCONTEXT pContext)
tStackFrame.AddrFrame.Mode = AddrModeFlat;
tStackFrame.AddrStack.Mode = AddrModeFlat;
std::deque<Frame_t> vTrace = {};
while (StackWalk64(IMAGE_FILE_MACHINE_AMD64, hProcess, hThread, &tStackFrame, pContext, nullptr, SymFunctionTableAccess64, SymGetModuleBase64, nullptr))
CONTEXT tContext = *pContext;
while (StackWalk64(IMAGE_FILE_MACHINE_AMD64, hProcess, hThread, &tStackFrame, &tContext, nullptr, SymFunctionTableAccess64, SymGetModuleBase64, nullptr))
{
Frame_t tFrame = {};
tFrame.m_uAddress = tStackFrame.AddrPC.Offset;
vTrace.push_back({ .m_uAddress = tStackFrame.AddrPC.Offset });
Frame_t& tFrame = vTrace.back();
if (auto hBase = HINSTANCE(SymGetModuleBase64(hProcess, tStackFrame.AddrPC.Offset)))
{
@@ -83,8 +88,6 @@ static inline std::deque<Frame_t> StackTrace(PCONTEXT pContext)
if (SymGetSymFromAddr64(hProcess, tStackFrame.AddrPC.Offset, &dwOffset, symbol))
tFrame.m_sName = symbol->Name;
}
vTrace.push_back(tFrame);
}
//if (!vTrace.empty())
// vTrace.pop_front();
@@ -102,6 +105,7 @@ static LONG APIENTRY ExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo)
case STATUS_ACCESS_VIOLATION: sError = "ACCESS VIOLATION"; break;
case STATUS_STACK_OVERFLOW: sError = "STACK OVERFLOW"; break;
case STATUS_HEAP_CORRUPTION: sError = "HEAP CORRUPTION"; break;
case STATUS_RUNTIME_ERROR: sError = "RUNTIME ERROR"; break;
case DBG_PRINTEXCEPTION_C: return EXCEPTION_EXECUTE_HANDLER;
}
@@ -109,14 +113,16 @@ static LONG APIENTRY ExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo)
|| !Vars::Debug::CrashLogging.Value
|| s_iExceptions && GetAsyncKeyState(VK_SHIFT) & 0x8000 && GetAsyncKeyState(VK_RETURN) & 0x8000)
return EXCEPTION_EXECUTE_HANDLER;
s_mAddresses[ExceptionInfo->ExceptionRecord->ExceptionAddress] = true;
s_mAddresses[ExceptionInfo->ExceptionRecord->ExceptionAddress];
std::stringstream ssErrorStream;
ssErrorStream << std::format("Error: {} (0x{:X}) ({})\n", sError, ExceptionInfo->ExceptionRecord->ExceptionCode, ++s_iExceptions);
if (U::Memory.GetOffsetFromBase(s_lpParam))
ssErrorStream << std::format("This: {}\n", U::Memory.GetModuleOffset(s_lpParam));
ssErrorStream << "\n";
ssErrorStream << "Built @ " __DATE__ ", " __TIME__ ", " __CONFIGURATION__ "\n";
ssErrorStream << std::format("Time @ {}, {}\n", SDK::GetDate(), SDK::GetTime());
ssErrorStream << "\n";
ssErrorStream << std::format("RIP: {:#x}\n", ExceptionInfo->ContextRecord->Rip);
ssErrorStream << std::format("RAX: {:#x}\n", ExceptionInfo->ContextRecord->Rax);
ssErrorStream << std::format("RCX: {:#x}\n", ExceptionInfo->ContextRecord->Rcx);
@@ -125,44 +131,43 @@ static LONG APIENTRY ExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo)
ssErrorStream << std::format("RSP: {:#x}\n", ExceptionInfo->ContextRecord->Rsp);
ssErrorStream << std::format("RBP: {:#x}\n", ExceptionInfo->ContextRecord->Rbp);
ssErrorStream << std::format("RSI: {:#x}\n", ExceptionInfo->ContextRecord->Rsi);
ssErrorStream << std::format("RDI: {:#x}\n\n", ExceptionInfo->ContextRecord->Rdi);
ssErrorStream << std::format("RDI: {:#x}\n", ExceptionInfo->ContextRecord->Rdi);
switch (ExceptionInfo->ExceptionRecord->ExceptionCode)
ssErrorStream << "\n";
if (auto vTrace = StackTrace(ExceptionInfo->ContextRecord);
!vTrace.empty())
{
case STATUS_ACCESS_VIOLATION:
//case STATUS_STACK_OVERFLOW:
//case STATUS_HEAP_CORRUPTION:
if (auto vTrace = StackTrace(ExceptionInfo->ContextRecord);
!vTrace.empty())
for (int i = 0; i < vTrace.size(); i++)
{
for (auto& tFrame : vTrace)
{
if (tFrame.m_uBase)
ssErrorStream << std::format("{}+{:#x}", tFrame.m_sModule, tFrame.m_uAddress - tFrame.m_uBase);
else
ssErrorStream << std::format("{:#x}", tFrame.m_uAddress);
if (!tFrame.m_sFile.empty())
ssErrorStream << std::format(" ({} L{})", tFrame.m_sFile, tFrame.m_uLine);
if (!tFrame.m_sName.empty())
ssErrorStream << std::format(" ({})", tFrame.m_sName);
ssErrorStream << "\n";
}
Frame_t& tFrame = vTrace[i];
ssErrorStream << std::format("{}: ", i + 1);
if (tFrame.m_uBase)
ssErrorStream << std::format("{}+{:#x}", tFrame.m_sModule, tFrame.m_uAddress - tFrame.m_uBase);
else
ssErrorStream << std::format("{:#x}", tFrame.m_uAddress);
if (!tFrame.m_sFile.empty())
ssErrorStream << std::format(" ({} L{})", tFrame.m_sFile, tFrame.m_uLine);
if (!tFrame.m_sName.empty())
ssErrorStream << std::format(" ({})", tFrame.m_sName);
ssErrorStream << "\n";
}
break;
default:
}
else
{
ssErrorStream << U::Memory.GetModuleOffset(ExceptionInfo->ExceptionRecord->ExceptionAddress);
ssErrorStream << "\n\n";
ssErrorStream << "\n";
}
ssErrorStream << "Built @ " __DATE__ ", " __TIME__ ", " __CONFIGURATION__ "\n";
ssErrorStream << "Ctrl + C to copy. \n";
try
{
std::ofstream file;
file.open(F::Configs.m_sConfigPath + "crash_log.txt", std::ios_base::app);
file << ssErrorStream.str() + "\n\n\n";
file.close();
ssErrorStream << "\n";
ssErrorStream << "Ctrl + C to copy. \n";
ssErrorStream << "Logged to Amalgam\\crash_log.txt. ";
}
catch (...) {}
@@ -170,20 +175,20 @@ static LONG APIENTRY ExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo)
switch (ExceptionInfo->ExceptionRecord->ExceptionCode)
{
case STATUS_ACCESS_VIOLATION:
//case STATUS_STACK_OVERFLOW:
//case STATUS_HEAP_CORRUPTION:
case STATUS_STACK_OVERFLOW:
case STATUS_HEAP_CORRUPTION:
SDK::Output("Unhandled exception", ssErrorStream.str().c_str(), {}, OUTPUT_DEBUG, MB_OK | MB_ICONERROR);
}
return EXCEPTION_EXECUTE_HANDLER;
}
void CCrashLog::Initialize(LPVOID lpParam)
void CErrorLog::Initialize(LPVOID lpParam)
{
s_pHandle = AddVectoredExceptionHandler(1, ExceptionFilter);
s_lpParam = lpParam;
}
void CCrashLog::Unload()
void CErrorLog::Unload()
{
RemoveVectoredExceptionHandler(s_pHandle);
}
@@ -2,11 +2,11 @@
#include "../Macros/Macros.h"
#include <Windows.h>
class CCrashLog
class CErrorLog
{
public:
void Initialize(LPVOID lpParam = nullptr);
void Unload();
};
ADD_FEATURE_CUSTOM(CCrashLog, CrashLog, U);
ADD_FEATURE_CUSTOM(CErrorLog, ErrorLog, U);