我有一个powershell脚本,它打开一个名为cncscreen的程序,保存该窗口的屏幕截图,然后关闭该应用程序。
前几次运行的很好。
在那几次之后,现在每次程序被调用时,它不是在前台打开,而是在其他已经打开的(在这种情况下是visual studio代码)后面打开。截图仍然会被保存,但图像包含了前景中的内容,在本例中是visual studio代码。
我试过各种脚本把窗口带到前台,基本上都是同一件事的轻微变化,没有太大的成功。它们通常只会使窗口在任务栏中闪烁。
我发现了一些建议,如果不首先满足某些条件,则不可能总是将窗口带到前台,例如最后输入必须来自前台的程序,或者您可以先最小化窗口,然后将其带到前台。
我的问题是,我不是很有经验的工作与windows api的通过powershell。我知道add-type是编译c#代码,然后允许powershell访问api,但我对c#几乎一无所知,这是我第一次使用add-type。
#open screen viewer app
Start-Process -FilePath 'C:Program Files (x86)CNCScreenEcncscrne.exe' -ArgumentList 'C:UsersmcncDocumentsprogrammingp900_programp900' -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:UsersmcncAppDataLocalTempoegsfdcroegsfdcr.0.cs(1) : Unexpected
character '€'
c:UsersmcncAppDataLocalTempoegsfdcroegsfdcr.0.cs(1) : >>> â€memberDefinition @â€
c:UsersmcncAppDataLocalTempoegsfdcroegsfdcr.0.cs(2) : [DllImport(user32.dll)]
At C:UsersmcncDocumentsprogrammingp900_programpowershell
screenshotshow-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:UsersmcncDocumentsprogrammingp900_programpowershell
screenshotshow-process.ps1:50 char:5
+ [DllImport("user32.dll")]
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
Unexpected attribute 'DllImport'.
At C:UsersmcncDocumentsprogrammingp900_programpowershell
screenshotshow-process.ps1:51 char:5
+ public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdSh ...
+ ~~~~~~
Unexpected token 'public' in expression or statement.
At C:UsersmcncDocumentsprogrammingp900_programpowershell
screenshotshow-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
@"one_answers"@包围多行被称为这里字符串。在这里字符串中不应该加上引号
嗯,我试着通过c#来做,发现SetForegroundWindow不起作用。我找到了这个
所以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
我也认为你确实需要最小化它(或以其他方式改变它的状态)在把它带到前台之前,否则窗口只允许你激活窗口,而不是把它带到前台。