2.0-beta.3 - Call the v1 library in v2

Post your working scripts, libraries and tools.
User avatar
thqby
Posts: 397
Joined: 16 Apr 2021, 11:18
Contact:

2.0-beta.3 - Call the v1 library in v2

Post by thqby » 15 Jan 2022, 12:51

Modify from lexikos' loadfile

Use autohotkey.exe or autohotkey.dll of v1 to load the library files, and returns an object which can be used as follows:

Code: Select all

; load v1 librarys
lib := import_v1lib("LibPath", "AHK.exe")
lib := import_v1lib(["Lib1Path", "Lib2Path"], "AHK.exe")
lib := import_v1lib("test(a){`n}", "AHK.dll")

; Call a function named 'Function' in the target library:
lib.Function(params)
lib.Function

; Retrieve a global variable:
value := lib["VarName"]

; Set a global variable:
lib["VarName"] := value
lib.VarName := value

; Create a class instance
value := lib["__AHKv1LibHelper"].__New("ClassName", params)
value := lib["__AHKv1LibHelper"].__New(lib["ClassName"].NestedClass, params)
All of the required functions are expected to be installed in a function library.

Code: Select all

/**
 * import ahk v1 library to v2. It can call v1 functions and classes, read and modify global variables.
 * 
 * - import v1 lib `v1 := import_v1lib("gdip_all.ahk", "ahkv1.exe")`
 * - create class instance `v1["__AHKv1LibHelper"].__New("classname", params)` or `v1["__AHKv1LibHelper"].__New(v1["classname"], params)`
 * - call functions `v1.funcname(params)`, *no param* `v1.funcname`
 * - set global variable `v1.varname := "str"` or `v1["varname"] := {}`
 * - retrieve global variable `MsgBox(v1["varname"])`
 * 
 * @param pathsorcode The paths of the include script files or ahk v1 code. `Array or String`
 * @param ahkv1runtime The path of the AutoHotkey v1 runtime (AutoHotkey.exe or AutoHotkey.dll).
 */
import_v1lib(pathsorcode, ahkv1runtime := "C:\Program Files\AutoHotkey\AutoHotkey.exe") {
	static IDispatch := Buffer(16), _ := NumPut("int64", 0x20400, "int64", 0x46000000000000c0, IDispatch)
	lresult := DllCall("oleacc\LresultFromObject", "ptr", IDispatch, "ptr", 0, "ptr", ObjPtr(client := { proxy: 0 }), "ptr")
	; free com marshal on fail
	autofree := { ptr: lresult, __Delete: (s) => DllCall("oleacc\ObjectFromLresult", "ptr", s, "ptr", IDispatch, "ptr", 0, "ptr*", ComValue(9, 0)) }
	if !FileExist(ahkv1runtime)
		throw Error("AutoHotkey v1 runtime isn't exist")
	if pathsorcode is Array {
		t := pathsorcode, pathsorcode := ""
		for p in t
			pathsorcode .= "`n#include " p
	}
	v1script := Format("
	(
		#Persistent
		#NoTrayIcon
		class __AHKv1LibHelper {
			__New(name, args*) {
				static _ := (VarSetCapacity(IDispatch, 16), NumPut(0x46000000000000c0, NumPut(0x20400, IDispatch, "int64"), "int64"), DllCall("oleacc\ObjectFromLresult", "ptr", {}, "ptr", &IDispatch, "ptr", 0, "ptr*", idisp := 0), ComObject(9, idisp).proxy := new __AHKv1LibHelper(), ObjRelease(idisp))
				return IsObject(name) ? new name(args*) : new %name%(args*)
			}
			__Call(name, args*) {
				return %name%(args*)
			}
			__Get(name) {
				global
				return val := %name%
			}
			__Set(name, val) {
				global
				return %name% := val
			}
			__Delete() {
				SetTimer ExitApp, -1
				return
				ExitApp:
					ExitApp
			}
		}
		{}
	)", lresult, FileExist(pathsorcode) ? "#include " pathsorcode : pathsorcode)
	if ahkv1runtime ~= "i)\.dll$" {
		if !DllCall("GetModuleHandle", "str", ahkv1runtime) && !DllCall("LoadLibrary", "str", ahkv1runtime)
			throw Error("load AutoHotkey.dll fail")
		if !hThread := DllCall(ahkv1runtime "\ahktextdll", "str", v1script, "str", "", "str", "", "cdecl ptr")
			throw Error("Failed to load script")
		while !client.proxy
			Sleep(10)
	} else {
		exec := ComObject("WScript.Shell").Exec('"' ahkv1runtime '" /ErrorStdOut *')
		exec.StdIn.Write(v1script), exec.StdIn.Close()
		while exec.Status = 0 && !client.proxy
			Sleep(10)
		if exec.Status != 0 {
			ex := Error("Failed to load script")
			if RegExMatch(err := exec.StdErr.ReadAll(), "s)(.*?) \((\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]
			throw ex
		}
	}
	autofree.DeleteProp("__Delete")
	return client.proxy
}

ZeroWidth
Posts: 1
Joined: 14 Apr 2023, 02:37

Re: 2.0-beta.3 - Call the v1 library in v2

Post by ZeroWidth » 14 Apr 2023, 02:46

Awesome! Thanks for sharing, btw, how can I pass a callback function and trigger the function on AHK v2 from AHK v1?

I am using your library to use Chrome.ahk (latest version from G33kDude, slightly modified) on AHK v2, as your modified Chrome.ahk library is not firing all of the events for some reason (maybe you could fix this)?

So I have this instance:

global PageInstance := ChromeInst.GetPage(1, "page", "Function")

And I want to know how to trigger that function from Chrome.ahk (AHK v1) on my AHK v2 script, Thanks!

User avatar
thqby
Posts: 397
Joined: 16 Apr 2021, 11:18
Contact:

Re: 2.0-beta.3 - Call the v1 library in v2

Post by thqby » 16 Apr 2023, 00:04

You may need to modify some of the v1 code, then pass the function as an argument to v1. you can call v2 functions like fn.Call(params) in v1.
ZeroWidth wrote:
14 Apr 2023, 02:46
I am using your library to use Chrome.ahk (latest version from G33kDude, slightly modified) on AHK v2, as your modified Chrome.ahk library is not firing all of the events for some reason (maybe you could fix this)?
Provide code that can reproduce the problem.

Post Reply

Return to “Scripts and Functions (v2)”