Process

对进程执行下列的其中一个操作: 检查进程是否存在; 改变进程的优先级; 关闭进程; 等待进程关闭.

Process, SubCommand , PIDOrName, Value

参数

SubCommand, Value
他们互相依赖, 其用法描述如下.
PIDOrName

此参数可以为下面描述的数字(PID) 或进程名称. 此参数可以为空或省略, 取决于所使用的子命令.

PID: 进程 ID, 唯一标识一个特定进程的数字(只有在此进程的生存期这个数字才有意义). 新运行的进程的 PID 可以通过 Run 命令获取. 同样的, 窗口的 PID 可以通过 WinGet 获取. Process 命令自身也可以获取 PID.

Name: 进程的名称, 通常和它的可执行文件名相同(不带路径), 例如 notepad.exe 或 winword.exe. 一个名称可能匹配多个正在运行的进程, 但只会对第一个进程进行操作. 这个名称不区分大小写.

子命令

对于 SubCommand, 指定以下命令之一:

Exist

检查指定的进程是否存在.

Process, Exist , PIDOrName

如果存在一个匹配的进程则设置 ErrorLevel 为此进程 ID(PID), 否则为 0. 如果 PIDOrName 参数为空或省略, 则获取脚本自身的 PID. 检索脚本的另一种单行的方法是 PID := DllCall("GetCurrentProcessId").

Close

强制关闭第一个匹配的进程.

Process, Close, PIDOrName

如果成功终止一个匹配的进程, 则设置 ErrorLevel 为此进程原来的进程 ID(PID). 否则(例如, 没有找到匹配的进程或在终止匹配进程的过程中出现了问题) 它被设置为 0. 因为进程会被突然终止(可能在一个关键点中断它的工作或导致窗口中未保存数据的丢失), 因此只有当无法使用 WinClose 作用于它的窗口来关闭相应进程时才使用这个子命令.

若要强制关闭 所有 匹配的进程, 请参阅示例 #6.

List

虽然这个子命令还没有得到支持, 示例 #4 演示了如何通过 DllCall() 检索进程列表.

Priority

更改第一个匹配进程的优先级.

Process, Priority, PIDOrName, Level

更改首个匹配进程的优先级(如同 Windows 任务管理器中看到的那样)为 Level, 并设置 ErrorLevel 为它的进程 ID(PID). 如果 PIDOrName 参数为空, 则改变脚本自己的优先级. 如果没有找到匹配的进程或在改变匹配进程的优先级过程中出现了问题, 则 ErrorLevel 被设置为 0.

Level 应该为下列字母或单词的其中一个: L(或 Low)(低), B(或 BelowNormal)(低于标准), N(或 Normal)(普通), A(或 AboveNormal)(高于标准), H(或 High)(高), R(或 Realtime)(实时). 注: 任何不是设计为 Realtime 优先级运行的进程如果设置为这个优先级可能会降低系统的稳定性.

Wait

等待指定的进程存在.

Process, Wait, PIDOrName , Timeout

Timeout 指定秒数(可以为小数) 以便在超时前等待. 如果 Timeout 为空或省略, 子命令将无限期地等待. 如果发现匹配进程, ErrorLevel 设置为其进程 ID(PID). 如果子命令超时, ErrorLevel 设置为 0.

每隔 100 毫秒检查目标进程一次; 当条件满足时, 子命令停止等待. 换句话说, 它不会等待超时过期, 而是像上面描述的那样立即设置 ErrorLevel, 然后继续执行脚本. 此外, 当子命令处于等待状态时, 可以通过热键, 自定义菜单计时器启动新线程.

WaitClose

等待 所有 匹配进程关闭.

Process, WaitClose, PIDOrName , Timeout

Timeout 指定秒数(可以为小数) 以便在超时前等待. 如果 Timeout 为空或省略, 子命令将无限期地等待. 如果所有的匹配进程都关闭了, ErrorLevel 设置为 0. 如果子命令超时, ErrorLevel 设置为仍然存在的首个匹配进程的 ID(PID).

每隔 100 毫秒检查目标进程一次; 当条件满足时, 子命令停止等待. 换句话说, 它不会等待超时过期, 而是像上面描述的那样立即设置 ErrorLevel, 然后继续执行脚本. 此外, 当子命令处于等待状态时, 可以通过热键, 自定义菜单计时器启动新线程.

ErrorLevel

如果子命令失败或超时, ErrorLevel 设置为 0. 否则, 它将被设置为进程 ID(PID). 有关详细信息, 请参阅上面的子命令.

Run, WinGet, WinClose, WinKill, WinWait, WinWaitClose, WinExist()

示例

启动记事本, 将其优先级设置为 High 并显示当前的 PID.

Run notepad.exe,,, NewPID
Process, Priority, %NewPID%, High
MsgBox The newly launched Notepad's PID is %NewPID%.

等待记事本进程出现, 如果在 5.5 秒内出现, 则其优先级设置为 Low, 而脚本自己的优先级设置为 High. 之后, 会尝试在 5 秒内关闭进程.

Process, Wait, notepad.exe, 5.5
NewPID := ErrorLevel  ; 由于 ErrorLevel 会经常发生改变, 所以要立即保存这个值.
if not NewPID
{
    MsgBox The specified process did not appear within 5.5 seconds.
    return
}
; 否则:
MsgBox A matching process has appeared (Process ID is %NewPID%).
Process, Priority, %NewPID%, Low
Process, Priority,, High  ; 把脚本自己设置为高优先级.
WinClose Untitled - Notepad
Process, WaitClose, %NewPID%, 5
if ErrorLevel ; PID 仍然存在.
    MsgBox The process did not close within 5 seconds.

