将窗口置于前台拒绝在 Windows 10 中工作

问题描述

我有一个 powershell 脚本,它打开一个名为 CNCScreenE 的程序,保存此窗口的屏幕截图,然后关闭该应用程序。

在我运行它的前几次运行得很好。

在那几次之后,现在每次程序被调用时,它不是在前台打开,而是在其他已经打开的东西后面打开(在这种情况下是视觉工作室代码)。屏幕截图仍会保存,但图像包含前景中的任何内容,在本例中为 Visual Studio 代码

我尝试了各种脚本来将窗口置于前台,这些脚本基本上都是同一事物的细微变化,但没有取得多大成功。它们通常只会导致窗口在任务栏中闪烁。

我发现了一些建议,在不首先满足某些条件的情况下,并不总是可以将窗口置于前台,例如最后输入必须来自前台的程序,或者您可以先最小化窗口,然后才可以被带到前台

我的问题是我在通过 powershell 使用 windows api 方面不是很有经验。我知道 add-type 正在编译 c# 代码,然后允许 powershell 访问 api,但我对 c# 几乎一无所知,这是我第一次使用 add-type。

#open screen viewer app
start-process  -FilePath 'C:\Program Files (x86)\CNCScreenE\cncscrne.exe' -ArgumentList 'C:\Users\mcnc\Documents\programming\p900_program\p900' -Passthru

start-sleep -seconds 1

#Get PID for p900 screen viewer
$Screen_viewer = (Get-Process -Name 'CNCScrnE').MainWindowHandle

#bring program to the foreground
Add-Type @"
using System;
using System.Runtime.InteropServices;
public class SFW {
 [DllImport("user32.dll")]
 [return: MarshalAs(UnmanagedType.Bool)]
 public static extern bool SetForegroundWindow(IntPtr hWnd);
}
"@

#call class SFW with Function SetForegroundWindow to bring screen viewer to the front
[SFW]::SetForegroundWindow($Screen_viewer)

我也尝试过这个看起来写得很好的脚本,但是每次我尝试运行它时都会出现一系列错误

Function Set-WindowStyle 
{
    param
    (
        [Parameter()]
        [validateset('FORCEMINIMIZE','HIDE','MAXIMIZE','MINIMIZE','RESTORE','SHOW','SHOWDEFAULT','SHOWMAXIMIZED','SHOWMINIMIZED','SHOWMINNOACTIVE','SHOWNA','SHOWNOACTIVATE','SHOWnorMAL')]
        $Style = 'SHOW',[Parameter()]
        $MainWindowHandle = (Get-Process -Id $pid).MainWindowHandle
    )

    $WindowStates = @{
        FORCEMINIMIZE = 11; HIDE = 0
        MAXIMIZE = 3; MINIMIZE = 6
        RESTORE = 9; SHOW = 5
        SHOWDEFAULT = 10; SHOWMAXIMIZED = 3
        SHOWMINIMIZED = 2; SHOWMINNOACTIVE = 7
        SHOWNA = 8; SHOWNOACTIVATE = 4
        SHOWnorMAL = 1
    }
    Write-Verbose ("Set Window Style {1} on handle {0}" -f $MainWindowHandle,$($WindowStates[$style]))

    $Win32ShowWindowAsync = Add-Type –memberDeFinition @” 
    [DllImport("user32.dll")] 
    public static extern bool ShowWindowAsync(IntPtr hWnd,int nCmdshow);
“@ -name “Win32ShowWindowAsync” -namespace Win32Functions –passthru

    $Win32ShowWindowAsync::ShowWindowAsync($MainWindowHandle,$WindowStates[$Style]) | Out-Null
}

# Usage

# Minimize a running process window
Get-Process -Name Taskmgr | %{Set-WindowStyle MINIMIZE $PSItem.MainWindowHandle}
Get-Process -Name notepad | %{Set-WindowStyle MINIMIZE $PSItem.MainWindowHandle}

# Restore a running process window - the last window called will be topmost
Get-Process -Name Taskmgr | %{Set-WindowStyle RESTORE $PSItem.MainWindowHandle}
Get-Process -Name notepad | %{Set-WindowStyle RESTORE $PSItem.MainWindowHandle}

它产生的错误都与下面基本相同,但指的是各种字符:

Add-Type : c:\Users\mcnc\AppData\Local\Temp\oegsfdcr\oegsfdcr.0.cs(1) : Unexpected 
character '€'
c:\Users\mcnc\AppData\Local\Temp\oegsfdcr\oegsfdcr.0.cs(1) : >>> â€memberDeFinition @†
c:\Users\mcnc\AppData\Local\Temp\oegsfdcr\oegsfdcr.0.cs(2) :     [DllImport(user32.dll)]  
At C:\Users\mcnc\Documents\programming\p900_program\powershell 
screenshot\show-process.ps1:49 char:29
+     $Win32ShowWindowAsync = Add-Type –memberDeFinition @â€
+                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidData: (Microsoft.Power...peCompilerError:AddTypeComp 
   ilerError) [Add-Type],Exception
    + FullyQualifiedErrorId : SOURCE_CODE_ERROR,Microsoft.PowerShell.Commands.AddTypeComm 
   and

我认为这与看起来很奇怪的引号有关,但是当我用常规引号替换它们时,会出现这些对我来说没有多大意义的错误

