How to bring focus to window by process name?

后端 未结 4 1029
梦毁少年i
梦毁少年i 2020-12-16 22:47

If I\'m understanding this correctly this code should capture the active window and keep it in focus. concentr.exe is the process name. How do I bring a window in focus base

相关标签:
4条回答
  • 2020-12-16 22:59

    I found it:

    Param(
        [string] $proc="C:\Program Files (x86)\Citrix\ICA Client\concentr.exe",
        [string] $adm
    )
    Clear-Host
    
    Add-Type @"
        using System;
        using System.Runtime.InteropServices;
        public class WinAp {
          [DllImport("user32.dll")]
          [return: MarshalAs(UnmanagedType.Bool)]
          public static extern bool SetForegroundWindow(IntPtr hWnd);
    
          [DllImport("user32.dll")]
          [return: MarshalAs(UnmanagedType.Bool)]
          public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
        }
    "@
    $p = Get-Process | Where {$_.mainWindowTitle} |
        Where {$_.Name -like "$proc"}
    if (($p -eq $null) -and ($adm -ne "")) {
        Start-Process "$proc" -Verb runAs
    } elseif (($p -eq $null) -and ($adm -eq "")) {
        Start-Process "$proc"
    } else {
        $h = $p.MainWindowHandle
        [void] [WinAp]::SetForegroundWindow($h)
        [void] [WinAp]::ShowWindow($h, 3)
    }
    
    0 讨论(0)
  • 2020-12-16 22:59

    Have you thought of using the Window Name? I've found this bit of code to work great and not take up a lot of space:

    $wshell = New-Object -ComObject wscript.shell
    $wshell.AppActivate('New Tab - Google Chrome')
    

    Also, if you need to just Alt-TAB back to the last thing that ran (ie: you need focus to come back to the script window after firing something off) try this:

    $wshell = New-Object -ComObject wscript.shell
    $wshell.SendKeys('%{TAB}')
    
    0 讨论(0)
  • 2020-12-16 23:14

    I use this script to do this. Modify as you need...

    For example, the default variables $ProcessNameRegEx and $WindowTitleRegEx will move new Notepad windows (just start a couple of them with no file specifed).

    You can pass different regex expressions to the script. Edit as makes sense to your needs.

    Show-WindowByName

    #Requires -RunAsAdministrator
    
    [CmdletBinding()]
    param (
        [string]
        $ProcessNameRegEx = 'notepad',
    
        [string]
        $WindowTitleRegEx = 'unt'
    )
    
    $cs = @" 
    using System; 
    using System.Runtime.InteropServices;
    
    namespace User32
    {
        public static class WindowManagement
        {
            [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
            public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);
    
            public const int SWP_NOSIZE = 0x01, SWP_NOMOVE = 0x02, SWP_SHOWWINDOW = 0x40, SWP_HIDEWINDOW = 0x80;
    
            public static void SetWindowPosWrappoer(IntPtr handle, int x, int y, int width, int height)
            {
                if (handle != null)
                { 
                    SetWindowPos(handle, 0, x, y, 0, 0, SWP_NOSIZE | SWP_HIDEWINDOW);
    
                    if (width > -1 && height > -1)
                        SetWindowPos(handle, 0, 0, 0, width, height, SWP_NOMOVE);
    
                    SetWindowPos(handle, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
                }
            }
    
            [DllImport("user32.dll", EntryPoint = "ShowWindow")]
            public static extern IntPtr ShowWindow(IntPtr hWnd, int nCmdShow);
    
            public static void ShowWindowWrapper(IntPtr handle, int nCmdShow)
            {
                if (handle != null)
                { 
                    ShowWindow(handle, nCmdShow);
                }
            }
    
            [DllImport("user32.dll", EntryPoint = "SetForegroundWindow")]
            public static extern IntPtr SetForegroundWindow(IntPtr hWnd);
    
            public static void SetForegroundWindowWrapper(IntPtr handle)
            {
                if (handle != null)
                { 
                    SetForegroundWindow(handle);
                }
            }
        }
    }
    "@ 
    
    Add-Type -TypeDefinition $cs -Language CSharp -ErrorAction SilentlyContinue
    
    
    function Move-Window
    {
        param (
            [int]$MainWindowHandle,
            [int]$PosX,
            [int]$PosY,
            [int]$Height,
            [int]$Width
        )
    
        if($MainWindowHandle -ne [System.IntPtr]::Zero)
        {
            [User32.WindowManagement]::SetWindowPosWrappoer($MainWindowHandle, $PosX, $PosY, $Width, $Height);
        }
        else
        {
          throw "Couldn't find the MainWindowHandle, aborting (your process should be still alive)"
        }
    }
    
    
    function Show-Window
    {
        param (
            [int]$MainWindowHandle,
            [int]$CmdShow
        )
    
        if($MainWindowHandle -ne [System.IntPtr]::Zero)
        {
            [User32.WindowManagement]::ShowWindowWrapper($MainWindowHandle, $CmdShow);
            [User32.WindowManagement]::SetForegroundWindowWrapper($MainWindowHandle);
        }
        else
        {
          throw "Couldn't find the MainWindowHandle, aborting (your process should be still alive)"
        }
    }
    
    
    $windows = Get-Process | ? {$_.ProcessName -match $ProcessNameRegEx -and $_.MainWindowTitle -match $WindowTitleRegEx} | Select -Last 100 | Select Id, MainWindowTitle, MainWindowHandle | Sort MainWindowTitle
    
    $h = 180
    $w = 1500
    $x = 400
    $y = 800
    $deltax = 80
    $deltay = 180
    
    foreach ($window in $windows)
    {
        Move-Window $window.MainWindowHandle $x $y $h $w
        Show-Window $window.MainWindowHandle 5
        #$x -= $deltax
        $y -= $deltay
    }
    
    0 讨论(0)
  • 2020-12-16 23:18

    Note:
    * This answer in part uses the same technique as the existing answers, but also introduces a new technique, and aims to contrast the approaches in a focused manner, particularly with respect to whether they're also supported in PowerShell Core.
    * Only the last solution below - which requires on-demand compilation of C# code via Add-Member - properly activates a window if it happens to be minimized.
    * All solutions use PSv4+ syntax; unless explicitly noted, they work in both Windows PowerShell and PowerShell Core (on Windows).


    A simpler solution that doesn't require Add-Type with WinAPI P/Invoke signatures is possible, based on the WScript.Shell COM object's .AppActivate() method (which Inventologist's answer hints at):

    Note:

    • If the target window happens to be minimized, this solution does put the focus on it, but doesn't restore it.
    function Show-Window {
      param(
        [Parameter(Mandatory)]
        [string] $ProcessName
      )
    
      # As a courtesy, strip '.exe' from the name, if present.
      $ProcessName = $ProcessName -replace '\.exe$'
    
      # Get the ID of the first instance of a process with the given name
      # that has a non-empty window title.
      # NOTE: If multiple instances have visible windows, it is undefined
      #       which one is returned.
      $procId = (Get-Process -ErrorAction Ignore $ProcessName).Where({ $_.MainWindowTitle }, 'First').Id
    
      if (-not $procId) { Throw "No $ProcessName process with a non-empty window title found." }
    
      # Note: 
      #  * This can still fail, because the window could have been closed since
      #    the title was obtained.
      #  * If the target window is currently minimized, it gets the *focus*, but is
      #    *not restored*.
      #  * The return value is $true only if the window still existed and was *not
      #    minimized*; this means that returning $false can mean EITHER that the
      #    window doesn't exist OR that it just happened to be minimized.
      $null = (New-Object -ComObject WScript.Shell).AppActivate($procId)
    
    }
    
    # Sample invocation
    Show-Window notepad
    

    A solution that also restores the target window if it happens to be minimized requires Add-Type with WinAPI P/Invoke declarations:

    Note:

    • On first invocation of the function in a PowerShell session, there is a noticeable delay due to having to compile the helper type that provides WinAPI access.

    • Unlike the solution above, this solution restores a currently minimized window to ensure that its content is visible, while properly activating a currently-maximized window without restoring it.

    function Show-Window {
      param(
        [Parameter(Mandatory)]
        [string] $ProcessName
      )
    
      # As a courtesy, strip '.exe' from the name, if present.
      $ProcessName = $ProcessName -replace '\.exe$'
    
      # Get the PID of the first instance of a process with the given name
      # that has a non-empty window title.
      # NOTE: If multiple instances have visible windows, it is undefined
      #       which one is returned.
      $hWnd = (Get-Process -ErrorAction Ignore $ProcessName).Where({ $_.MainWindowTitle }, 'First').MainWindowHandle
    
      if (-not $hWnd) { Throw "No $ProcessName process with a non-empty window title found." }
    
      $type = Add-Type -PassThru -NameSpace Util -Name SetFgWin -MemberDefinition @'
        [DllImport("user32.dll", SetLastError=true)]
        public static extern bool SetForegroundWindow(IntPtr hWnd);
        [DllImport("user32.dll", SetLastError=true)]
        public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);    
        [DllImport("user32.dll", SetLastError=true)]
        public static extern bool IsIconic(IntPtr hWnd);    // Is the window minimized?
    '@ 
    
      # Note: 
      #  * This can still fail, because the window could have bee closed since
      #    the title was obtained.
      #  * If the target window is currently minimized, it gets the *focus*, but its
      #    *not restored*.
      $null = $type::SetForegroundWindow($hWnd)
      # If the window is minimized, restore it.
      # Note: We don't call ShowWindow() *unconditionally*, because doing so would
      #       restore a currently *maximized* window instead of activating it in its current state.
      if ($type::IsIconic($hwnd)) {
        $type::ShowWindow($hwnd, 9) # SW_RESTORE
      }
    
    }
    
    # Sample invocation
    Show-Window notepad
    
    0 讨论(0)
提交回复
热议问题