自动处理重复运行程序时弹出”Could not close the previous instance of this script. Keep waiting“窗口

#NoEnv
#SingleInstance Force
SetBatchLines, -1
Process, Priority,, High
SetWorkingDir %A_ScriptDir%

;=======================================活动窗口监控===============================================
RunAsAdmin()
Gui +LastFound
DllCall( "RegisterShellHookWindow", UInt,WinExist() )
OnMessage( DllCall( "RegisterWindowMessage", Str,"SHELLHOOK" ), "ShellIMEMessage")
;================================重复进程检查与处理================================================
If A_IsCompiled {
	thisPID := DllCall("GetCurrentProcessId")
	if objCount(Processlist:=GetProcessNameList(A_ScriptName))>1
	{
		loop,% objCount(Processlist)
		{
			if (thisPID<>Processlist[A_Index,2]){
				process,Close,% Processlist[A_Index,2]
			}
		}
	}
}Else{
	DetectHiddenWindows, On
	thisPID := DllCall("GetCurrentProcessId")
	WinGet, List, List,%A_ScriptName%
	Loop % List
	{
		WinGet, PID, PID, % "ahk_id " List%A_Index%
		;;WinGet, ProcessPath, ProcessPath,% "ahk_id " List%A_Index%
		WinGetTitle, WinTitle , % "ahk_id " List%A_Index%
		If (PID != thisPID&&WinTitle=A_ScriptName){
			process,Close,% PID
		}
	}
	DetectHiddenWindows, Off
}
;;刷新任务栏残留的图标残影
TrayRefresh()

Return
;;================================监控消息回调ShellIMEMessage监控窗口变化================================

ShellIMEMessage( wParam,lParam ) {
	/*    wParam参数:
		;1 顶级窗体被创建 	;2 顶级窗体即将被关闭 	;54 退出全屏	;32772 窗口切换
		;3 SHELL 的主窗体将被激活 	;4 顶级窗体被激活 	;&H8000& 掩码 	;53 全屏
		;5 顶级窗体被最大化或最小化 	;6 Windows 任务栏被刷新,也可以理解成标题变更
		;7 任务列表的内容被选中 	;8 中英文切换或输入法切换 	;13 wParam=被替换的顶级窗口的hWnd 
		;9 显示系统菜单 	;10 顶级窗体被强制关闭 	;14 wParam=替换顶级窗口的窗口hWnd
		;12 没有被程序处理的APPCOMMAND。见WM_APPCOMMAND
	*/
	WinWait , %A_ScriptName%, , 1
	;消除重复运行程序时弹出”Could not close the previous instance of this script. Keep waiting“窗口
	ControlGetText, WinStaticText , Static1,ahk_class #32770
	if WinExist(A_ScriptName)&&InStr(WinStaticText,"keep Waiting"){   ;ahk_class #32770
		DllCall("DestroyWindow", "ptr", WinExist(A_ScriptName))
		Reload
	}
}

;;根据进程文件名获取进程信息列表
GetProcessNameList(ProcessName:=""){
	list:="",tarr:=[]
	s := 10240  ; 缓存和数组的大小(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)  ; 接收进程列表标识符的数组:

	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){  ; 如果映像不是空的, 则添加到列表:
			If (ProcessName&&ProcessName=n)
				tarr.push([n,id])
			else
				list.=n "/" id "|"
		}
	}
	DllCall("FreeLibrary", "Ptr", hModule)  ; 卸载库来释放内存.

	return !ProcessName?list:tarr
}

TrayRefresh() {
/*		Remove any dead icon from the tray menu
 *		Should work both for W7 & W10
 */
	WM_MOUSEMOVE := 0x200
	detectHiddenWin := A_DetectHiddenWindows
	DetectHiddenWindows, On
	allTitles := ["ahk_class Shell_TrayWnd"
			, "ahk_class NotifyIconOverflowWindow"]
	allControls := ["ToolbarWindow321"
				,"ToolbarWindow322"
				,"ToolbarWindow323"
				,"ToolbarWindow324"]
	allIconSizes := [24,32]

	for id, title in allTitles {
		for id, controlName in allControls
		{
			for id, iconSize in allIconSizes
			{
				ControlGetPos, xTray,yTray,wdTray,htTray,% controlName,% title
				y := htTray - 10
				While (y > 0)
				{
					x := wdTray - iconSize/2
					While (x > 0)
					{
						point := (y << 16) + x
						PostMessage,% WM_MOUSEMOVE, 0,% point,% controlName,% title
						x -= iconSize/2
					}
					y -= iconSize/2
				}
			}
		}
	}
	DetectHiddenWindows, %detectHiddenWin%
}

RunAsAdmin(){
	full_command_line := DllCall("GetCommandLine", "str")
	if not (A_IsAdmin or RegExMatch(full_command_line, " /restart(?!\S)")) {
		try {
			if A_IsCompiled
				Run *RunAs "%A_ScriptFullPath%" /restart
			else
				Run *RunAs "%A_AhkPath%" /restart "%A_ScriptFullPath%"
		}Catch e{
			MsgBox, 262160,Error,% e.Extra?e.Extra:"以管理员身份运行失败!",15
			ExitApp
		}
	}
}

给TA捐赠
共{{data.count}}人
人已捐赠
其他

AHKv1文件或目录监控〔搬运〕

2021-12-10 12:55:28

其他案例

AHKv1带滚动条的窗口示例

2021-12-10 21:35:59

2 条回复 A文章作者 M管理员
  1. AHK中文社区
    1河许人给您打赏了¥2
  2. AHK中文社区

    辛苦

个人中心
购物车
优惠劵
有新私信 私信列表
搜索