3

Context:

  • This question is about how to control, through configuration, whether programmatic cross-process window activation (making a window the foreground window with the input focus) is allowed, via the SetForegroundWindow WinAPI function.

It seems that the SPI_GETFOREGROUNDLOCKTIMEOUT / SPI_SETFOREGROUNDLOCKTIMEOUT values used with the SystemParametersInfo WinAPI function correspond to the ForegroundLockTimeout persistent, per-user registry value (in HKEY_CURRENT_USER\Control Panel\Desktop).
The foreground-lock timeout is the period of time following interactive user input during which cross-process window activation is not permitted.

My expectation is as follows:

  • The effective value in a session is the one reported by SPI_GETFOREGROUNDLOCKTIMEOUT, which may differ from the underlying ForegroundLockTimeout registry value if a non-persistent update was made via SPI_SETFOREGROUNDLOCKTIMEOUT (fWinIni parameter set to 0)

  • On next logon, the two values should be back in sync.

This expectation is not met in the following cases:

  • On Windows 11, the SPI_GETFOREGROUNDLOCKTIMEOUT always reports 2147483647 (the max. value of a signed 32-bit integer) on logon - even though the ForegroundLockTimeout registry default value is 200000

    • Update: The behavior was observed on an ARM W11 ISO image run via the VMWare Fusion Technology Preview for M1 Macs, current as of 16 Sep 2022.

    • While non-persistent SPI_SETFOREGROUNDLOCKTIMEOUT updates are possible, an attempt to persistently change the effective SPI_GETFOREGROUNDLOCKTIMEOUT value for future session is quietly ignored.

    • In effect, a new user session defaults to not allowing unconditional window activation.

  • On Windows 10, I observe similar behavior with one particular user account:

    • The behavior is as on Windows 11, except that 0 is the default SPI_GETFOREGROUNDLOCKTIMEOUT value, which cannot be changed persistently. In effect, a new session for this user default to allowing unconditional window activation.

    • Another user account on the same machine does not exhibit this behavior - there, the above expectations are met.

    • The machine is not in developer mode; the account with the divergent behavior is an administrator, while the other is not - but I wouldn't expect that to matter.

My questions:

  • Is the observed Windows 11 behavior to be expected? If so, is it documented somewhere?

  • On Windows 10, what is the explanation for the behavior of the wayward user account? Is there another persistent setting somewhere that overrides the expected behavior?

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • 2
    For what it's worth, the Windows 11 version installed through Hyper-V "Quick Create" feature (version 21H2, build 22000.856), outputs `$true` and `200000` when running this PowerShell one-liner: `$outVal = 0; (Add-Type -PassThru -Name WinApi -Namespace pg -MemberDefinition ' [DllImport("user32.dll")] public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, ref UInt32 pvParam, uint fWinIni); ')::SystemParametersInfo(0x2000 <# SPI_GETFOREGROUNDLOCKTIMEOUT #>, 0, [ref] $outVal, 0); $outVal` – zett42 Sep 16 '22 at 22:17
  • Thanks, @zett42. Another mystery to solve: why does my ARM W11 ISO image run via the VMWare Fusion Technology Preview for M1 Macs act differently? – mklement0 Sep 16 '22 at 22:32
  • 2
    Also, the following PowerShell one-liner succeeds in persisting the timeout value `10000` (so the snippet in my previous comment outputs `10000` even after a reboot): `(Add-Type -PassThru -Name WinApi -Namespace pg1 -MemberDefinition ' [DllImport("user32.dll")] public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, IntPtr pvParam, uint fWinIni); ')::SystemParametersInfo(0x2001 <# SPI_SETFOREGROUNDLOCKTIMEOUT #>, 0, 10000, 0x03 <# SPIF_UPDATEINIFILE | SPIF_SENDCHANGE #> );` – zett42 Sep 16 '22 at 22:33
  • 1
    I have no explanation for the difference between the x86-64 and the ARM versions. Maybe MSFT made the foreground activation even more restrictive, given that ARM is mostly used on mobile devices. It wouldn't surprise me if they have a different policy for mobile devices. – zett42 Sep 16 '22 at 22:40
  • Thanks, @zett42, I've updated the answer with your findings. I'm still baffled by the behavior of the one account on my W10 VM, however, which is x86-64. – mklement0 Sep 16 '22 at 22:47
  • Does the W10 user have something in one of the multiple Policy keys in HKCU? Can you debug the function call? Some of the SPI's are fully in user32, others are in the kernel. – Anders Sep 16 '22 at 23:50
  • @Anders, please tell me what those keys are. Don't know how to debug a function call. What are SPIs? – mklement0 Sep 17 '22 at 00:30
  • 1
    HKEY_CURRENT_USER\Software\Policies\Microsoft and HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies at least, maybe more. Take a look in those and see if anything pops out at you (run Regedit as that user of course). – Anders Sep 17 '22 at 00:37
  • Thanks, @Anders - turns out it was a third-party application that runs on every login via `HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run` - please see my answer. – mklement0 Sep 17 '22 at 21:24

1 Answers1

1
  • In Windows 10+, the registry-based setting (value ForegroundLockTimeout in HKEY_CURRENT_USER\Control Panel\Desktop) is no longer respected, and the invariable default value in a new session is [int]::MaxValue,[1] which in effect disables programmatic activation of windows by processes other than those that happen to run in the current foreground window.

  • In my case, it happened to be a third-party application configured to run on every logon (via registry key HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run) that set the non-persistent SPI_GETFOREGROUNDLOCKTIMEOUT value to 0 on a per-session basis: AutoHotkey


[1] This value in milliseconds amounts to a duration of 24+ days(!) of the system having to be idle (in terms of user input) before a non-foreground process is allowed to activate another window, which in effect amounts to disabling such activations.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • There are ARM desktop machines running Win 11, Apcsilmic Dot 1 etc. Win 8 did its policy changes based on screen size. – Anders Sep 17 '22 at 21:29
  • Indeed, @Anders: my ARM VM runs on a M1 MacBook Pro. Its resolution is 1024 x 768 (which I cannot change). What resolution thresholds did Win 8 use, and where are those policies located? – mklement0 Sep 17 '22 at 21:35
  • 8 inches. There is no policy for the screen size in Win 8, Microsoft just forces it. See my related question https://stackoverflow.com/q/28930582/3501 and the comments from RaymondChen – Anders Sep 17 '22 at 21:41
  • Thanks, @Anders. Raymond states "It's because you have a small screen and only 1GB of memory". I don't know how to measure my VM's virtual screen size, but it has 4GB of memory, so this shouldn't apply. – mklement0 Sep 17 '22 at 21:53