Skip to content

Add Mod: Hide From Screencapture#4728

Open
AjaxFNC-YT wants to merge 12 commits into
ramensoftware:mainfrom
AjaxFNC-YT:main
Open

Add Mod: Hide From Screencapture#4728
AjaxFNC-YT wants to merge 12 commits into
ramensoftware:mainfrom
AjaxFNC-YT:main

Conversation

@AjaxFNC-YT

Copy link
Copy Markdown

Mod authorship

If this pull request introduces a new mod, please complete the section below.

This mod was created by:

    • The submitter, without AI assistance
    • The submitter, with AI assistance
    • Claude
    • ChatGPT
    • Gemini
    • Another AI (please specify):
    • Other (please specify):

@AjaxFNC-YT AjaxFNC-YT changed the title Add files via upload Add Mod: Hide From Screencapture Jul 9, 2026
Renamed file to match id in mod metadata
@AjaxFNC-YT

AjaxFNC-YT commented Jul 10, 2026

Copy link
Copy Markdown
Author

Oops, forgot the github tag, let me add it

@m417z

m417z commented Jul 10, 2026

Copy link
Copy Markdown
Member

Submission review

Note: This review was done by Claude, and then refined manually. Due to the amount of submissions, doing a fully manual review for each pull request is no longer feasible. Thank you for understanding.

Please address the following issues. The items in the collapsed sections are optional, so it's your call whether to address them.


1. Heavy, blocking work runs inside the WH_MOUSE_LL / WH_KEYBOARD_LL callbacks — this freezes all system input. On WM_MBUTTONDOWN (and on the hotkey), ExplorerMouseHookProc / ExplorerKeyboardHookProc call ToggleWindowFromTaskbarPoint synchronously, which does:

  • UI Automation COM work — CoCreateInstance, ElementFromPoint, and up to 16 levels of GetParentElement tree-walking;
  • a full EnumWindows scoring pass that calls OpenProcess + QueryFullProcessImageNameW + SHGetPropertyStoreForWindow (COM) per top-level window on the desktop;
  • a SendMessageTimeoutW with a 700 ms timeout (SMTO_BLOCK).

Low-level hook callbacks run on the thread that installed the hook and block delivery of all mouse/keyboard input system-wide until they return. This chain can easily take hundreds of ms to over a second, so every middle-click / hotkey press stutters the entire desktop. This is the most important item.

The hook must return almost immediately. Since the hook already runs on your dedicated g_explorerHookThread (which has a message loop), do the cheap gate in the hook, then post the point to that thread and let the loop do the heavy resolution + send:

if (wParam == WM_MBUTTONDOWN && TriggerModeHasMouse() && IsModifierSatisfied() &&
    IsPointOnTaskbar(mouse->pt, nullptr)) {
    PostThreadMessageW(g_explorerHookThreadId, WM_APP_TOGGLE, 0,
                       POINTTOPOINTS(mouse->pt));
    g_swallowStartTick.store(GetTickCount());
    return 1;  // swallow, but return right away
}

IsPointOnTaskbar is just WindowFromPoint + a GetParent walk, so the synchronous part stays trivial while the UIA/EnumWindows/SendMessageTimeout work moves off the input path.

