Skip to content

Instantly share code, notes, and snippets.

@m417z
Last active March 20, 2025 10:37
Show Gist options
  • Save m417z/69815de59bc1c2b724bde88054884f3c to your computer and use it in GitHub Desktop.
Save m417z/69815de59bc1c2b724bde88054884f3c to your computer and use it in GitHub Desktop.
Prevents some UWP popups from closing due to UWPSpy stealing focus. See https://github.com/m417z/UWPSpy/issues/8.
// ==WindhawkMod==
// @id prevent-uwpspy-focus-steal
// @name Prevent UWPSpy Focus Steal
// @description Prevents some UWP popups from closing due to UWPSpy stealing focus
// @version 0.1
// @author m417z
// @github https://github.com/m417z
// @twitter https://x.com/m417z
// @homepage https://m417z.com/
// @compilerOptions -lcomctl32
// @include *
// ==/WindhawkMod==
// ==WindhawkModReadme==
/*
# Prevent UWPSpy Focus Steal
Prevents some UWP popups from closing due to UWPSpy stealing focus. See [UWPSpy
Feature Request: Ability to "pause" or
"save"](https://github.com/m417z/UWPSpy/issues/8).
*/
// ==/WindhawkModReadme==
#include <windhawk_utils.h>
// Suppress the messages we want to ignore
// and prevent them from reaching the main windowProc
LRESULT CALLBACK TargetWindowSubclassProc(HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam,
DWORD_PTR dwRefData) {
switch (uMsg) {
case WM_NCACTIVATE: // Non-client area activation (e.g. titlebar)
if (!wParam) {
return FALSE;
}
break;
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
bool IsTargetWindow(HWND hwnd) {
WCHAR className[64];
if (!GetClassName(hwnd, className, ARRAYSIZE(className))) {
return false;
}
return _wcsicmp(className, L"UWPSpy") == 0;
// return _wcsicmp(className, L"XamlExplorerHostIslandWindow_WASDK") == 0;
}
// ------------------ Dealing with newly created windows ------------------
// Hooks for creating and destroying new windows to ensure that
// new windows created after the mod is initially enabled get subclassed
using PUNICODE_STRING = PVOID;
// https://github.com/sandboxie-plus/Sandboxie/blob/294966c7d6e99cd153ede87ad09aa39ef29e34c3/Sandboxie/core/dll/Win32.c#L25
using NtUserCreateWindowEx_t = HWND(WINAPI*)(DWORD dwExStyle,
PUNICODE_STRING UnsafeClassName,
LPCWSTR VersionedClass,
PUNICODE_STRING UnsafeWindowName,
DWORD dwStyle,
LONG x,
LONG y,
LONG nWidth,
LONG nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam,
DWORD dwShowMode,
DWORD dwUnknown1,
DWORD dwUnknown2,
VOID* qwUnknown3);
NtUserCreateWindowEx_t NtUserCreateWindowEx_Original;
HWND WINAPI NtUserCreateWindowEx_Hook(DWORD dwExStyle,
PUNICODE_STRING UnsafeClassName,
LPCWSTR VersionedClass,
PUNICODE_STRING UnsafeWindowName,
DWORD dwStyle,
LONG x,
LONG y,
LONG nWidth,
LONG nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam,
DWORD dwShowMode,
DWORD dwUnknown1,
DWORD dwUnknown2,
VOID* qwUnknown3) {
HWND hWnd = NtUserCreateWindowEx_Original(
dwExStyle, UnsafeClassName, VersionedClass, UnsafeWindowName, dwStyle,
x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam,
dwShowMode, dwUnknown1, dwUnknown2, qwUnknown3);
if (!hWnd || !IsTargetWindow(hWnd))
return hWnd;
WindhawkUtils::SetWindowSubclassFromAnyThread(hWnd,
TargetWindowSubclassProc, 0);
Wh_Log(L"New window subclassed: %08X", (DWORD)(UINT_PTR)hWnd);
return hWnd;
}
// ------------------ Dealing with existing windows ------------------
// We subclass all existing windows when the mod is enabled
// while the program is already running
BOOL CALLBACK InitialEnumTargetWindowsFunc(HWND hWnd, LPARAM lParam) {
DWORD dwProcessId = 0;
DWORD dwThreadId = GetWindowThreadProcessId(hWnd, &dwProcessId);
if (!dwThreadId || dwProcessId != GetCurrentProcessId()) {
return TRUE;
}
if (IsTargetWindow(hWnd)) {
Wh_Log(L"Existing window subclassed: %08X", (DWORD)(UINT_PTR)hWnd);
WindhawkUtils::SetWindowSubclassFromAnyThread(
hWnd, TargetWindowSubclassProc, 0);
}
return TRUE;
}
// ------------------ Clean up when mod is disabled ------------------
// Send a message to each windowProc in the process
// If it was subclassed, it will process the message and unsubclass itself
BOOL CALLBACK EnumTargetWindowsUnsubclassFunc(HWND hWnd, LPARAM lParam) {
DWORD dwProcessId = 0;
DWORD dwThreadId = GetWindowThreadProcessId(hWnd, &dwProcessId);
if (!dwThreadId || dwProcessId != GetCurrentProcessId()) {
return TRUE;
}
if (IsTargetWindow(hWnd)) {
Wh_Log(L"Unsubclass: %08X", (DWORD)(UINT_PTR)hWnd);
WindhawkUtils::RemoveWindowSubclassFromAnyThread(
hWnd, TargetWindowSubclassProc);
}
return TRUE;
}
BOOL Wh_ModInit() {
Wh_Log(L">");
// Ensure subclass will be added to newly created windows
HMODULE hModule = GetModuleHandle(L"win32u.dll");
if (!hModule) {
return FALSE;
}
NtUserCreateWindowEx_t pNtUserCreateWindowEx =
(NtUserCreateWindowEx_t)GetProcAddress(hModule, "NtUserCreateWindowEx");
if (!pNtUserCreateWindowEx) {
return FALSE;
}
Wh_SetFunctionHook((void*)pNtUserCreateWindowEx,
(void*)NtUserCreateWindowEx_Hook,
(void**)&NtUserCreateWindowEx_Original);
return TRUE;
}
void Wh_ModAfterInit() {
Wh_Log(L">");
EnumWindows(InitialEnumTargetWindowsFunc, 0);
}
void Wh_ModUninit() {
Wh_Log(L">");
EnumWindows(EnumTargetWindowsUnsubclassFunc, 0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment