-
-
Save m417z/f0cdf071868a6f31210e84dd0d444055 to your computer and use it in GitHub Desktop.
| // ==WindhawkMod== | |
| // @id process-shutdown-message-box-fix | |
| // @name Process shutdown message box fix | |
| // @description Fixes message box and beep sound on process shutdown, e.g. when launching folders via an explorer shortcut | |
| // @version 0.3 | |
| // @author m417z | |
| // @github https://github.com/m417z | |
| // @twitter https://twitter.com/m417z | |
| // @homepage https://m417z.com/ | |
| // @include * | |
| // ==/WindhawkMod== | |
| #include <stdlib.h> | |
| // Just to make the mod depend on libc++. | |
| #include <vector> | |
| std::vector<int> g_v; | |
| using _errno_t = decltype(&_errno); | |
| HMODULE g_libCpp; | |
| void** g_ppSetlocale; | |
| HMODULE g_msvcrtModule; | |
| _errno_t g_msvcrtErrno; | |
| void** FindImportPtr(HMODULE hFindInModule, | |
| PCSTR pModuleName, | |
| PCSTR pImportName) { | |
| IMAGE_DOS_HEADER* pDosHeader; | |
| IMAGE_NT_HEADERS* pNtHeader; | |
| ULONG_PTR ImageBase; | |
| IMAGE_IMPORT_DESCRIPTOR* pImportDescriptor; | |
| ULONG_PTR* pOriginalFirstThunk; | |
| ULONG_PTR* pFirstThunk; | |
| ULONG_PTR ImageImportByName; | |
| // Init | |
| pDosHeader = (IMAGE_DOS_HEADER*)hFindInModule; | |
| pNtHeader = (IMAGE_NT_HEADERS*)((char*)pDosHeader + pDosHeader->e_lfanew); | |
| if (!pNtHeader->OptionalHeader.DataDirectory[1].VirtualAddress) | |
| return nullptr; | |
| ImageBase = (ULONG_PTR)hFindInModule; | |
| pImportDescriptor = | |
| (IMAGE_IMPORT_DESCRIPTOR*)(ImageBase + | |
| pNtHeader->OptionalHeader.DataDirectory[1] | |
| .VirtualAddress); | |
| // Search! | |
| while (pImportDescriptor->OriginalFirstThunk) { | |
| if (lstrcmpiA((char*)(ImageBase + pImportDescriptor->Name), | |
| pModuleName) == 0) { | |
| pOriginalFirstThunk = | |
| (ULONG_PTR*)(ImageBase + pImportDescriptor->OriginalFirstThunk); | |
| ImageImportByName = *pOriginalFirstThunk; | |
| pFirstThunk = | |
| (ULONG_PTR*)(ImageBase + pImportDescriptor->FirstThunk); | |
| while (ImageImportByName) { | |
| if (!(ImageImportByName & IMAGE_ORDINAL_FLAG)) { | |
| if ((ULONG_PTR)pImportName & ~0xFFFF) { | |
| ImageImportByName += sizeof(WORD); | |
| if (lstrcmpA((char*)(ImageBase + ImageImportByName), | |
| pImportName) == 0) | |
| return (void**)pFirstThunk; | |
| } | |
| } else { | |
| if (((ULONG_PTR)pImportName & ~0xFFFF) == 0) | |
| if ((ImageImportByName & 0xFFFF) == | |
| (ULONG_PTR)pImportName) | |
| return (void**)pFirstThunk; | |
| } | |
| pOriginalFirstThunk++; | |
| ImageImportByName = *pOriginalFirstThunk; | |
| pFirstThunk++; | |
| } | |
| } | |
| pImportDescriptor++; | |
| } | |
| return nullptr; | |
| } | |
| using SetLocale_t = char*(__cdecl*)(int category, const char* locale); | |
| SetLocale_t SetLocale_Original; | |
| char* __cdecl SetLocale_Wrapper(int category, const char* locale) { | |
| // A workaround for https://github.com/mstorsjo/llvm-mingw/issues/459. | |
| errno_t* err = g_msvcrtErrno(); | |
| HMODULE module; | |
| if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | | |
| GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, | |
| (PCWSTR)err, &module) && | |
| module == g_msvcrtModule) { | |
| // Getting a process-wide errno from the module section instead of the | |
| // thread errno from the heap means we have no PTD (Per-thread data) and | |
| // setlocale will fail, likely with a message box and abort. Return NULL | |
| // instead to let the caller handle it gracefully. | |
| Wh_Log(L"Returning NULL for setlocale"); | |
| return nullptr; | |
| } | |
| return SetLocale_Original(category, locale); | |
| } | |
| bool InitGlobals() { | |
| if (!GetModuleHandleEx(0, L"libc++.dll", &g_libCpp)) { | |
| Wh_Log(L"No libc++.dll"); | |
| return false; | |
| } | |
| g_ppSetlocale = FindImportPtr(g_libCpp, "msvcrt.dll", "setlocale"); | |
| if (!g_ppSetlocale) { | |
| Wh_Log(L"No setlocale"); | |
| return false; | |
| } | |
| if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, | |
| (PCWSTR)*g_ppSetlocale, &g_msvcrtModule)) { | |
| Wh_Log(L"No setlocale module"); | |
| return false; | |
| } | |
| if (g_msvcrtModule != GetModuleHandle(L"msvcrt.dll")) { | |
| Wh_Log(L"Bad setlocale module, already patched?"); | |
| Wh_Log(L"%p %p", g_msvcrtModule, GetModuleHandle(L"msvcrt.dll")); | |
| return false; | |
| } | |
| g_msvcrtErrno = (_errno_t)GetProcAddress(g_msvcrtModule, "_errno"); | |
| if (!g_msvcrtErrno) { | |
| Wh_Log(L"No _errno"); | |
| return false; | |
| } | |
| return true; | |
| } | |
| BOOL Wh_ModInit() { | |
| Wh_Log(L">"); | |
| if (!InitGlobals()) { | |
| if (g_msvcrtModule) { | |
| FreeLibrary(g_msvcrtModule); | |
| } | |
| if (g_libCpp) { | |
| FreeLibrary(g_libCpp); | |
| } | |
| return FALSE; | |
| } | |
| DWORD dwOldProtect; | |
| VirtualProtect(g_ppSetlocale, sizeof(*g_ppSetlocale), | |
| PAGE_EXECUTE_READWRITE, &dwOldProtect); | |
| SetLocale_Original = (SetLocale_t)*g_ppSetlocale; | |
| *g_ppSetlocale = (void*)SetLocale_Wrapper; | |
| VirtualProtect(g_ppSetlocale, sizeof(*g_ppSetlocale), dwOldProtect, | |
| &dwOldProtect); | |
| return TRUE; | |
| } | |
| void Wh_ModUninit() { | |
| Wh_Log(L">"); | |
| DWORD dwOldProtect; | |
| VirtualProtect(g_ppSetlocale, sizeof(*g_ppSetlocale), | |
| PAGE_EXECUTE_READWRITE, &dwOldProtect); | |
| *g_ppSetlocale = (void*)SetLocale_Original; | |
| VirtualProtect(g_ppSetlocale, sizeof(*g_ppSetlocale), dwOldProtect, | |
| &dwOldProtect); | |
| FreeLibrary(g_msvcrtModule); | |
| FreeLibrary(g_libCpp); | |
| } |
@m417z I don't seem to be able to do that (I guess it is not technically a crash in that sense), but I can provide more details regarding what happens.
When I try to start a WSL session, Windhawk shows this:

And then WSL prints this and exits:
The remote procedure call failed.
Error code: Wsl/Service/RPC_S_CALL_FAILED
@mkacct It seems to happen because the process exits really quickly after launching. This mod tries to implement a workaround, but it's not perfect. Rather than improving it, I'd rather invest my time in a new Windhawk version with a proper fix.
For now, I suggest to exclude wslservice.exe in Windhawk, I assume you don't have relevant mods for it. For excluding a process in Windhawk, check out the short video here.
Thanks for the feedback, and let me know if you need help with one of the steps.
@m417z Okay thank you
@mkacct Can you post a crash dump? You should be able to get it with the following steps:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error ReportingLocalDumpsDumpTypewith value 2%LocalAppData%\CrashDumpsfolder, you should see a dump file in there