Process

AutoHotKey

Process

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

Process, Cmd, PID-or-Name [, Param3]

参数

Cmd

下列单词的其中一个:

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

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

List: 尽管还不支持 List, 但 示例部分 中的例子演示了通过 DllCall 获取进程列表的方法.

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

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

Wait: 在 Param3 指定的秒数 (可以为小数) 中检查是否存在匹配的进程. 如果省略 Param3, 则此命令会无限期等待. 如果找到了匹配的进程, 则 ErrorLevel 被设置为它的进程 ID (PID). 如果命令超时了, 则 ErrorLevel 被置为 0.

WaitClose: 在 Param3 指定的秒数 (可以为小数) 中检查所有匹配的进程是否关闭. 如果省略 Param3, 则此命令会无限期等待. 如果所有的匹配进程都关闭了, 则 ErrorLevel 被置为 0. 如果命令超时了, 则 ErrorLevel 被设置为仍然存在的首个匹配进程的进程 ID (PID).

PID-or-Name

此参数可以为数字 (PID) 或下面描述的进程名称. 它还可以被留空来改变脚本自己的优先级.

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

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

Param3

请参阅上面的 Cmd 了解详情.

ErrorLevel

请参阅上面的 Cmd 了解详情.

备注

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

相关

Run, WinGet, WinClose, WinKill, WinWait, WinWaitClose, IfWinExist

示例

; 示例 #1:

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

 

; 示例 #2:

Process, wait, Notepad.exe, 5.5
NewPID = %ErrorLevel%  ; 由于 ErrorLevel 会经常发生改变, 所以要立即保存这个值.
if NewPID = 0
{
    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.

 

; 示例 #3: 一个改变活动窗口进程优先级的热键:

#z:: ; Win+Z hotkey
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

 

; 示例 #4: 使用 DllCall 获取正在运行的进程列表然后显示在 MsgBox.

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%

 

; 示例 #5: 使用 COM 获取正在运行的进程列表.

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

; Win32_Process: http://msdn.microsoft.com/en-us/library/aa394372.aspx