2. Don't swap the window procedure directly with SetWindowLongPtr(GWLP_WNDPROC). MaybeSubclassWindow (line 1452) and the teardown in MaybeUnsubclassWindow / ToggleSubclassProc's WM_NCDESTROY install and remove the hook by writing GWLP_WNDPROC. This is problematic on several fronts:

  • It breaks the subclass chain if any other mod (or the app itself) subclasses the same window — restoring "the original" clobbers whatever was chained on top.
  • You apply and remove it cross-thread (from Wh_ModInit's EnumWindows, from the CreateWindowExW hook on arbitrary threads, and from Wh_ModUninit on an arbitrary thread) — writing GWLP_WNDPROC for a window owned by another thread races with that thread dispatching messages.
  • On unload, if any window's restore is missed or raced, that window still points at ToggleSubclassProc after the mod DLL is unmapped → crash on the next message.

Use WindhawkUtils::SetWindowSubclassFromAnyThread / RemoveWindowSubclassFromAnyThread, which route the (un)subclass through the window's owning thread and preserve the chain (see https://github.com/ramensoftware/windhawk/wiki/Development-tips).

3. You don't need to subclass every user-facing window in every process. Combined with @include *, the current design hooks CreateWindowExW and subclasses every "primary" window in every process on the system, purely so that some window in the target process can receive the toggle message. But the toggle is applied process-wide anyway (ApplyDisplayAffinityForCurrentProcess enumerates all of the process's windows), so a single message-only window (HWND_MESSAGE) created once per process is enough to receive the toggle — carry the target HWND in the message payload. That removes the per-window subclassing entirely (and with it issue #2's chain/teardown problem) and cuts the footprint of injecting into every process. The broad @include * itself is understandable — SetWindowDisplayAffinity only works on windows of the calling process, so the target must run the toggle itself — but the per-window subclassing on top of it is avoidable.

4. @architecture x86-64 means 32-bit apps can't be toggled at all. The toggle only works if the mod is loaded in the target process (the registered message hits the subclass/listener, which calls SetWindowDisplayAffinity in-process). With x86-64 the mod never loads into 32-bit processes, so middle-clicking a 32-bit taskbar app silently does nothing (the registered message just reaches the app's own WndProc and returns Failed). Plenty of taskbar apps are still 32-bit. Omit @architecture entirely — that covers x86 and x86-64 (which itself transparently covers ARM64), so the mod loads into 32-bit and 64-bit targets alike.

5. Explorer-hosted windows are never restored on unload (reversibility gap). Wh_ModUninit skips the affinity restore for explorer (if (!g_processIsExplorer.load() && IsProcessHiddenByMod()), line 1897). If a user hid a File Explorer window (a common taskbar app), disabling the mod leaves that window stuck with WDA_EXCLUDEFROMCAPTURE until it's closed or explorer restarts — the effect doesn't disappear when the mod is disabled, which Windhawk expects it to. Restore explorer's managed windows too (or explain why they're intentionally excluded).

Optional improvements

