-
-
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); | |
} |
@mkacct Can you post a crash dump? You should be able to get it with the following steps:
- Open regedit
- Go to:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting
- Create a key named
LocalDumps
- Create a DWORD value named
DumpType
with value 2 - Trigger the crash
- Go to the
%LocalAppData%\CrashDumps
folder, you should see a dump file in there
@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
On my machine this seems to render Windows Subsystem for Linux unusable (crashes on startup) for some reason...