Loads a script file as a child process and returns an object which can be used as follows:
Code: Select all
; Call a function named 'Function' in the target script:
Script.Function()
; Retrieve a global variable:
value := Script.G["VarName"]
; Set a global variable:
Script.G["VarName"] := value
Code: Select all
/*
LoadFile(Path [, EXE])
Loads a script file as a child process and returns an object
which can be used to call functions or get/set global vars.
Path:
The path of the script.
EXE:
The path of the AutoHotkey executable (defaults to A_AhkPath).
Version: 1.1
*/
#Requires AutoHotkey v1.1.35+
LoadFile(path, exe:="", exception_level:=-1) {
exe := """" (exe="" ? A_AhkPath : exe) """"
exec := ComObjCreate("WScript.Shell")
.Exec(exe " /ErrorStdOut /include """ A_LineFile """ """ path """")
exec.StdIn.Close()
err := exec.StdErr.ReadAll()
if SubStr(err, 1, 8) = "LRESULT=" {
hr := DllCall("oleacc\ObjectFromLresult", "ptr", SubStr(err, 9), "ptr", LoadFile.IID, "ptr", 0, "ptr*", pobj:=0)
if hr >= 0
return ComObj(9, pobj, 1)
err := Format("ObjectFromLresult returned failure (0x{:x})", hr & 0xffffffff)
}
ex := Exception("Failed to load file", exception_level)
if RegExMatch(err, "Os)(.*?) \((\d+)\) : ==> (.*?)(?:\s*Specifically: (.*?))?\R?$", m)
ex.Message .= "`n`nReason:`t" m[3] "`nLine text:`t" m[4] "`nFile:`t" m[1] "`nLine:`t" m[2]
else
ex.Message .= "`n`nReason:`t" err
throw ex
}
class LoadFile {
Init() {
static IID, _ := LoadFile.Init()
VarSetCapacity(IID, 16), this.IID := &IID
NumPut(0x46000000000000c0, NumPut(0x20400, IID, "int64"), "int64") ; IID_IDispatch
if InStr(DllCall("GetCommandLine", "str"), " /include """ A_LineFile """ ")
this.Serve()
}
Serve() {
stderr := FileOpen("**", "w")
try {
proxy := new this.Proxy
lResult := DllCall("oleacc\LresultFromObject", "ptr", this.IID, "ptr", 0, "ptr", &proxy, "ptr")
if lResult < 0
throw Exception(Format("LresultFromObject returned failure (0x{:x})", lResult))
stderr.Write("LRESULT=" lResult)
DllCall("CloseHandle", "ptr", stderr := stderr.__Handle) ; Flush buffer and end ReadAll().
}
catch ex {
stderr.Write(Format("{} ({}) : ==> {}`n Specifically: {}"
, ex.File, ex.Line, ex.Message, ex.Extra))
stderr.Close() ; Flush write buffer.
ExitApp
}
; Rather than sleeping in a loop, make the script persistent
; and then return so that the #included file is auto-executed.
Hotkey IfWinActive, LoadFile:%A_ScriptHwnd%
Hotkey vk07, #Persistent, Off
Hotkey IfWinActive
#Persistent:
}
class Proxy {
__call(name, args*) {
if (name != "G")
return %name%(args*)
}
G[name] { ; x.G[name] because x[name] via COM invokes __call.
get {
global
return ( %name% )
}
set {
global
return ( %name% := value )
}
}
__delete() {
ExitApp
}
}
}
Known issues: See ObjRegisterActive for some limitations which apply to all scripts using COM for IPC.
Version 1.0 of the script was mostly intended as an example for ObjRegisterActive, but might be useful in its own right. It can be used on AutoHotkey v1.1.17+.
Version 1.0
Script := LoadLib(LibName [, EXE])
Like LoadFile, but loads a script from a function library.
Code: Select all
LoadLib(name, exe:="") {
if (exe = "")
exe := A_AhkPath
libs := [A_ScriptDir "\Lib\", A_MyDocuments "\AutoHotkey\Lib\", exe "\..\Lib\"]
for i, lib in libs {
if FileExist(lib name ".ahk")
return LoadFile(lib name ".ahk", exe, -2)
}
}
Code: Select all
lib := LoadLib("CreateGUID")
MsgBox % lib.CreateGUID()
MsgBox % lib.G["A_WorkingDir"]