At C:\Users\mcnc\Documents\programming\p900_program\powershell 
screenshot\show-process.ps1:50 char:5
+     [DllImport("user32.dll")]
+     ~~~~~~~~~~~~~~~~~~~~~~~~~
Unexpected attribute 'DllImport'.
At C:\Users\mcnc\Documents\programming\p900_program\powershell 
screenshot\show-process.ps1:51 char:5
+     public static extern bool ShowWindowAsync(IntPtr hWnd,int nCmdsh ...
+     ~~~~~~
Unexpected token 'public' in expression or statement.
At C:\Users\mcnc\Documents\programming\p900_program\powershell 
screenshot\show-process.ps1:52 char:11
+ "@ -name "Win32ShowWindowAsync" -namespace Win32Functions –passthru
+           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unexpected token 'Win32ShowWindowAsync" -namespace Win32Functions –passthru' in    
expression or statement.
    + CategoryInfo          : ParserError: (:) [],ParentContainsErrorRecordException
    + FullyQualifiedErrorId : UnexpectedAttribute

解决方法

我最好的猜测是您应该只更改外部引号,如下所示:

$Win32ShowWindowAsync = Add-Type –memberDefinition @" 
[DllImport("user32.dll")] 
public static extern bool ShowWindowAsync(IntPtr hWnd,int nCmdShow);
"@ -name "Win32ShowWindowAsync" -namespace Win32Functions –passThru

@" 和 "@ 环绕多行的结构称为 here-string。 here-string 内的引号不应被引用。

,

好吧,我尝试通过 c# 来完成,发现 SetForegroundWindow 不起作用。搜索解决方法我得到了 this one

所以工作 C# 部分代码将如下所示:

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
public class SFW
{
    [DllImport("user32.dll",SetLastError = true)]
    static extern bool SetForegroundWindow(IntPtr hWnd);
    [DllImport("user32.dll",SetLastError = true)]
    public static extern bool ShowWindowAsync(HandleRef hWnd,int nCmdShow);
    public const int SW_RESTORE = 9;

    public static void BringToFront()
    {
        Process[] processes = Process.GetProcessesByName("CNCScrnE");

        foreach (Process p in processes)
        {
            IntPtr windowHandle = p.MainWindowHandle;
            ShowWindowAsync(new HandleRef(null,windowHandle),SW_RESTORE);
            SetForegroundWindow(windowHandle);
        }
    }
}

只需从您的 PowerShell 调用BringToFront 方法。你也可以删除这部分:

    #Get PID for p900 screen viewer
    $Screen_viewer = (Get-Process -Name 'CNCScrnE').MainWindowHandle
,

像往常一样,我在发帖求助后发现了一些有用的东西。

此外,我想我可能已经有了一个可行的解决方案,但没有意识到,因为我正在逐步执行该程序。我记得看到程序闪到前台,然后立即转到 vsc 后面,我想这是因为我刚刚点击了降级按钮。如果我让它在不按任何按钮的情况下运行,它可能会起作用。

无论如何这是我发现的代码就像一个魅力

Function Set-WindowState {
    <#
    .LINK
    https://gist.github.com/Nora-Ballard/11240204
    #>

    [CmdletBinding(DefaultParameterSetName = 'InputObject')]
    param(
        [Parameter(Position = 0,Mandatory = $true,ValueFromPipeline = $true)]
        [Object[]] $InputObject,[Parameter(Position = 1)]
        [ValidateSet('FORCEMINIMIZE','HIDE','MAXIMIZE','MINIMIZE','RESTORE','SHOW','SHOWDEFAULT','SHOWMAXIMIZED','SHOWMINIMIZED','SHOWMINNOACTIVE','SHOWNA','SHOWNOACTIVATE','SHOWNORMAL')]
        [string] $State = 'SHOW'
    )

    Begin {
        $WindowStates = @{
            'FORCEMINIMIZE'     = 11
            'HIDE'              = 0
            'MAXIMIZE'          = 3
            'MINIMIZE'          = 6
            'RESTORE'           = 9
            'SHOW'              = 5
            'SHOWDEFAULT'       = 10
            'SHOWMAXIMIZED'     = 3
            'SHOWMINIMIZED'     = 2
            'SHOWMINNOACTIVE'   = 7
            'SHOWNA'            = 8
            'SHOWNOACTIVATE'    = 4
            'SHOWNORMAL'        = 1
        }

        $Win32ShowWindowAsync = Add-Type -MemberDefinition @'
[DllImport("user32.dll")]
public static extern bool ShowWindowAsync(IntPtr hWnd,int nCmdShow);
'@ -Name "Win32ShowWindowAsync" -Namespace Win32Functions -PassThru

        if (!$global:MainWindowHandles) {
            $global:MainWindowHandles = @{ }
        }
    }

    Process {
        foreach ($process in $InputObject) {
            if ($process.MainWindowHandle -eq 0) {
                if ($global:MainWindowHandles.ContainsKey($process.Id)) {
                    $handle = $global:MainWindowHandles[$process.Id]
                } else {
                    Write-Error "Main Window handle is '0'"
                    continue
                }
            } else {
                $handle = $process.MainWindowHandle
                $global:MainWindowHandles[$process.Id] = $handle
            }

            $Win32ShowWindowAsync::ShowWindowAsync($handle,$WindowStates[$State]) | Out-Null
            Write-Verbose ("Set Window State '{1} on '{0}'" -f $MainWindowHandle,$State)
        }
    }
}

Get-Process -Name CNCScrnE | Set-WindowState -State Minimize
Get-Process -Name CNCScrnE | Set-WindowState -State Restore

这是我发现它在到期时给予信用的地方

https://gist.github.com/lalibi/3762289efc5805f8cfcf

此外,我认为您确实需要在将其置于前台之前将其最小化(或以其他方式更改其状态),否则窗口将仅允许您激活该窗口而不是将其向前移动。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...