Minor polish — none of this affects users, so it's your call.

  • Drop the custom Log wrapper (lines 403–410). Wh_Log already takes printf-style format strings directly and already prefixes the mod name, so the _vsnwprintf_s-into-a-2048-buffer wrapper is redundant — replace Log(L"...", ...) calls with Wh_Log(L"...", ...).
  • Use WindhawkUtils::SetFunctionHook for the CreateWindowExW hook instead of the raw Wh_SetFunctionHook(GetProcAddress(user32, "CreateWindowExW"), ...) idiom (lines 1841–1851): WindhawkUtils::SetFunctionHook(CreateWindowExW, CreateWindowExW_Hook, &g_originalCreateWindowExW);.
  • Dead legacy-settings migration. This is a brand-new v1.0.0 mod, but LoadSettings names its settings TriggerModeV2 / TriggerModifierV2 / HoverHotkeyV2 and falls back to reading non-existent integer settings TriggerMode / TriggerModifier / HoverHotkey (which aren't in the settings block, so they always return the default 0). There's no v1 to migrate from — this looks like an AI artifact. Remove the legacy branches and rename the keys to TriggerMode / TriggerModifier / HoverHotkey.
  • The WH_MOUSE_LL hook is installed unconditionally, while the keyboard hook is gated on TriggerModeHasHotkey(). For consistency (and to avoid touching every system mouse event when in hotkey-only mode), install the mouse hook only when TriggerModeHasMouse().

Functionality notes

Non-critical observations about the feature behavior itself.

  • Taskbar-button → window resolution is heuristic. ResolveTaskbarButtonTargetWindow picks a UIA descriptor and then scores EnumWindows candidates by fuzzy title/exe/AppUserModelId matching with a threshold of 35. With grouped taskbar buttons, multiple windows of the same app, or apps whose title doesn't resemble the button label, this can resolve to the wrong window or to none. It's inherent to inferring the HWND from a taskbar button, but worth being aware of.
  • The protection list is best-effort. IsProtectedProcessPath matches a few hardcoded exe names and path substrings (c:\riot games\, \easyanticheat\, \battleye\, …). Anti-cheat installed on another drive, in a non-default path, or any engine not on the list won't be caught, and the readme's safety promise is only as good as this list. Given that the whole feature (hiding windows from capture, incl. games) carries real anti-cheat/ban risk, consider making the readme clearer that the protection is best-effort rather than a guarantee.
  • The gray-border indicator uses DWMWA_BORDER_COLOR, which is Windows 11 (22000+) only — consistent with the mod's stated Windows 11 scope, just noting it won't work if anyone runs it on Windows 10.

@m417z

m417z commented Jul 12, 2026

Copy link
Copy Markdown
Member

Submission review

Note: This review was done by Claude, and then refined manually. Due to the amount of submissions, doing a fully manual review for each pull request is no longer feasible. Thank you for understanding.

Please address the following issues. The items in the collapsed sections are optional, so it's your call whether to address them.


  • The heavy toggle work runs on the low-level-hook thread, which stalls system-wide input during every toggle. ExplorerHookThreadMain both owns the WH_MOUSE_LL/WH_KEYBOARD_LL hooks (installed via SetWindowsHookExW on that thread, lines 1522/1543) and runs the message loop that services kExplorerToggleMessage by calling ToggleWindowFromTaskbarPoint (lines 1574–1578). That toggle path does a lot of blocking work — UIA ElementFromPoint + a tree walk, an EnumWindows over every top-level window on the desktop with OpenProcess/QueryFullProcessImageNameW/SHGetPropertyStoreForWindow per window, and finally SendMessageTimeoutW with up to kToggleSendTimeoutMs (700 ms) and SMTO_BLOCK. While that thread is busy, it isn't in GetMessage, so the OS can't deliver low-level hook callbacks to it and every mouse/keyboard event is delayed up to LowLevelHooksTimeout (~300 ms) before being passed through un-hooked. The result is a perceptible system-wide input hitch on each toggle. The raw hook callbacks themselves are correctly kept thin (they just PostThreadMessageW and return), so the fix is to also move the heavy work off the hook thread: post the point to a dedicated worker thread with its own message loop and let the hook thread do nothing but pump. See the low-level-hook guidance in the wiki (Development tips).

  • The "protected-app" list guards the toggle, but not injection — so the README oversells safety. The protection list (and DisableProtectionList) only prevents the mod from calling SetWindowDisplayAffinity on a protected process; it does nothing about the fact that @include * causes Windhawk to inject this DLL into the target process in the first place. For anti-cheat titles, the injection itself (an unknown module in the process) is the thing that gets flagged — and that has already happened by the time Wh_ModInit runs the protection check. Windhawk already excludes well-known game folders (Riot Games, Steam, Epic, EasyAntiCheat_EOS, etc.) from injection entirely (see Injection targets and critical system processes), which covers the common cases — but a game installed in a non-standard path is still injected, and the mod's protection list gives the user no protection there. Two concrete things: (1) reword the README "Safety" section so users understand the guard is about the hide action, not about avoiding injection, and (2) consider adding @exclude entries for the known anti-cheat executables so the DLL isn't even loaded into them.

  • Fuzzy matching can hide the wrong app. When the taskbar button has no native HWND (the usual case for the Win11 XAML taskbar), ResolveTaskbarButtonTargetWindow falls back to scoring window titles/exe/AppUserModelId across all windows and accepts the best with score >= 35 (line 891). Two apps with similar titles can cross-match, and since hiding-from-capture is a silent effect (the window just vanishes from recordings), the user may not notice they hid the wrong app. Consider requiring a stronger signal (e.g. an AppUserModelId match) or surfacing which window was actually targeted.

Two options that come to mind:

  • Use AutomationId to get the HWND. Example value: "Window: 0x1f114a".
  • Extract the HWND using native calls. Example mod for reference: Taskbar Volume Control Per-App.
Optional improvements

Minor polish — none of this affects users, so it's your call.

  • ERROR_CLASS_ALREADY_EXISTS fall-through can reuse a stale window class. In ReceiverThreadMain (lines 1222–1228) a failed RegisterClassW is treated as success when the error is ERROR_CLASS_ALREADY_EXISTS, and the code then proceeds to CreateWindowExW against whatever class is already registered. On a normal unload the class is unregistered (end of ReceiverThreadMain), so this branch shouldn't trigger — but if a previous teardown ever failed to complete, the lingering registration still points lpfnWndProc at the old (now-unmapped) mod image, and reusing it dispatches messages into a dangling proc. Safer to always register fresh with the mod's own hInstance and treat ALREADY_EXISTS as a hard failure rather than reuse.
  • g_processHidden is dead. It's stored in ApplyDisplayAffinityForCurrentProcess (line 1146) but never read anywhere. Remove it.
  • Unhide clobbers a custom border color. ApplyHiddenBorderIndicator(hwnd, false) resets DWMWA_BORDER_COLOR to DWMWA_COLOR_DEFAULT (line 990), so if the app (or another mod) had set a custom border color, restoring drops it to the system default rather than the original. If you want full reversibility, read and stash the original color alongside the affinity in RememberManagedWindowAffinity.
  • Trim unused -l libraries. -lpropsys, -lruntimeobject, and -luiautomationcore look unused — UIA is consumed purely through COM (CoCreateInstance + interfaces), which needs only the headers and -luuid, and there's no WinRT/Ro* usage despite WINRT_LEAN_AND_MEAN. Worth double-checking a build with them removed.
  • The 2 s retry timer is perpetual. kExplorerHookRetryIntervalMs re-checks the hooks every 2 s forever in explorer. It's cheap and idempotent, but LL hooks rarely drop, so a longer interval would reduce needless wakeups.

Functionality notes

Non-critical observations and ideas about the feature behavior itself.

  • All the risky logic lives inside explorer.exe. The UIA tree walk, EnumWindows, and fuzzy matching run on the explorer hook thread, so a hang or fault there destabilizes the shell. None of that work actually requires being in explorer — LL hooks, UIA, EnumWindows, and SendMessageTimeout all work from any process — so in principle the controller could live in a dedicated process while only the thin receiver stays @include *. Not a required change, but worth considering for blast-radius isolation. Mod example for running some of the functionality in an isolated process: Simple Window Switcher.
  • Toggle applies to the whole process, not the clicked window. The receiver resolves a specific sourceWindow but then hides/shows every user-facing top-level window of that process (ApplyDisplayAffinityForCurrentProcess), using sourceWindow only to decide direction. For multi-window apps (several browser or explorer windows, each with its own taskbar button), clicking one button toggles them all. If per-window behavior is intended, sourceWindow is already available to scope it to just that HWND.

@m417z

m417z commented Jul 15, 2026

Copy link
Copy Markdown
Member

Thanks for the update. You didn't address this:

  • The "protected-app" list guards the toggle, but not injection — so the README oversells safety.
    [...]
    Windhawk already excludes well-known game folders (Riot Games, Steam, Epic, EasyAntiCheat_EOS, etc.) from injection entirely (see Injection targets and critical system processes), which covers the common cases — but a game installed in a non-standard path is still injected, and the mod's protection list gives the user no protection there.

Also, I tried it with Notepad.

  • I didn't see the "AutomationId hwnd match" log. Did you test that it works?
  • I don't see a border. Logs are below.
01:43:01.825 6568 explorer.exe  [WH] [local@hide-from-screencapture] [1387:ToggleWindowFromTaskbarPoint]: ToggleWindowFromTaskbarPoint: taskbar hit root=0x0000000000010154
01:43:01.842 6568 explorer.exe  [WH] [local@hide-from-screencapture] [872:ResolveTaskbarButtonTargetWindow]: ResolveTaskbarButtonTargetWindow: selected taskbar descriptor name='Untitled - Notepad - 1 running window' automationId='Window: 0x404b6' class='Taskbar.TaskListButtonAutomationPeer' framework='XAML' help='' status=''
01:43:01.872 6568 explorer.exe  [WH] [local@hide-from-screencapture] [893:ResolveTaskbarButtonTargetWindow]: ResolveTaskbarButtonTargetWindow: unique process match -> hwnd=0x00000000000404B6 pid=6968 label='Untitled - Notepad'
01:43:01.874 6568 explorer.exe  [WH] [local@hide-from-screencapture] [1408:ToggleWindowFromTaskbarPoint]: ToggleWindowFromTaskbarPoint: resolved target hwnd=0x00000000000404B6 label='Untitled - Notepad'
01:43:01.874 6968 notepad.exe  [WH] [local@hide-from-screencapture] [1194:ReceiverWindowProc]: ReceiverWindowProc: received toggle source=0x00000000000404B6 pid=6968
01:43:01.875 6968 notepad.exe  [WH] [local@hide-from-screencapture] [1165:ToggleDisplayAffinityForCurrentProcess]: ToggleDisplayAffinityForCurrentProcess: pid=6968 managed=0 source=0x00000000000404B6 sourceHidden=0 hide=1 allowUnmanagedRestore=0
01:43:01.876 6968 notepad.exe  [WH] [local@hide-from-screencapture] [930:RememberManagedWindowAffinity]: RememberManagedWindowAffinity: hwnd=0x00000000000404B6 originalAffinity=0x00000000 inserted=1 stored=0x00000000
01:43:01.877 6968 notepad.exe  [WH] [local@hide-from-screencapture] [1058:ApplyDisplayAffinityForWindow]: ApplyDisplayAffinityForWindow: hwnd=0x00000000000404B6 hide=1 currentAffinity=0x00000000 desiredAffinity=0x00000011 exStyle=0x0000000000000110
01:43:01.878 6968 notepad.exe  [WH] [local@hide-from-screencapture] [972:ApplyHiddenBorderIndicator]: ApplyHiddenBorderIndicator: couldn't read original border color hwnd=0x00000000000404B6 hr=0x80070057; default color will be restored
01:43:01.879 6968 notepad.exe  [WH] [local@hide-from-screencapture] [992:ApplyHiddenBorderIndicator]: ApplyHiddenBorderIndicator: hwnd=0x00000000000404B6 hidden=1 color=0x00888888
01:43:01.879 6968 notepad.exe  [WH] [local@hide-from-screencapture] [1068:ApplyDisplayAffinityForWindow]: ApplyDisplayAffinityForWindow: SetWindowDisplayAffinity succeeded hwnd=0x00000000000404B6 result=Hidden
01:43:01.880 6568 explorer.exe  [WH] [local@hide-from-screencapture] [1355:SendToggleMessageToWindow]: SendToggleMessageToWindow: receiver=0x0000000000060196 pid=6968 result=1
01:43:01.881 6568 explorer.exe  [WH] [local@hide-from-screencapture] [1423:ToggleWindowFromTaskbarPoint]: ToggleWindowFromTaskbarPoint: toggle completed hwnd=0x00000000000404B6 result=1 actualLabel='Untitled - Notepad'

@m417z

m417z commented Jul 16, 2026

Copy link
Copy Markdown
Member

Submission review

Below is another AI review with correctness issues, but on a personal note: it seems to me like a great idea, but I think that it can be made more useful by having a per-window effect, not a per-process effect.

If you manage to extract a window handle, you can use it to hide that exact window. Instead, you get its process id and hide all its windows, which is sub-optimal, while doing the right thing is probably easier.

If you don't manage to extract a window handle, you're getting the app id. You could affect all windows with that app id, which is probably the best approximation using that method. Instead, again, you affect all the window of that process.

Also, I noticed that the mod doesn't work in some cases, for example the Run dialog (Win+R).

Regarding the border color: It's barely noticeable in the default Windows light theme (I haven't tried others). How about changing the default color to something more noticeable, such as red (255, 0, 0)?

