tl;dr
System.Diagnostics.Process.CloseMainWindow()
will not work, for the reasons explained in the bottom section.
Note:
- If the target processes weren't started from your own user account, you'll need to run the following from an elevated (run as admin) session.
You can try the following to achieve graceful termination, but there's no guarantee it will work:
# 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
If it doesn't, forceful termination is your only option, which is most easily accomplished with:
# !! Forcefully terminates all GoogleDriveFS, without cleanup.
Stop-Process -Force -Name GoogleDriveFS
Note: As discussed below, Stop-Process
always terminates forcefully. The only function of the -Force
switch is to suppress a potential confirmation prompt that is presented when you attempt to terminate processes belonging to a different user (only works with elevation).
Here's a snippet that first tries graceful termination, then falls back to forceful termination after a specifiable timeout:
$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
}
}
On Windows, graceful termination is fundamentally only an option for GUI-subsystem applications, i.e. processes that have a main window (whether visible or not) and therefore a message loop to which the WM_CLOSE
message can be posted.
In other words: you cannot ask console applications on Windows to terminate gracefully (unless they implement some application-specific custom mechanism through which other processes can request termination).
For supported applications, there are important considerations:
Termination isn't guaranteed, and even if it does happen, its timing isn't guaranteed:
- The target process may be in a state where it cannot process the
WM_CLOSE
message, such as when it happens to be displaying a modal dialog at the time or happens to be stuck.
- The target process may quietly refuse to terminate.
- The target process may put up a modal dialog to confirm the intent to terminate, notably when trying to close an editor-like application that has an unsaved document open.
Therefore, if you need to ensure termination, you'll have to monitor the process for actual termination afterwards, and possibly terminate it forcefully after a suitable timeout period.
At the Windows API level, it doesn't matter if the targeted main window is visible or not, so that even (GUI-subsystem) processes that by design run invisibly - as GoogleDriveFS.exe
appears to be - can be targeted with a WM_CLOSE
message.
While System.Diagnostics.Process.CloseMainWindow()
is designed to request graceful termination of a given process by sending a WM_CLOSE
message to its main window, it unfortunately doesn't find that window if it happens to be invisible (hidden) (still applies as of .NET 6.0)
By contrast, the taskkill.exe
utility does not have this limitation.
A limitation that BOTH methods share is the inability to target processes that are UWP / Microsoft Store applications.
- However, this applies only to "pure" UWP applications (e.g, Settings, Calculator), and not to desktop applications packaged as UWP apps (e.g., Windows Terminal, Microsoft Edge).
- The reason is that both methods rely on the
EnumWindows
WinAPI method, which only supports desktop applications.
- However, manually finding a UWP application's main window via
FindWindowEx
and posting WM_CLOSE
to it, is possible.