Powershell - CloseMainWindow 对所有人有用吗?
Powershell - CloseMainWindow work for all?
我正在寻找一种优雅地 close/quit 在 GoogleDriveFS 进程下运行的 GoogleDrive 应用程序的方法。
get-process GoogleDriveFS
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
219 16 10796 5732 0.05 4392 1 GoogleDriveFS
333 22 11820 32364 0.17 8424 1 GoogleDriveFS
297 19 16528 34860 0.06 12036 1 GoogleDriveFS
245 17 10472 23992 0.03 14296 1 GoogleDriveFS
572 26 52256 82728 0.84 17788 1 GoogleDriveFS
518 21 28668 68208 0.44 18460 1 GoogleDriveFS
1024 59 47016 89396 27.95 19452 1 GoogleDriveFS
类似 Process.CloseMainWindow 的方法适合这个吗?还是有更好的方法来确保该应用不是 运行?
你可以这样做:
do {
$running = try { Get-Process -Name GoogleDriveFS -ErrorAction Stop } catch { Write-Host "Error: $($PSItem.Exception.Message) " }
$running | ForEach-Object {
$_.CloseMainWindow()
Write-Debug -Message "Closing ($_).pm "
}
}
until ($running -eq $null)
但是,这将提示用户确认关闭。
您也可以使用 close()
方法来避免提示用户或 kill()
立即释放所有资源。
CloseMainWindow()
Closes a process that has a user interface by sending a close message to its main window.
Close() Frees all the resources that are associated with this component.
Kill() Immediately stops the associated process.
通过https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.process?view=net-6.0#methods
tl;dr
System.Diagnostics.Process.CloseMainWindow()
将 不 工作,原因在底部解释。
注:
- 如果目标进程不是从您自己的用户帐户启动的,您需要 运行 从 提升的 (运行作为管理员)会话。
你可以尝试以下实现优雅终止,但不能保证它会起作用:
# Asks all GoogleDriveFS processes to terminate, which they may or may not do.
# A status line is output to stdout for each targeted process,
# indicating whether the termination request was successfully *sent*.
# Note: ".exe" must be used, whereas it mustn't be
# with PowerShell's *-Process cmdlets.
taskkill.exe /im GoogleDriveFS.exe
如果没有,强制终止是您唯一的选择,最容易实现的是:
# !! Forcefully terminates all GoogleDriveFS, without cleanup.
Stop-Process -Force -Name GoogleDriveFS
注意:如下所述,Stop-Process
总是 强制终止。 -Force
开关的唯一功能是抑制在您尝试终止属于不同用户的进程时出现的潜在确认提示(仅适用于提升)。
这是一个 片段,它首先尝试正常终止,然后在指定的超时后退回到强制终止:
$processName = 'GoogleDriveFS'
$timeOutSecs = 2
# Get all existing processes of interest.
$processes = Get-Process -ErrorAction Ignore -Name $processName
if (-not $processes) {
Write-Verbose -Verbose "No $processName processes running."
} else {
# Ask the processes to terminate, which they may or may not do.
taskkill.exe /im "$processName.exe" *>$null
try {
# Wait for up to $timeOutSecs seconds for the processes to -
# potentially - terminate gracefully.
$processes | Wait-Process -ErrorAction Stop -Timeout $timeOutSecs
} catch {
Write-Warning "Forcefully terminating (remaining) $processName processes..."
# Note: This assumes that you don't care about any new
# processes that may have launched since Get-Process was called.
$processes | Stop-Process -Force
}
}
在 Windows 上,正常 终止基本上只是 GUI-subsystem 应用程序的一个选项,即具有主 window(无论可见与否)的进程,因此有一个 消息循环 ,可以将 WM_CLOSE
消息发布到其中。
换句话说:你不能要求console Windows 上的应用程序正常终止(除非他们实现了一些 application-specific 自定义机制,其他进程可以通过该机制请求终止)。
对于受支持的应用程序,有重要注意事项:
无法保证终止,即使确实发生,也无法保证其时机:
- 目标进程可能处于无法处理
WM_CLOSE
消息的状态,比如当时恰好在显示模态对话框,或者恰好卡住了。
- 目标进程可能会悄悄地拒绝终止。
- 目标进程可能会提出一个模式对话框来确认终止的意图,特别是在试图关闭一个打开了未保存文档的 editor-like 应用程序时。
因此,如果您需要确保终止,您必须监控进程以实际终止之后,可能会在适当的超时时间.
后强行终止它
taskkill.exe
通过其 /f
选项提供强制终止。
- .NET 通过
System.Diagnostics.Process.Kill()
提供强制终止
- 顺便说一句:从 PowerShell 7.2.x 开始,
Stop-Process
cmdlet invariably uses this method, i.e. invariably terminates processes forcefully - allowing requesting graceful termination on an opt-in basis is the subject of GitHub issue #13664.
在WindowsAPI层级,目标主window是否可见无所谓,因此即使 (GUI-subsystem) 处理通过设计 运行 不可见的 - as GoogleDriveFS.exe
appears to be - 也可以用 WM_CLOSE
作为目标消息。
虽然System.Diagnostics.Process.CloseMainWindow()
是旨在通过发送WM_CLOSE
消息到它的主要 window,不幸的是 没有发现 window 如果它碰巧是不可见的(隐藏) (从 .NET 6.0 开始仍然适用)
相比之下,taskkill.exe
实用程序没有 有此限制。
这两种方法的共同限制是无法针对 UWP/Microsoft Store 应用程序.
- 但是,此仅适用于“纯”UWP 应用程序(例如,设置、计算器),不适用于桌面应用程序打包为 UWP 应用程序(例如,Windows 终端、Microsoft Edge)。
- 原因是这两种方式都依赖于
EnumWindows
WinAPI方式,只支持桌面应用
- 但是,手动通过
FindWindowEx
找到UWP应用程序的主要window并向其发布WM_CLOSE
,是 可能。
我正在寻找一种优雅地 close/quit 在 GoogleDriveFS 进程下运行的 GoogleDrive 应用程序的方法。
get-process GoogleDriveFS
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
219 16 10796 5732 0.05 4392 1 GoogleDriveFS
333 22 11820 32364 0.17 8424 1 GoogleDriveFS
297 19 16528 34860 0.06 12036 1 GoogleDriveFS
245 17 10472 23992 0.03 14296 1 GoogleDriveFS
572 26 52256 82728 0.84 17788 1 GoogleDriveFS
518 21 28668 68208 0.44 18460 1 GoogleDriveFS
1024 59 47016 89396 27.95 19452 1 GoogleDriveFS
类似 Process.CloseMainWindow 的方法适合这个吗?还是有更好的方法来确保该应用不是 运行?
你可以这样做:
do {
$running = try { Get-Process -Name GoogleDriveFS -ErrorAction Stop } catch { Write-Host "Error: $($PSItem.Exception.Message) " }
$running | ForEach-Object {
$_.CloseMainWindow()
Write-Debug -Message "Closing ($_).pm "
}
}
until ($running -eq $null)
但是,这将提示用户确认关闭。
您也可以使用 close()
方法来避免提示用户或 kill()
立即释放所有资源。
CloseMainWindow() Closes a process that has a user interface by sending a close message to its main window.
Close() Frees all the resources that are associated with this component.
Kill() Immediately stops the associated process.
通过https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.process?view=net-6.0#methods
tl;dr
System.Diagnostics.Process.CloseMainWindow()
将 不 工作,原因在底部解释。
注:
- 如果目标进程不是从您自己的用户帐户启动的,您需要 运行 从 提升的 (运行作为管理员)会话。
你可以尝试以下实现优雅终止,但不能保证它会起作用:
# Asks all GoogleDriveFS processes to terminate, which they may or may not do.
# A status line is output to stdout for each targeted process,
# indicating whether the termination request was successfully *sent*.
# Note: ".exe" must be used, whereas it mustn't be
# with PowerShell's *-Process cmdlets.
taskkill.exe /im GoogleDriveFS.exe
如果没有,强制终止是您唯一的选择,最容易实现的是:
# !! Forcefully terminates all GoogleDriveFS, without cleanup.
Stop-Process -Force -Name GoogleDriveFS
注意:如下所述,Stop-Process
总是 强制终止。 -Force
开关的唯一功能是抑制在您尝试终止属于不同用户的进程时出现的潜在确认提示(仅适用于提升)。
这是一个 片段,它首先尝试正常终止,然后在指定的超时后退回到强制终止:
$processName = 'GoogleDriveFS'
$timeOutSecs = 2
# Get all existing processes of interest.
$processes = Get-Process -ErrorAction Ignore -Name $processName
if (-not $processes) {
Write-Verbose -Verbose "No $processName processes running."
} else {
# Ask the processes to terminate, which they may or may not do.
taskkill.exe /im "$processName.exe" *>$null
try {
# Wait for up to $timeOutSecs seconds for the processes to -
# potentially - terminate gracefully.
$processes | Wait-Process -ErrorAction Stop -Timeout $timeOutSecs
} catch {
Write-Warning "Forcefully terminating (remaining) $processName processes..."
# Note: This assumes that you don't care about any new
# processes that may have launched since Get-Process was called.
$processes | Stop-Process -Force
}
}
在 Windows 上,正常 终止基本上只是 GUI-subsystem 应用程序的一个选项,即具有主 window(无论可见与否)的进程,因此有一个 消息循环 ,可以将
WM_CLOSE
消息发布到其中。换句话说:你不能要求console Windows 上的应用程序正常终止(除非他们实现了一些 application-specific 自定义机制,其他进程可以通过该机制请求终止)。
对于受支持的应用程序,有重要注意事项:
无法保证终止,即使确实发生,也无法保证其时机:
- 目标进程可能处于无法处理
WM_CLOSE
消息的状态,比如当时恰好在显示模态对话框,或者恰好卡住了。 - 目标进程可能会悄悄地拒绝终止。
- 目标进程可能会提出一个模式对话框来确认终止的意图,特别是在试图关闭一个打开了未保存文档的 editor-like 应用程序时。
- 目标进程可能处于无法处理
因此,如果您需要确保终止,您必须监控进程以实际终止之后,可能会在适当的超时时间.
后强行终止它taskkill.exe
通过其/f
选项提供强制终止。- .NET 通过
System.Diagnostics.Process.Kill()
提供强制终止- 顺便说一句:从 PowerShell 7.2.x 开始,
Stop-Process
cmdlet invariably uses this method, i.e. invariably terminates processes forcefully - allowing requesting graceful termination on an opt-in basis is the subject of GitHub issue #13664.
- 顺便说一句:从 PowerShell 7.2.x 开始,
在WindowsAPI层级,目标主window是否可见无所谓,因此即使 (GUI-subsystem) 处理通过设计 运行 不可见的 - as
GoogleDriveFS.exe
appears to be - 也可以用WM_CLOSE
作为目标消息。虽然
System.Diagnostics.Process.CloseMainWindow()
是旨在通过发送WM_CLOSE
消息到它的主要 window,不幸的是 没有发现 window 如果它碰巧是不可见的(隐藏) (从 .NET 6.0 开始仍然适用)相比之下,
taskkill.exe
实用程序没有 有此限制。这两种方法的共同限制是无法针对 UWP/Microsoft Store 应用程序.
- 但是,此仅适用于“纯”UWP 应用程序(例如,设置、计算器),不适用于桌面应用程序打包为 UWP 应用程序(例如,Windows 终端、Microsoft Edge)。
- 原因是这两种方式都依赖于
EnumWindows
WinAPI方式,只支持桌面应用 - 但是,手动通过
FindWindowEx
找到UWP应用程序的主要window并向其发布WM_CLOSE
,是 可能。