raz0shi
raz0shi

Reputation: 11

How to bring GUI window to front after an event?

As the title says, how can I bring a Powershell GUI window in front of another window after an event has happened, if it is at all possible? As in, I have, for example, Firefox opened and the Powershell GUI is running behind it, after certain event happens inside of the Powershell it pops in front of the Firefox?

Upvotes: 1

Views: 971

Answers (1)

mklement0
mklement0

Reputation: 439597

On Windows, you can use [Microsoft.VisualBasic.Interaction]::AppActivate() to reactivate your own process' main window via the process ID, as reflected in the automatic $PID variable:

# Enable cross-process window activation (see below).
(Add-Type -ErrorAction Stop -PassThru -Namespace "Random.Ns$PID.AllowWindowActivation" -Name WinApiHelper -MemberDefinition @'
  [DllImport("user32.dll", EntryPoint="SystemParametersInfo")]
  static extern bool SystemParametersInfo_Set_UInt32(uint uiAction, uint uiParam, UInt32 pvParam, uint fWinIni);
  public static void AllowWindowActivation()
  {
    if (! SystemParametersInfo_Set_UInt32(0x2001 /* SPI_SETFOREGROUNDLOCKTIMEOUT */, 0, 0 /* timeout in secs */, 0 /* non-persistent change */)) {
      throw new System.ComponentModel.Win32Exception(System.Runtime.InteropServices.Marshal.GetLastWin32Error(), "Unexpected failure calling SystemParametersInfo() with SPI_SETFOREGROUNDLOCKTIMEOUT");
    }
  }
'@)::AllowWindowActivation()

# Load the required assembly.
Add-Type -AssemblyName Microsoft.VisualBasic

# Launch a sample GUI application that will steal the focus
# (will become the foreground application).
Start-Process notepad.exe

# Wait a little.
Start-Sleep 3 

# Now reactivate the main window of the current process.
[Microsoft.VisualBasic.Interaction]::AppActivate($PID)

Note:

  • General programmatic activation of arbitrary windows across process boundaries is prevented by default:

    • Instead of the targeted window getting activated, its taskbar button flashes, so as to signal to the user the intent to make the window active.

    • However, programmatic activation from code running in the current foreground window seems to always be permitted.

  • The Add-Type -MemberDefinition call above overrides this for the current session using a P/Invoke call to the SystemParametersInfo WinAPI function, via setting its SPI_SETFOREGROUNDLOCKTIMEOUT parameter to 0.

    • This will incur a one-time compilation performance penalty per session.

    • Cross-process window activation will be enabled for the remainder of the session, for all processes.

    • [Doesn't work anymore in W10+] The alternative is to persistently configure your user account to allow activation, via the registry:

      • Set the ForegroundLockTimeout per-user registry value in HKEY_CURRENT_USER\Control Panel\Desktop to 0 (the default is 200000 msecs., i.e. 3 minutes and 20 secs); requires logging off or rebooting for the change to take effect:

        Set-ItemProperty 'registry::HKEY_CURRENT_USER\Control Panel\Desktop' ForegroundLockTimeout 0
        

Upvotes: 2

Related Questions