@JoeWinograd.
This script demos what I was trying to do.
Windows doesn't quite work how I thought it might.
I thought you could get AutoHotkey to run Explorer to open a process/file, giving you a chain of descendants: AutoHotkey\Explorer\MyExe.
Instead, you get Explorer\MyExe.
And to make things more complicated still, that Explorer process, is not the one triggered by AutoHotkey.
It does not correspond to the PID you get, when you use Run or RunWait with explorer.exe.
Anyway, what my script does: if the target is a path, the script uses Explorer to open it, otherwise the script falls back to Run. It then waits until the process closes.
I noticed one difference between this script, and just using RunWait, when using Adobe Reader.
If you try to open Adobe via this script, and Adobe is already open, it reports the process as closed immediately.
If you try to open Adobe via RunWait, and Adobe is already open, it will wait until Adobe closes.
In both cases, if Adobe was not already open, it will open Adobe, and wait until Adobe closes.
Perhaps this approach is good enough for you. Otherwise maybe my approach can be improved or replaced, or you might be best off always using 64-bit AHK with Run/RunWait on 64-bit PCs.
Code: Select all
; launch target using Run, or explorer.exe where possible, and wait for process to close
; target := "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Adobe Acrobat DC.lnk"
; target := "notepad.exe"
target := "C:\Windows\System32\notepad.exe"
pidsskip := {}
for proc in ComObjGet("winmgmts:").ExecQuery("Select * from Win32_Process")
{
pid := proc.ProcessID
pidsskip[pid] := 1
}
pidscheck := []
if FileExist(target)
{
RunWait, explorer "%target%"
Sleep, 1000
for proc in ComObjGet("winmgmts:").ExecQuery("Select * from Win32_Process")
{
pid := proc.ProcessID
if pidsskip.HasKey(pid)
continue
try
{
; pidancestor := ProcessGetAncestor(pid, 1)
pidancestor := proc.ParentProcessId
if (ProcessGetName(pidancestor) = "explorer.exe")
pidscheck.Push(pid)
}
}
}
else
{
Run, % target,,, pid
pidscheck.Push(pid)
}
; MsgBox, % pidscheck.Length()
Loop
{
count := pidscheck.Length()
if !count
break
while (count)
{
Process, Exist, % pidscheck[count]
pidtemp := ErrorLevel
if !pidtemp
pidscheck.RemoveAt(count)
count--
}
Sleep, 1000
}
MsgBox, process closed
return
/*------------------------------------------------------------------------------
*/
ProcessGetAncestor(pid, depth)
{
Loop % depth
{
pidparent := 0
for proc in ComObjGet("winmgmts:").ExecQuery("Select * from Win32_Process where ProcessId = " pid)
pidparent := proc.ParentProcessId
if !pidparent
throw Exception("Failed to find ancestor PID of depth " depth ".", -1)
pid := pidparent
}
return pid
}
ProcessGetParent(pid)
{
pidparent := 0
for proc in ComObjGet("winmgmts:").ExecQuery("Select * from Win32_Process where ProcessId = " pid)
pidparent := proc.ParentProcessId
if !pidparent
throw Exception("Failed to get ancestor PID.", -1)
return pidparent
}
ProcessGetName(pid)
{
for proc in ComObjGet("winmgmts:").ExecQuery("Select * from Win32_Process where ProcessId = " pid)
return proc.Name
throw Exception("Failed to get process name.", -1)
}
/*------------------------------------------------------------------------------
*/