From ccc64987390b240d5b1db7aef9975ce3170da04f Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 6 Nov 2019 17:44:32 +1100 Subject: [PATCH 1/4] fix(windows): Keyman was crashing sporadically Fixes #2147. This potentially addresses the issues reported in #2147 where Keyman would crash due to a race condition as a critical section was not deleted before attempting to recreate it. Some logging has been added for debugging these issues. Also fixes memory leaks and another race on startup relating to loading the taskbar icon. There are still some known memory leaks because DLL_THREAD_DETACH is not called for all threads before keyman32.dll is unloaded, so those threads don't get the opportunity to clean themsselves up. However, the key danger with the csGlobals critical section has been addressed. --- windows/src/engine/keyman/UfrmKeyman7Main.pas | 4 + windows/src/engine/keyman/keyman.dpr | 7 +- windows/src/engine/keyman32/K32_DBG.CPP | 10 ++- windows/src/engine/keyman32/Keyman32.cpp | 30 +++++-- windows/src/engine/keyman32/hookutils.cpp | 82 ++++++++++--------- windows/src/engine/keyman32/hotkeys.cpp | 12 +++ windows/src/engine/keyman32/hotkeys.h | 3 +- windows/src/engine/keyman32/k32_globals.cpp | 7 +- .../keyman32/k32_lowlevelkeyboardhook.cpp | 2 +- .../src/engine/keyman32/keyboardoptions.cpp | 7 +- .../engine/keyman32/kmhook_callwndproc.cpp | 3 +- .../engine/keyman32/serialkeyeventclient.cpp | 2 + windows/src/global/delphi/general/klog.pas | 2 +- windows/src/global/inc/keyman64.h | 7 ++ 14 files changed, 121 insertions(+), 57 deletions(-) diff --git a/windows/src/engine/keyman/UfrmKeyman7Main.pas b/windows/src/engine/keyman/UfrmKeyman7Main.pas index 8c198f699f..c37b73fb95 100644 --- a/windows/src/engine/keyman/UfrmKeyman7Main.pas +++ b/windows/src/engine/keyman/UfrmKeyman7Main.pas @@ -442,6 +442,10 @@ begin begin olestrm := TOLEStream.Create(istrm); try + // In some situations, launching the app multiple times rapidly can + // cause the icon to be loaded multiple times. Make sure we reset the + // stream position before we try and read. + olestrm.Position := 0; Application.Icon.LoadFromStream(olestrm); finally olestrm.Free; diff --git a/windows/src/engine/keyman/keyman.dpr b/windows/src/engine/keyman/keyman.dpr index b2352c3a7e..2f9bed1197 100644 --- a/windows/src/engine/keyman/keyman.dpr +++ b/windows/src/engine/keyman/keyman.dpr @@ -1,7 +1,5 @@ program keyman; - - uses Forms, Dialogs, @@ -148,6 +146,11 @@ uses {$R VERSION.RES} {$R MANIFEST.RES} +// +// PEOPTFLAGS $140 turns on Data Execution Prevention +// +{$SETPEOPTFLAGS $140} + begin //InitTntEnvironment; //ShowMessage('Start'); diff --git a/windows/src/engine/keyman32/K32_DBG.CPP b/windows/src/engine/keyman32/K32_DBG.CPP index 7fcc025762..a6e28b0873 100644 --- a/windows/src/engine/keyman32/K32_DBG.CPP +++ b/windows/src/engine/keyman32/K32_DBG.CPP @@ -304,4 +304,12 @@ char *Debug_UnicodeString(PWSTR s, int x) { } //WideCharToMultiByte(CP_ACP, 0, buf, -1, bufout, 128, NULL, NULL); return bufout[x]; -} \ No newline at end of file +} + +#ifdef _DEBUG +void _OutputThreadDebugString(char *s) { + char buf[256]; + wsprintf(buf, "[%d]: %s\n", GetCurrentThreadId(), s); + OutputDebugString(buf); +} +#endif diff --git a/windows/src/engine/keyman32/Keyman32.cpp b/windows/src/engine/keyman32/Keyman32.cpp index 9f4948f35b..58245b1c97 100644 --- a/windows/src/engine/keyman32/Keyman32.cpp +++ b/windows/src/engine/keyman32/Keyman32.cpp @@ -157,11 +157,13 @@ BOOL __stdcall DllMain(HINSTANCE hinstDll, DWORD fdwReason, LPVOID reserved) case DLL_PROCESS_ATTACH: //if(!TestDebugProcess()) return FALSE; //if(!ShouldAttachToProcess()) return FALSE; + OutputThreadDebugString("DLL_PROCESS_ATTACH"); if(!Globals_InitProcess()) return FALSE; break; case DLL_PROCESS_DETACH: //if(!TestDebugProcess()) return FALSE; if (reserved == NULL) { + OutputThreadDebugString("DLL_PROCESS_DETACH not terminating"); // If reserved == NULL, that means the library is being unloaded, but // the process is not terminating. // @@ -180,15 +182,20 @@ BOOL __stdcall DllMain(HINSTANCE hinstDll, DWORD fdwReason, LPVOID reserved) // CloseTSF from here. This needs further investigation... UninitialiseProcess(FALSE); Globals_UninitProcess(); + } + else { + OutputThreadDebugString("DLL_PROCESS_DETACH terminating"); } break; case DLL_THREAD_ATTACH: //if(!TestDebugProcess()) return FALSE; + OutputThreadDebugString("DLL_THREAD_ATTACH"); Globals_InitThread(); break; case DLL_THREAD_DETACH: //if(!TestDebugProcess()) return FALSE; - UninitialiseProcess(FALSE); + OutputThreadDebugString("DLL_THREAD_DETACH"); + UninitialiseProcess(FALSE); Globals_UninitThread(); break; } @@ -214,8 +221,13 @@ BOOL UninitialiseProcess(BOOL Lock) if(_td->IndexStack) delete _td->IndexStack; _td->IndexStack = NULL; - } + if (_td->miniContext) delete _td->miniContext; + _td->miniContext = NULL; + + if (_td->msgbuf) delete _td->msgbuf; + _td->msgbuf = NULL; + } return TRUE; } @@ -512,6 +524,10 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_Exit(void) return FALSE; } +#ifndef WIN64 + Hotkeys::Unload(); +#endif + *Globals::InitialisingThread() = 0; BOOL RetVal = TRUE; @@ -801,6 +817,7 @@ void LoadBaseLayoutSettings() { // I4552 // I4583 void RefreshKeyboards(BOOL Initialising) { + OutputThreadDebugString("RefreshKeyboards"); char sz[_MAX_FNAME]; char oldname[_MAX_FNAME]; RegistryReadOnly *reg2; @@ -828,7 +845,7 @@ void RefreshKeyboards(BOOL Initialising) _td->ActiveKeymanID = KEYMANID_NONKEYMAN; } - ReleaseKeyboards(TRUE); + ReleaseKeyboards(TRUE); /* Read the "keyboard off hotkey", simulate Alt+Gr, Hotkeys-Toggle flags */ @@ -938,13 +955,14 @@ void RefreshKeyboards(BOOL Initialising) _td->FInRefreshKeyboards = FALSE; } - void ReleaseKeyboards(BOOL Lock) { + OutputThreadDebugString("ReleaseKeyboards"); PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td || _td->lpKeyboards) return; + if(!_td || !_td->lpKeyboards) return; - if(Lock) if(_td->lpActiveKeyboard && !_td->ForceFileName[0]) DeactivateDLLs(_td->lpActiveKeyboard); + + if(Lock) if(_td->lpActiveKeyboard && !_td->ForceFileName[0]) DeactivateDLLs(_td->lpActiveKeyboard); for(int i = 0; i < _td->nKeyboards; i++) { diff --git a/windows/src/engine/keyman32/hookutils.cpp b/windows/src/engine/keyman32/hookutils.cpp index 15c24283b9..008bda99d1 100644 --- a/windows/src/engine/keyman32/hookutils.cpp +++ b/windows/src/engine/keyman32/hookutils.cpp @@ -15,45 +15,44 @@ typedef BOOL IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL ); - -DWORD ExceptionMessage(LPSTR Proc, LPEXCEPTION_POINTERS ep) -{ +DWORD ExceptionMessage(LPSTR Proc, LPEXCEPTION_POINTERS ep) { MINIDUMP_EXCEPTION_INFORMATION mei; char filename[MAX_PATH], temppath[MAX_PATH]; - if(GetTempPath(MAX_PATH, temppath) == 0 || - GetTempFileName(temppath, "kmc", 0, filename) == 0) - SendDebugMessageFormat(0, sdmGlobal, 0, "Minidump failed to generate temp file name"); - else - { + if (GetTempPath(MAX_PATH, temppath) == 0 || + GetTempFileName(temppath, "kmc", 0, filename) == 0) { + OutputThreadDebugString("Minidump failed to generate temp file name\n"); + } + else { HANDLE hFile = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); - if(!hFile) - SendDebugMessageFormat(0, sdmGlobal, 0, "Minidump failed to create file %s", filename); - else - { + if (!hFile) { + OutputThreadDebugString("Minidump failed to create file "); + OutputThreadDebugString(filename); + } + else { mei.ClientPointers = TRUE; mei.ExceptionPointers = ep; mei.ThreadId = GetCurrentThreadId(); HMODULE hDbgHelp = LoadLibrary("dbghelp.dll"); - if(!hDbgHelp) - SendDebugMessage(0, sdmGlobal, 0, "dbghelp.dll not available"); - else - { + if (!hDbgHelp) { + OutputThreadDebugString("dbghelp.dll not available"); + } + else { PMiniDumpWriteDump mdwd = (PMiniDumpWriteDump) GetProcAddress(hDbgHelp, "MiniDumpWriteDump"); - if(!mdwd) - SendDebugMessage(0, sdmGlobal, 0, "MiniDumpWriteDump not available"); - else - { + if (!mdwd) { + OutputThreadDebugString("MiniDumpWriteDump not available"); + } + else { if (!(*mdwd)(GetCurrentProcess(), GetCurrentProcessId(), hFile, - (MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithHandleData), - &mei, NULL, NULL)) + (MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithHandleData), + &mei, NULL, NULL)) { DebugLastError("MiniDumpWriteDump"); - else - { - SendDebugMessageFormat(0, sdmGlobal, 0, "Minidump written to %s", filename); + } + else { + OutputThreadDebugString("Minidump written to "); + OutputThreadDebugString(filename); HKEY hkey; if(RegCreateKeyEx(HKEY_CURRENT_USER, REGSZ_KeymanEngineDiag, 0, NULL, 0, KEY_ALL_ACCESS, - NULL, &hkey, NULL) == ERROR_SUCCESS) - { + NULL, &hkey, NULL) == ERROR_SUCCESS) { DWORD v = 0; RegSetValueEx(hkey, filename, 0, REG_DWORD, (PBYTE)&v, sizeof(DWORD)); RegCloseKey(hkey); @@ -66,23 +65,26 @@ DWORD ExceptionMessage(LPSTR Proc, LPEXCEPTION_POINTERS ep) } } - if(!ep || !ep->ExceptionRecord) - { - SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT UNKNOWN EXCEPTION"); + if(!ep || !ep->ExceptionRecord) { + OutputThreadDebugString("CAUGHT UNKNOWN EXCEPTION"); return EXCEPTION_CONTINUE_SEARCH; } LPEXCEPTION_RECORD er = ep->ExceptionRecord; - while(er != NULL) - { - if(er->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) - SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT EXCEPTION %d (ACCESS VIOLATION) IN %s AT %x; attempted to %s %x", - er->ExceptionCode, Proc, er->ExceptionAddress, - er->ExceptionInformation[0] == 0 ? "read from" : "write to", - er->ExceptionInformation[1]); - else - SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT EXCEPTION %d IN %s AT %x", - er->ExceptionCode, Proc, er->ExceptionAddress); + while(er != NULL) { + if (er->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { + OutputThreadDebugString("EXCEPTION_ACCESS_VIOLATION in "); + OutputThreadDebugString(Proc); + SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT EXCEPTION %d (ACCESS VIOLATION) IN %s AT %x; attempted to %s %x", + er->ExceptionCode, Proc, er->ExceptionAddress, + er->ExceptionInformation[0] == 0 ? "read from" : "write to", + er->ExceptionInformation[1]); + } + else { + OutputThreadDebugString("CAUGHT EXCEPTION"); + SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT EXCEPTION %d IN %s AT %x", + er->ExceptionCode, Proc, er->ExceptionAddress); + } er = er->ExceptionRecord; } diff --git a/windows/src/engine/keyman32/hotkeys.cpp b/windows/src/engine/keyman32/hotkeys.cpp index a3363c49cc..cead296f8d 100644 --- a/windows/src/engine/keyman32/hotkeys.cpp +++ b/windows/src/engine/keyman32/hotkeys.cpp @@ -45,6 +45,18 @@ Hotkeys *Hotkeys::Instance() { // I4326 return g_Hotkeys; } +void Hotkeys::Unload() { + if (GetCurrentThreadId() != Globals::get_InitialisingThread()) { + OutputThreadDebugString("Unexpected: no other thread should be attempting to unload hotkeys"); + return; + } + + if (g_Hotkeys != NULL) { + delete g_Hotkeys; + g_Hotkeys = NULL; + } +} + void Hotkeys::Reload() { // I4326 // I4390 Hotkeys *hotkeys = Hotkeys::Instance(); // I4641 if(hotkeys == NULL) { diff --git a/windows/src/engine/keyman32/hotkeys.h b/windows/src/engine/keyman32/hotkeys.h index b011d20547..863be3636c 100644 --- a/windows/src/engine/keyman32/hotkeys.h +++ b/windows/src/engine/keyman32/hotkeys.h @@ -43,4 +43,5 @@ public: Hotkey *GetHotkey(DWORD hotkey); static void Reload(); // I4326 static Hotkeys *Instance(); // I4326 -}; + static void Unload(); + }; diff --git a/windows/src/engine/keyman32/k32_globals.cpp b/windows/src/engine/keyman32/k32_globals.cpp index af59056a15..2a08e6c293 100644 --- a/windows/src/engine/keyman32/k32_globals.cpp +++ b/windows/src/engine/keyman32/k32_globals.cpp @@ -138,7 +138,11 @@ PKEYMAN64THREADDATA Globals_InitThread() void Globals_UninitThread() { - if(!Globals_ProcessInitialised()) return; + OutputThreadDebugString("Globals_UninitThread"); + if (!Globals_ProcessInitialised()) { + OutputThreadDebugString("Globals_UninitThread aborted without cleanup"); + return; + } CloseTSF(); // I3933 @@ -185,6 +189,7 @@ void Globals_UninitProcess() TlsFree(dwTlsIndex); dwTlsIndex = TLS_OUT_OF_INDEXES; LeaveCriticalSection(&csGlobals); + DeleteCriticalSection(&csGlobals); } PKEYMAN64THREADDATA ThreadGlobals() diff --git a/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp b/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp index b50e0486e4..fee747f486 100644 --- a/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp +++ b/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp @@ -53,7 +53,7 @@ LRESULT CALLBACK kmnLowLevelKeyboardProc( __except(ExceptionMessage("kmnLowLevelKeyboardProc", GetExceptionInformation())) { } #endif - return res; + return res; } BOOL KeyLanguageSwitchPress(WPARAM wParam, BOOL extended, BOOL isUp, DWORD ShiftState); diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index 2e907c6460..1e0e0a8511 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -41,9 +41,10 @@ void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp) void FreeKeyboardOptions(LPINTKEYBOARDINFO kp) { - assert(kp != NULL); - assert(kp->Keyboard != NULL); - assert(kp->KeyboardOptions != NULL); + // This is a cleanup routine; we don't want to precondition all calls to it + // so we do not assert + if (kp == NULL || kp->Keyboard == NULL || kp->KeyboardOptions == NULL) + return; for(DWORD i = 0; i < kp->Keyboard->cxStoreArray; i++) if(kp->KeyboardOptions[i].Value) diff --git a/windows/src/engine/keyman32/kmhook_callwndproc.cpp b/windows/src/engine/keyman32/kmhook_callwndproc.cpp index 4b72ab7bd6..7178ed5fea 100644 --- a/windows/src/engine/keyman32/kmhook_callwndproc.cpp +++ b/windows/src/engine/keyman32/kmhook_callwndproc.cpp @@ -66,6 +66,7 @@ LRESULT _kmnCallWndProc(int nCode, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK kmnCallWndProc(int nCode, WPARAM wParam, LPARAM lParam) { LRESULT res = 0; + #ifdef _DEBUG_EXCEPTION res = _kmnCallWndProc(nCode,wParam,lParam); #else @@ -77,7 +78,7 @@ LRESULT CALLBACK kmnCallWndProc(int nCode, WPARAM wParam, LPARAM lParam) { } #endif - return res; + return res; } // I3617 BOOL IsSysTrayWindow(HWND hwnd); diff --git a/windows/src/engine/keyman32/serialkeyeventclient.cpp b/windows/src/engine/keyman32/serialkeyeventclient.cpp index 3719b9409a..722903e6c3 100644 --- a/windows/src/engine/keyman32/serialkeyeventclient.cpp +++ b/windows/src/engine/keyman32/serialkeyeventclient.cpp @@ -149,6 +149,7 @@ public: }; void ISerialKeyEventClient::Startup() { + OutputThreadDebugString("ISerialKeyEventClient::Startup"); PKEYMAN64THREADDATA _td = ThreadGlobals(); if (_td) { _td->pSerialKeyEventClient = new SerialKeyEventClient(); @@ -156,6 +157,7 @@ void ISerialKeyEventClient::Startup() { } void ISerialKeyEventClient::Shutdown() { + OutputThreadDebugString("ISerialKeyEventClient::Shutdown"); PKEYMAN64THREADDATA _td = ThreadGlobals(); if (_td && _td->pSerialKeyEventClient) { delete _td->pSerialKeyEventClient; diff --git a/windows/src/global/delphi/general/klog.pas b/windows/src/global/delphi/general/klog.pas index 8f8198bf31..0915696743 100644 --- a/windows/src/global/delphi/general/klog.pas +++ b/windows/src/global/delphi/general/klog.pas @@ -133,7 +133,7 @@ begin end; writeln(FLogFile, Format('%12.12d ', [GetTickCount()])+FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', Now) + ': ' + StringOfChar(' ', FMethodStack.Count*2) + msg); flush(FLogFile); - OutputDebugString(PChar(msg)); + OutputDebugString(PChar('KLog:' + msg + #13#10)); {$ENDIF} end; diff --git a/windows/src/global/inc/keyman64.h b/windows/src/global/inc/keyman64.h index ca8961501e..65e17b6db9 100644 --- a/windows/src/global/inc/keyman64.h +++ b/windows/src/global/inc/keyman64.h @@ -347,6 +347,13 @@ BOOL ShouldDebug_1(); // TSDMState state); #endif +#ifdef _DEBUG +#define OutputThreadDebugString(s) _OutputThreadDebugString(s) +void _OutputThreadDebugString(char *s); +#else +#define OutputThreadDebugString(s) +#endif + /* Keyboard selection functions */ void HandleRefresh(int code, LONG tag); From fc330e621ab2f04faf201cbd505517b243c32fda Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 7 Nov 2019 17:24:56 +1100 Subject: [PATCH 2/4] fix(windows): tweak preprocessor conditional --- windows/src/engine/keyman32/Keyman32.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/src/engine/keyman32/Keyman32.cpp b/windows/src/engine/keyman32/Keyman32.cpp index 58245b1c97..f146f3eae0 100644 --- a/windows/src/engine/keyman32/Keyman32.cpp +++ b/windows/src/engine/keyman32/Keyman32.cpp @@ -524,7 +524,7 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_Exit(void) return FALSE; } -#ifndef WIN64 +#ifndef _WIN64 Hotkeys::Unload(); #endif From be1b8f6457e46b218e1384aa490b02870db5fdc9 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 7 Nov 2019 17:31:03 +1100 Subject: [PATCH 3/4] chore(developer): tidy up from review comments --- windows/src/engine/keyman32/hookutils.cpp | 8 ++++---- windows/src/engine/keyman32/{K32_DBG.CPP => k32_dbg.cpp} | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) rename windows/src/engine/keyman32/{K32_DBG.CPP => k32_dbg.cpp} (99%) diff --git a/windows/src/engine/keyman32/hookutils.cpp b/windows/src/engine/keyman32/hookutils.cpp index 008bda99d1..da03f4ac5e 100644 --- a/windows/src/engine/keyman32/hookutils.cpp +++ b/windows/src/engine/keyman32/hookutils.cpp @@ -75,15 +75,15 @@ DWORD ExceptionMessage(LPSTR Proc, LPEXCEPTION_POINTERS ep) { if (er->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { OutputThreadDebugString("EXCEPTION_ACCESS_VIOLATION in "); OutputThreadDebugString(Proc); - SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT EXCEPTION %d (ACCESS VIOLATION) IN %s AT %x; attempted to %s %x", + /*SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT EXCEPTION %d (ACCESS VIOLATION) IN %s AT %x; attempted to %s %x", er->ExceptionCode, Proc, er->ExceptionAddress, er->ExceptionInformation[0] == 0 ? "read from" : "write to", - er->ExceptionInformation[1]); + er->ExceptionInformation[1]);*/ } else { OutputThreadDebugString("CAUGHT EXCEPTION"); - SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT EXCEPTION %d IN %s AT %x", - er->ExceptionCode, Proc, er->ExceptionAddress); + /*SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT EXCEPTION %d IN %s AT %x", + er->ExceptionCode, Proc, er->ExceptionAddress);*/ } er = er->ExceptionRecord; } diff --git a/windows/src/engine/keyman32/K32_DBG.CPP b/windows/src/engine/keyman32/k32_dbg.cpp similarity index 99% rename from windows/src/engine/keyman32/K32_DBG.CPP rename to windows/src/engine/keyman32/k32_dbg.cpp index a6e28b0873..f78eb737fa 100644 --- a/windows/src/engine/keyman32/K32_DBG.CPP +++ b/windows/src/engine/keyman32/k32_dbg.cpp @@ -309,7 +309,7 @@ char *Debug_UnicodeString(PWSTR s, int x) { #ifdef _DEBUG void _OutputThreadDebugString(char *s) { char buf[256]; - wsprintf(buf, "[%d]: %s\n", GetCurrentThreadId(), s); + sprintf_s(buf, "[%d]: %s\n", GetCurrentThreadId(), s); OutputDebugString(buf); } #endif From b7d4e83270de4dc2e2a8c1df29b63e9cdfe7f074 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Fri, 8 Nov 2019 09:40:40 +1100 Subject: [PATCH 4/4] chore(windows): unreferenced param in release build --- windows/src/engine/keyman32/hookutils.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/windows/src/engine/keyman32/hookutils.cpp b/windows/src/engine/keyman32/hookutils.cpp index da03f4ac5e..6ccccae719 100644 --- a/windows/src/engine/keyman32/hookutils.cpp +++ b/windows/src/engine/keyman32/hookutils.cpp @@ -16,6 +16,10 @@ typedef BOOL ); DWORD ExceptionMessage(LPSTR Proc, LPEXCEPTION_POINTERS ep) { +#ifndef _DEBUG + UNREFERENCED_PARAMETER(Proc); +#endif + MINIDUMP_EXCEPTION_INFORMATION mei; char filename[MAX_PATH], temppath[MAX_PATH]; if (GetTempPath(MAX_PATH, temppath) == 0 ||