I am using ShellRun to overcome an issue with Run - Is there a ShellRunWait to overcome the same issue with RunWait?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
JoeWinograd
Posts: 2182
Joined: 10 Feb 2014, 20:00
Location: U.S. Central Time Zone

I am using ShellRun to overcome an issue with Run - Is there a ShellRunWait to overcome the same issue with RunWait?

Post by JoeWinograd » 22 Nov 2021, 17:10

I had been using Run and RunWait with no problems to launch EXE files, but then ran into an issue with some LNK files, discussed in this forum thread:
viewtopic.php?f=76&t=88473

The solution there is ShellRun (huge thanks to @lexikos), which solves the problem for Run, but I'm having the same issue with RunWait, and am wondering if there is a comparable ShellRunWait, or any way to leverage ShellRun into, effectively, a ShellRunWait. I checked the parameters at Shell.ShellExecute (lexikos put that link in the comments in his ShellRun script), and nothing jumped out as related to waiting for the target to exit or be closed (as RunWait does), although I may have missed it.

Thanks much, Joe

lexikos
Posts: 9560
Joined: 30 Sep 2013, 04:07
Contact:

Re: I am using ShellRun to overcome an issue with Run - Is there a ShellRunWait to overcome the same issue with RunWait?

Post by lexikos » 23 Nov 2021, 04:09

As far as I can tell, no.

I suppose you will have to work around it, such as by using ShellRun to launch a script which notifies you when it is done.

User avatar
JoeWinograd
Posts: 2182
Joined: 10 Feb 2014, 20:00
Location: U.S. Central Time Zone

Re: I am using ShellRun to overcome an issue with Run - Is there a ShellRunWait to overcome the same issue with RunWait?

Post by JoeWinograd » 23 Nov 2021, 05:11

OK, thanks for the comment. I'm using ShellRun to launch other standard Windows programs, such as Excel, IrfanView, VLC, Word, etc. (i.e., not my own scripts), so getting notified when they are done is not possible. Would it be possible to modify ShellRun to return the handle of the window that gets created?


User avatar
JoeWinograd
Posts: 2182
Joined: 10 Feb 2014, 20:00
Location: U.S. Central Time Zone

Re: I am using ShellRun to overcome an issue with Run - Is there a ShellRunWait to overcome the same issue with RunWait?

Post by JoeWinograd » 23 Nov 2021, 11:58

teadrinker wrote:
23 Nov 2021, 08:34
ShellExecuteEx, maybe?
Thanks for the link...I'll give it a read.

lexikos
Posts: 9560
Joined: 30 Sep 2013, 04:07
Contact:

Re: I am using ShellRun to overcome an issue with Run - Is there a ShellRunWait to overcome the same issue with RunWait?

Post by lexikos » 25 Nov 2021, 04:54

No, that's missing the point of ShellRun - to execute the program in the context of explorer.exe, not the script's own process. Run uses ShellExecuteEx internally in various situations where CreateProcess can't be used.

User avatar
JoeWinograd
Posts: 2182
Joined: 10 Feb 2014, 20:00
Location: U.S. Central Time Zone

Re: I am using ShellRun to overcome an issue with Run - Is there a ShellRunWait to overcome the same issue with RunWait?

Post by JoeWinograd » 25 Nov 2021, 15:15

lexikos wrote:
25 Nov 2021, 04:54
No, that's missing the point of ShellRun - to execute the program in the context of explorer.exe, not the script's own process. Run uses ShellExecuteEx internally in various situations where CreateProcess can't be used.
OK, thanks for the explanation.


User avatar
JoeWinograd
Posts: 2182
Joined: 10 Feb 2014, 20:00
Location: U.S. Central Time Zone

Re: I am using ShellRun to overcome an issue with Run - Is there a ShellRunWait to overcome the same issue with RunWait?

Post by JoeWinograd » 25 Nov 2021, 22:56

anaglypta wrote:
25 Nov 2021, 21:04
Maybe you could use explorer.exe ... but with RunWait
The good news is that execution of the target succeeds. The bad news is that it does not achieve what I want because the RunWait is satisifed when explorer.exe finishes, whereas I want the RunWait to be satisifed only after the target finishes (exits or is closed). But thanks for the idea...I appreciate it!

anaglypta
Posts: 17
Joined: 10 Nov 2020, 10:18

Re: I am using ShellRun to overcome an issue with Run - Is there a ShellRunWait to overcome the same issue with RunWait?

Post by anaglypta » 26 Nov 2021, 12:38

Maybe using child/parent processes could help.

You create process A, which creates process B.
You get the PID for process A by using Run or RunWait.
You get the PID for process B by checking for any processes that have parent process A.
You wait until process B is closed, by using Process Exist or WinExist.

In my example, AutoHotkey creates a Notepad instance.
AutoHotkey then lists any children processes that it has created, e.g. the Notepad instance.

Code: Select all

; list children processes for a PID
Run, notepad
WinWait, ahk_class Notepad

pid := DllCall("kernel32\GetCurrentProcessId", "UInt")
for proc in ComObjGet("winmgmts:").ExecQuery("Select * from Win32_Process where ParentProcessId = " pid)
	MsgBox, % proc.ProcessId "`n" proc.Name
return

User avatar
JoeWinograd
Posts: 2182
Joined: 10 Feb 2014, 20:00
Location: U.S. Central Time Zone

Re: I am using ShellRun to overcome an issue with Run - Is there a ShellRunWait to overcome the same issue with RunWait?

Post by JoeWinograd » 27 Nov 2021, 15:42

anaglypta wrote:Maybe using child/parent processes could help.
Interesting idea, but I see two issues off the top of my head: (1) If your posted code uses RunWait rather than Run, it will never work, because the launched program will be closed when the WinWait executes. (2) Even with using Run, it may sometimes not work, because the target of it can be any program, and suppose it is a very fast-running program, in which case it could be closed by the time the WinWait executes. Or did I misunderstand the concept? Regards, Joe

anaglypta
Posts: 17
Joined: 10 Nov 2020, 10:18

Re: I am using ShellRun to overcome an issue with Run - Is there a ShellRunWait to overcome the same issue with RunWait?

Post by anaglypta » 20 Dec 2021, 13:19

@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)
}

/*------------------------------------------------------------------------------
*/

User avatar
JoeWinograd
Posts: 2182
Joined: 10 Feb 2014, 20:00
Location: U.S. Central Time Zone

Re: I am using ShellRun to overcome an issue with Run - Is there a ShellRunWait to overcome the same issue with RunWait?

Post by JoeWinograd » 20 Dec 2021, 20:11

Hi @anaglypta,
I tested your script on numerous targets...EXE files...LNK files...and files associated with a program, such as DOCX and PDF files. All worked perfectly, except TXT files, which had the same issue that you described about Adobe, i.e., it reports the process as closed immediately after it opens the file (my default text editor is KEDIT). But your script is a very interesting approach. Thanks for your continued effort on this...I really appreciate it! Regards, Joe

Post Reply

Return to “Ask for Help (v1)”