Thank you Lexikos!
To get this stuff to stick in my brain I tried summarizing it, based on tests in v2. Let me know if anything is faulty.
What happens when Run has a target parameter that is a filename without any path specified?
We can explain using the case of two AutoHotkey scripts, where one uses Run to run the other.
Let's use the name "target" for the script that we call and the name "caller" for the calling script (that contains the Run line).
What happens depends on two things: if target is compiled and if caller is compiled.
What happens depends on two things: whether target is compiled and and where the calling process is located.
We can imagine four simple cases (set other possible cases aside):
- caller.ahk doing
Run "target.ahk"
- caller.ahk doing
Run "target.exe"
- caller.exe doing
Run "target.ahk"
- caller.exe doing
Run "target.exe"
Caller uses
CreateProcess if target is .exe (compiled script or other
executable file)
Caller uses
ShellExecuteEx if target is .ahk (non-executable file)
CreateProcess
Where the calling process is located matters for the order CreateProcess searches for the target file.
If caller is uncompiled (caller.ahk) then the process actually running the script is A_AhkPath. For example C:\Program Files\AutoHotkey\AutoHotkey.exe .
If caller is compiled (caller.exe) then it is itself the process running the script, from A_ScriptDir. For example C:\MyScripts\caller.exe .
The
CreateProcess documentation specifies the search order "[if] the file name does not contain a directory path":
1. The directory from which the application loaded.
2. The current directory for the parent process. ...
Which means
- in caller.exe 1 is A_ScriptDir
- in caller.ahk 1 is the folder that A_AhkPath is in.
- in an .exe or .ahk caller 2 is WorkingDir (Run's 2nd parameter) if set and otherwise caller's A_WorkingDir which defaults to A_ScriptDir
ShellExecuteEx
The documentation for the related
SHELLEXECUTEINFOA structure says
lpFile ... name of the file ... If the path is not included ... current directory is assumed. ...
lpDirectory ... Optional ... name of the working directory. If ... NULL ... current directory is used as the working directory.
Which means
- in an .exe or .ahk caller the target is searched for in WorkingDir (Run's 2nd parameter) if set or otherwise in caller's A_WorkingDir which defaults to A_ScriptDir. There is no other search step.
We can now explain what happens in Guillaume's first post
When the caller is .exe Run (CreateProcess) first searches in A_ScriptDir and finds ahkdir.exe there and runs it. Both times.
When the caller is .ahk Run (CreateProcess) first searches in the folder that contains A_AhkPath (for example C:\Program Files\AutoHotkey ) and doesn't find ahkdir.exe there so falls back to searching in A_WorkingDir, which is A_ScriptDir in the first Run and A_Temp in the second Run.
Some relevant AutoHotkey source locations
https://github.com/AutoHotkey/AutoHotkey/blob/v2.0/source/lib/process.cpp#L172
https://github.com/AutoHotkey/AutoHotkey/blob/v2.0/source/script.cpp#L12258
https://github.com/AutoHotkey/AutoHotkey/blob/v2.0/source/script.cpp#L12420
https://github.com/AutoHotkey/AutoHotkey/blob/v2.0/source/script.cpp#L12538
(edited based on lexikos comment below)