As discussed before, remove the "Disable protected-app blocking" option and the IsProtectedProcessPath function. You can add @exclude entries if you prefer. You can also use paths. This will actually prevent the mod from being injected.


1. The hook-retry watchdog timer never fires (and never gets killed). In ExplorerHookThreadMain:

SetTimer(nullptr, kExplorerHookRetryTimerId, kExplorerHookRetryIntervalMs, nullptr);
...
if (msg.message == WM_TIMER && msg.wParam == kExplorerHookRetryTimerId) { ... }
...
KillTimer(nullptr, kExplorerHookRetryTimerId);

When SetTimer is called with a NULL window, the nIDEvent argument is ignored and the function returns a system-generated timer ID; the WM_TIMER message carries that generated ID in wParam, not your constant kExplorerHookRetryTimerId (1). So msg.wParam == kExplorerHookRetryTimerId is essentially never true — EnsureExplorerHooksInstalled is never re-run — and KillTimer(nullptr, 1) kills nothing. This defeats the entire purpose of the retry loop (recovering the low-level hooks after they're silently dropped, e.g. Windows dropping an LL hook that exceeds LowLevelHooksTimeout, or a graphics-driver/explorer hiccup). The middle-click/hotkey trigger then stops working with no recovery until a reload.

Capture the returned ID and use it (pass 0 as nIDEvent), like hotcorner-hotkeys.wh.cpp and keyboard-shortcut-actions.wh.cpp do:

UINT_PTR retryTimer = SetTimer(nullptr, 0, kExplorerHookRetryIntervalMs, nullptr);
...
if (msg.message == WM_TIMER && msg.wParam == retryTimer) { ... }
...
KillTimer(nullptr, retryTimer);

(Or attach the timer to a TIMERPROC and drop the wParam compare entirely.)

2. Global g_uia (ComPtr<IUIAutomation>) is released off its owning thread at process shutdown. g_uia is created and used on the explorer worker thread (an STA — CoInitializeEx(COINIT_APARTMENTTHREADED)), and correctly Reset() on that thread during a normal unload. But Windhawk does not call Wh_ModUninit when explorer itself terminates (restart, sign-out, reboot). In that path the OS terminates the worker thread first and then runs the global ComPtr destructor on the shutdown thread — releasing the apartment-affine UIA client from a thread that isn't its owner, while its STA is gone, under the loader lock. That can hang or crash the process during teardown. Since explorer restarts are routine, mark the global to suppress the automatic destructor and keep the existing explicit release on the worker thread:

[[clang::no_destroy]] ComPtr<IUIAutomation> g_uia;

The g_uia.Reset() in ExplorerWorkerThreadMain stays as-is (it handles the controlled-unload path on the correct thread).

Optional improvements

Minor polish — none of this affects users, so it's your call.

  • -lshell32 is unused. No shell32 API is called (PathFindFileNameW/PathStartsWith* are shlwapi, GetApplicationUserModelId is kernel32). Drop -lshell32 from @compilerOptions.
  • WindhawkUtils::StringSetting (RAII) would replace the three Wh_GetStringSetting + Wh_FreeStringSetting pairs in LoadSettings and remove the manual frees. Also note Wh_GetStringSetting never returns NULL (it returns L""), so the value && guard in SettingEquals is redundant.

Functionality notes

Non-critical observations about the feature behavior itself.

  • DWMWA_BORDER_COLOR is write-only. ApplyHiddenBorderIndicator calls DwmGetWindowAttribute(hwnd, DWMWA_BORDER_COLOR, ...) to remember the original color, but DWM doesn't support getting that attribute (it returns an error), so g_managedWindowOriginalBorderColor never actually stores anything and unhide always resets the border to DWMWA_COLOR_DEFAULT rather than any pre-existing custom color. Harmless in practice, but the "remember original" code path is effectively dead.
  • Toggle is per-process, not per-window. Resolving a taskbar button hides/unhides all of that process's user-facing primary windows (via EnumWindows filtered to the pid), using the clicked window only to decide hide-vs-unhide. That's a reasonable match for taskbar grouping, but worth being explicit about in the README if users expect only the specific window to be affected.
  • Heuristic window resolution is best-effort. The fallback chain (AutomationId → AppUserModelID → exe/title normalization → "only capture-hidden process") can fail to resolve or deliberately refuse ambiguous matches (multiple processes with the same app name), so some taskbar buttons may not toggle. Expected given the Win11 XAML taskbar, just a robustness FYI.

@m417z

m417z commented Jul 17, 2026

Copy link
Copy Markdown
Member

It doesn't work for me when buttons are grouped. For example, with 2 Explorer windows:

03:09:34.956 6568 explorer.exe  [WH] [local@hide-from-screencapture] [1573:ToggleWindowFromTaskbarPoint]: ToggleWindowFromTaskbarPoint: taskbar hit root=0x0000000000010154
03:09:34.969 6568 explorer.exe  [WH] [local@hide-from-screencapture] [1040:ResolveTaskbarButtonTargetWindow]: ResolveTaskbarButtonTargetWindow: selected taskbar descriptor name='File Explorer - 2 running windows pinned' automationId='Appid: Microsoft.Windows.Explorer' class='Taskbar.TaskListButtonAutomationPeer' framework='XAML' help='' status=''
03:09:34.992 6568 explorer.exe  [WH] [local@hide-from-screencapture] [1085:ResolveTaskbarButtonTargetWindow]: ResolveTaskbarButtonTargetWindow: no unambiguous target found for taskbar button name='File Explorer - 2 running windows pinned' automationId='Appid: Microsoft.Windows.Explorer'
03:09:34.993 6568 explorer.exe  [WH] [local@hide-from-screencapture] [1579:ToggleWindowFromTaskbarPoint]: ToggleWindowFromTaskbarPoint: failed to resolve taskbar button target

Does it work for you?
Here's a snippet to get an AppId of a window you can use:
https://gist.github.com/m417z/451dfc2dad88d7ba88ed1814779a26b4

Also please remove IsProtectedProcessPath as discussed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants