问题描述
我有一个 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
此外,我认为您确实需要在将其置于前台之前将其最小化(或以其他方式更改其状态),否则窗口将仅允许您激活该窗口而不是将其向前移动。