按下热键改变活动窗口进程优先级.

#z:: ; Win+Z 热键
WinGet, active_pid, PID, A
WinGetTitle, active_title, A
Gui, 5:Add, Text,, Press ESCAPE to cancel, or double-click a new`npriority level for the following window:`n%active_title%
Gui, 5:Add, ListBox, vMyListBox gMyListBox r5, Normal|High|Low|BelowNormal|AboveNormal
Gui, 5:Add, Button, default, OK
Gui, 5:Show,, Set Priority
return

5GuiEscape:
5GuiClose:
Gui, Destroy
return

MyListBox:
if (A_GuiEvent != "DoubleClick")
    return
; 否则直接进入下一个标签:
5ButtonOK:
GuiControlGet, MyListBox
Gui, Destroy
Process, Priority, %active_pid%, %MyListBox%
if ErrorLevel
    MsgBox Success: Its priority was changed to "%MyListBox%".
else
    MsgBox Error: Its priority could not be changed to "%MyListBox%".
return
显示一个通过 DllCall() 获取的正在运行的进程列表.

d := "  |  "  ; 字符串分隔符
s := 4096  ; 缓存和数组的大小(4 KB)

Process, Exist  ; 设置 ErrorLevel 为这个正在运行脚本的 PID.
; 使用 PROCESS_QUERY_INFORMATION(0x0400) 获取此脚本的句柄:
h := DllCall("OpenProcess", "UInt", 0x0400, "Int", false, "UInt", ErrorLevel, "Ptr")
; 打开此进程的可调整的访问令牌(TOKEN_ADJUST_PRIVILEGES = 32):
DllCall("Advapi32.dll\OpenProcessToken", "Ptr", h, "UInt", 32, "PtrP", t)
VarSetCapacity(ti, 16, 0)  ; 特权结构
NumPut(1, ti, 0, "UInt")  ; 特权数组中的一个条目...
; 获取调试特权的本地唯一标识符:
DllCall("Advapi32.dll\LookupPrivilegeValue", "Ptr", 0, "Str", "SeDebugPrivilege", "Int64P", luid)
NumPut(luid, ti, 4, "Int64")
NumPut(2, ti, 12, "UInt")  ; 启用这个特权: SE_PRIVILEGE_ENABLED = 2
; 使用新的访问令牌更新此进程的特权:
r := DllCall("Advapi32.dll\AdjustTokenPrivileges", "Ptr", t, "Int", false, "Ptr", &ti, "UInt", 0, "Ptr", 0, "Ptr", 0)
DllCall("CloseHandle", "Ptr", t)  ; 关闭此访问令牌句柄以节约内存.
DllCall("CloseHandle", "Ptr", h)  ; 关闭此进程句柄以节约内存.

hModule := DllCall("LoadLibrary", "Str", "Psapi.dll")  ; 通过预加载来提升性能.
s := VarSetCapacity(a, s)  ; 接收进程列表标识符的数组:
c := 0  ; 用于进程标识符的计数器
DllCall("Psapi.dll\EnumProcesses", "Ptr", &a, "UInt", s, "UIntP", r)
Loop, % r // 4  ; 把数组解析为 DWORD(32 位) 的标识符:
{
    id := NumGet(a, A_Index * 4, "UInt")
   ; 打开进程: PROCESS_VM_READ(0x0010) | PROCESS_QUERY_INFORMATION(0x0400)
    h := DllCall("OpenProcess", "UInt", 0x0010 | 0x0400, "Int", false, "UInt", id, "Ptr")
    if !h
        continue
    VarSetCapacity(n, s, 0)  ; 接收模块基础名称的缓存:
    e := DllCall("Psapi.dll\GetModuleBaseName", "Ptr", h, "Ptr", 0, "Str", n, "UInt", A_IsUnicode ? s//2 : s)
    if !e    ;  用于 64 位进程在 32 位模式时的回退方法:
        if e := DllCall("Psapi.dll\GetProcessImageFileName", "Ptr", h, "Str", n, "UInt", A_IsUnicode ? s//2 : s)
            SplitPath n, n
    DllCall("CloseHandle", "Ptr", h)  ; 关闭进程句柄以节约内存
    if (n && e)  ; 如果映像不是空的, 则添加到列表:
        l .= n . d, c++
}
DllCall("FreeLibrary", "Ptr", hModule)  ; 卸载库来释放内存.
;Sort, l, C  ; 取消注释这行来按字母顺序对列表进行排序.
MsgBox, 0, %c% Processes, %l%

显示通过 COM 和 Microsoft Docs 获取的正在运行的进程列表.

Gui, Add, ListView, x2 y0 w400 h500, Process Name|Command Line
for proc in ComObjGet("winmgmts:").ExecQuery("Select * from Win32_Process")
    LV_Add("", proc.Name, proc.CommandLine)
Gui, Show,, Process List

强制关闭 所有 匹配的进程.

ProcessCloseAll(PIDOrName)
{
    Loop {
        Process, Close, % PIDOrName
        Process, Exist, % PIDOrName  ; 在一些情况下提高稳定性.
    } Until not ErrorLevel
}

; 示例:
Loop 3
    Run, notepad.exe
Sleep 3000
ProcessCloseAll("notepad.exe")