[Lib] ahkBridge() - 进程之桥

许多实用脚本和封装函数, 可以让您编写脚本更加便捷高效

Moderators: tmplinshi, arcticir

arcticir
Posts: 694
Joined: 17 Nov 2013, 11:32

[Lib] ahkBridge() - 进程之桥

28 Nov 2014, 08:21

AHK进程之桥
进程间交互操作:传递数据及相互操作。

刚重写一遍,明明以前觉得写的很好,现在再看简直渣透了。

特点:
1,模仿AHKDLL的交互方式,某些程度上可以与AHKDLL混用。补充DLL单进程的不足。

这是H版帮助里的示例:

Code: Select all

AhkThread := AhkDllThread("AutoHotkey.dll")
AhkThread.ahktextdll() 
AhkThread.addScript("Sub:`nMsgbox Sub`nReturn",0) ; 追加但不执行.
AhkThread.ahkLabel("Sub")
AhkThread.ahkassign("a","test") ;写入数据到变量

使用 ahkBridge() 就可以直接当作DLL操作:

Code: Select all

AhkThread := ahkBridge()
AhkThread.ahktextdll() 
AhkThread.addScript("Sub:`nMsgbox Sub`nReturn",0) ; 追加但不执行.
AhkThread.ahkLabel("Sub")
AhkThread.ahkassign("a","test") ;写入数据到变量
2,可以传递对象,这借助了 H的 ObjDump()




===============================

示例,两个不同进程的脚本:


A脚本 :

Code: Select all

ahkBridge("A",1) ;将自己写入交互标志,这样其他脚本就可以对它操作
B:=ahkBridge("B")  ;读取B,前提是B已经加载并写入标志
B.ahkAssign(n,f) ;写入变量,1,目标,2,写入的数据。
B.ahkGetvar(n) ;读取变量。结果传递的是对象,如:B.ahkGetvar(["n","a","b"}) 将返回包含所有变量的对象。
B.ahkFunction(n,f*)  ;调用函数返回结果,1,函数名,2,可变参数。默认等待最长5秒。如果想自定义等待时间:B.ahkFunction(n,{Time:100000,Params:[a,b,c,d]}) 
B.ahkPostFunction(n,f*)  ;调用函数不返回结果
;子标签的调用方法就多了些
B.ahkLabel("测试") ;不等待
B.ahkLabel("测试",1) ;等待最多5秒
B.ahkLabel("测试",1110000) ;片定义等待时间
B.ahkLabel("测试",,100) ;定时器运行
B.ahkReload()		; 重启
B.Edit()			; 编辑脚本
B.ahkPause()		; 暂停
B.suspend()		; 挂起
B.ahkTerminate()		; 退出
B.ListLines()		; 显示最近运行的行
B.ListVars()		; 显示变量
B.Hotkey()		; 显示热键
B.Window()		; 显示脚本信息
B.Script()		; 显示脚本信息
B.ahkReady()		;检查是否运行
; 以及其他一些与DLL相同的函数就不写了。
然后写个类似的B脚本:

Code: Select all

ahkBridge("B",1)
;.....

Code: Select all

class Bridge {

	__New(s){
		if s
			if (s+1)
				this.id:=s
			else
			{
				u := A_TitleMatchMode, h:=A_DetectHiddenWindows
				DetectHiddenWindows,On
				SetTitleMatchMode 2
				loop 5
				{
					if this.id:=WinExist("ahkBridge_" s)
						break
					Sleep, 30
				}
				DetectHiddenWindows % h
				SetTitleMatchMode % u
				if !this.id
					Return
				this.Name:=s
			}
	}

;==========================			===============================

;==========================			===============================

	ahkAssign(n,f){
		Return Bridge_send(this.id, {Name:n,Command:"Assign",Params:f})
	}

	ahkGetvar(n){
		Return Bridge_send(this.id, {Results:1,Name:n,Command:"Getvar"})
		}

	ahkFunction(n,f*){
		h:={Results:1,Name:n,Command:"Function"}
			,f.Time ? (h.Time :=f.Time,h.Params:=f.Params):h.Params :=f
		Return Bridge_send(this.id, h)
	}

	ahkPostFunction(n,f*){
		Return Bridge_send(this.id, {Time:0,Name:n,Command:"Function",Params:f})

	}

	ahkLabel(n,s:=0,f:=""){  ;调用子标签。s 调用方式。省略,立即返回;1,等待最长5秒。0或其他的非空值,无限等待。 f 定时器
		Return Bridge_send(this.id, {Time:f?0:s=1?5000:s,Name:n,Command:"Label",Params:f})
		}


;==========================			===============================

;==========================			===============================

	ahkReload(){		; 重启
		Return Bridge_Post(0x111 ,this.id,65400)
	}

	Edit(){			; 编辑脚本
		Bridge_Post(0x111 ,this.id,65401)
	}

	ahkPause(){		; 暂停
		Return Bridge_Post(0x111 ,this.id,65403)
	}

	suspend(){		; 挂起
		Return Bridge_Post(0x111,this.id,65404)
	}

	ahkTerminate(){		; 退出
		Return Bridge_Post(0x111,this.id,65405)
	}

	ListLines(){		; 显示最近运行的行
		Bridge_Post(0x111,this.id,65406)
	}

	ListVars(){		; 显示变量
		Bridge_Post(0x111,this.id,65407)
	}

	Hotkey(){		; 显示热键
		Bridge_Post(0x111,this.id,65408)
	}

	Window(){		; 显示脚本信息
		Bridge_Post(0x111,this.id,65409)
	}

	Script(){		; 显示脚本信息
		Bridge_Post(0x111,this.id,65410)
	}

	ahkReady(){		;检查是否运行
		Return (Bridge_Post(0x111,this.id) = 0)
	}


;==========================			===============================

;==========================			===============================

	ahkdll(n, b:="", r:=""){   ; 加载脚本
		FileRead, n, % n
		If (ErrorLevel = 0) and n
			Return this.ahktextdll(n,b,r)
		}

	ahktextdll(n:="#Persistent", b:="", r:=""){  ;加载代码
		if this.id
			this.ahkTerminate()
		h:=A_DetectHiddenWindows
		DetectHiddenWindows,On
		WinWait % PID:= "ahk_pid " Bridge_BinRun("`n#NoTrayIcon`nSetBatchLines -1`n" (r ? "A_ahkneme:=""" r """`nahkBridge(""" r """,1)`n" : "") n , b, r), ,4
	 	this.id:=WinExist("ahk_class AutoHotkey ahk_pid " PID)
		DetectHiddenWindows % h		
		Return this.id
		}

	; 以下函数需要H版
	ahkFile(n, f:=1){
		Return Bridge_send(this.id, {Results:1,Name:n,Command:"File",Params:f})
	}

	ahkScript(n, f:=1){
		Return Bridge_send(this.id, {Results:1,Name:n,Command:"Script",Params:f})
	}

	ahkExec(n){
		Return Bridge_send(this.id, {Results:1,Name:n,Command:"Exec"})
	}

	ahkExecuteLine(n, f:=0, b:=0){
		Return Bridge_send(this.id, {Results:1,Name:n,Command:"ExecuteLine",mode:f,wait:b})
	}

}

;==========================			===============================

;==========================			===============================

class BridgeHandle {

	Function(f){
		if IsFunc(n:=f.Name)
			Return %n%(f.Params*)
	}

	Label(f){
		Gosub(f.Name,f.Params?f.Params:(f.Time=0)?-1:"")
	}

	var(f){
		Bridge_Drawer["_" f.id]:=f.Return
	}

	Assign(f){
		global
		n:=f.Name
		Try
			%n%:=f.Params
	}

	Getvar(f){
		global
		Try
		if IsObject(b:=f.Name)
		{
			s:=[]
			for i,n in b
				s[n]:=%n%
		}
		else
		{
			s:=%b%
		}
		Return s
	}

	File(f){
		Return   Return h_Self.addFile(f.Name,f.Params)
	}

	Script(f){
		Return h_Self.addScript(f.Name,f.Params)
	}

	ahkExec(f){
		Return h_Self.ahkExec(f.Name)
	}

	ExecuteLine(f){
		Return 	h_Self.ahkExecuteLine(f.Name,f.mode,f.wait)
	}

}


;==========================			===============================

Bridge_Post(s, a ,e:=0 ,c:=0){
	h := A_DetectHiddenWindows
	DetectHiddenWindows on
	PostMessage, %s%, %e%, %c% ,,ahk_id %a%
	DetectHiddenWindows %h%
	Return ErrorLevel
	}


Bridge_BinRun(n,c:="",m:=""){
	static p:=(h_scriptdir ? h_scriptdir : A_ScriptDira), a:=A_IsCompiled ? (FileExist(p "\AutoHotkey.exe") ? p "\AutoHotkey.exe" : A_ScriptFullPath) : A_AhkPath, e := A_IsCompiled ? "/E " : 
		Return	BinRun(a,e "`n" n,c,m)
}


ahkBridge(s:="",r:=""){
	if r
	{
		Critical
		static h:=Gosub("Bridge_Ready")
		h:=A_DetectHiddenWindows
		DetectHiddenWindows,On
		WinGetTitle, T, ahk_id %A_ScriptHwnd%
		WinSetTitle, ahk_id %A_ScriptHwnd%,,%  s:=(instr(T, "ahkBridge_") ? T "|" : "") "ahkBridge_" (s?s:A_ScriptName)
		DetectHiddenWindows % h
	}
	else
	{
		Return new Bridge(s)
	}
}

Return

Bridge_Ready:
	global Bridge_mark, Bridge_Drawer ,Bridge_Parked,h_Self
	if !Bridge_Drawer
		h_Self  ? "" : h_Self:=A_IsDll ? AhkSelf() : AhkExported(),Bridge_mark:=0, Bridge_Drawer:=[], Bridge_Parked:=[]
			,onmessage(0x4a, "Bridge_Receive",50), onmessage(0x80e, "Bridge_Receive",50)
Return

ahkBridge_List(){
	u := A_TitleMatchMode, h:=A_DetectHiddenWindows
	DetectHiddenWindows,On
	SetTitleMatchMode 2
	WinGet s,List,ahkBridge_
	SetTitleMatchMode % u
	f:=[]
	loop % s
	{
		WinGetTitle, r, % "ahk_id " b:=s%A_Index%
		f[b]:=StrReplace(r,"ahkBridge_")
	}
	DetectHiddenWindows % h
	Return f
}

;==========================			===============================

;==========================			===============================

Bridge_send(i, f){
	static n:=1
	w:=A_DetectHiddenWindows,f.Tick:=t:=A_TickCount,f.Hwnd:=A_ScriptHwnd
		,VarSetCapacity(s, 3*A_PtrSize, 0),f.id:=n++,cb:= ObjDump(f,dw)
		,NumPut(&dw, &s, 2*A_PtrSize,"PTR"),NumPut(cb, &s, 1*A_PtrSize,"PTR")
	DetectHiddenWindows on
	if (f.Time=0)
		PostMessage, 0x80e,0, &s,,ahk_id %i%
	else
		SendMessage, 0x4a,0, &s,,ahk_id %i%,,,,% f.Time?f.Time:5000
	DetectHiddenWindows %w%
	if f.Results and (ErrorLevel!="FAIL")
		Return Bridge_Drawer.remove("_" f.id)
}

Bridge_receive(w,l){
	f := ObjLoad(NumGet(l+A_PtrSize*2,"PTR"),NumGet(l + A_PtrSize,"PTR"))
	if IsFunc(BridgeHandle[f.Command])
	{
		r:=BridgeHandle[f.Command](f)
		if f.Results and ((A_TickCount - f.Tick) < ((f.Time?f.Time:5000)-15))
			Bridge_send(f.Hwnd,{Return:r, id:f.id, Command:"var"})
	}
}

= = 话说调用了相当多的外部函数呢,我想都贴上来,但又觉得很麻烦。。。反正用的人应该没有。。。
arcticir
Posts: 694
Joined: 17 Nov 2013, 11:32

Re: [Lib] ahkBridge() - 进程之桥

30 Nov 2014, 02:51

修复一个小错误。另外一个因为AHKBUG暂时未解决

Code: Select all

class Bridge {

	__New(s){
		if s
			if (s+1)
				this.id:=s
			else
			{
				u := A_TitleMatchMode, h:=A_DetectHiddenWindows
				DetectHiddenWindows,On
				SetTitleMatchMode 2
				loop 5
				{
					if this.id:=WinExist("ahkBridge_" s)
						break
					Sleep, 30
				}
				DetectHiddenWindows % h
				SetTitleMatchMode % u
				if !this.id
					Return
				this.Name:=s
			}
	}

;==========================			===============================

;==========================			===============================

	ahkAssign(n,f){
		Return Bridge_send(this.id, {Name:n,Command:"Assign",Params:f})
	}

	ahkGetvar(n){
		Return Bridge_send(this.id, {Results:1,Name:n,Command:"Getvar"})
		}

	ahkFunction(n,f*){
		h:={Results:1,Name:n,Command:"Function"}
			,f.1.Time ? (h.Time :=f.1.Time,h.Params:=f.1.Params):h.Params :=f
		Return Bridge_send(this.id,h)
	}

	ahkPostFunction(n,f*){
		Return Bridge_send(this.id, {Time:0,Name:n,Command:"Function",Params:f})

	}

	ahkLabel(n,s:=0,f:=""){  ;调用子标签。s 调用方式。省略,立即返回;1,等待最长5秒。0或其他的非空值,无限等待。 f 定时器
		Return Bridge_send(this.id, {Time:f?0:s=1?5000:s,Name:n,Command:"Label",Params:f})
		}


;==========================			===============================

;==========================			===============================

	ahkReload(){		; 重启
		Return Bridge_Post(0x111 ,this.id,65400)
	}

	Edit(){			; 编辑脚本
		Bridge_Post(0x111 ,this.id,65401)
	}

	ahkPause(){		; 暂停
		Return Bridge_Post(0x111 ,this.id,65403)
	}

	suspend(){		; 挂起
		Return Bridge_Post(0x111,this.id,65404)
	}

	ahkTerminate(){		; 退出
		Return Bridge_Post(0x111,this.id,65405)
	}

	ListLines(){		; 显示最近运行的行
		Bridge_Post(0x111,this.id,65406)
	}

	ListVars(){		; 显示变量
		Bridge_Post(0x111,this.id,65407)
	}

	Hotkey(){		; 显示热键
		Bridge_Post(0x111,this.id,65408)
	}

	Window(){		; 显示脚本信息
		Bridge_Post(0x111,this.id,65409)
	}

	Script(){		; 显示脚本信息
		Bridge_Post(0x111,this.id,65410)
	}

	ahkReady(){		;检查是否运行
		Return (Bridge_Post(0x111,this.id) = 0)
	}


;==========================			===============================

;==========================			===============================

	ahkdll(n, b:="", r:=""){   ; 加载脚本
		FileRead, n, % n
		If (ErrorLevel = 0) and n
			Return this.ahktextdll(n,b,r)
		}

	ahktextdll(n:="#Persistent", b:="", r:=""){  ;加载代码
		if this.id
			this.ahkTerminate()
		h:=A_DetectHiddenWindows
		DetectHiddenWindows,On
		WinWait % PID:= "ahk_pid " Bridge_BinRun("`n#NoTrayIcon`nSetBatchLines -1`n" (r ? "A_ahkneme:=""" r """`nahkBridge(""" r """,1)`n" : "") n , b, r), ,4
	 	this.id:=WinExist("ahk_class AutoHotkey ahk_pid " PID)
		DetectHiddenWindows % h		
		Return this.id
		}

	; 以下函数需要H版
	ahkFile(n, f:=1){
		Return Bridge_send(this.id, {Results:1,Name:n,Command:"File",Params:f})
	}

	ahkScript(n, f:=1){
		Return Bridge_send(this.id, {Results:1,Name:n,Command:"Script",Params:f})
	}

	ahkExec(n){
		Return Bridge_send(this.id, {Results:1,Name:n,Command:"Exec"})
	}

	ahkExecuteLine(n, f:=0, b:=0){
		Return Bridge_send(this.id, {Results:1,Name:n,Command:"ExecuteLine",mode:f,wait:b})
	}

}

;==========================			===============================

;==========================			===============================

class BridgeHandle {

	Function(f){
		if IsFunc(n:=f.Name)
			Return %n%(f.Params*)
	}

	Label(f){
		Gosub(f.Name,f.Params?f.Params:(f.Time=0)?-1:"")
	}

	var(f){
		Bridge_Drawer["_" f.di]:=f.Return
	}

	Assign(f){
		global
		n:=f.Name
		Try
			%n%:=f.Params
	}

	Getvar(f){
		global
		Try
		if IsObject(b:=f.Name)
		{
			s:=[]
			for i,n in b
				s[n]:=%n%
		}
		else
		{
			s:=%b%
		}
		Return s
	}

	File(f){
		Return   Return h_Self.addFile(f.Name,f.Params)
	}

	Script(f){
		Return h_Self.addScript(f.Name,f.Params)
	}

	ahkExec(f){
		Return h_Self.ahkExec(f.Name)
	}

	ExecuteLine(f){
		Return 	h_Self.ahkExecuteLine(f.Name,f.mode,f.wait)
	}

}


;==========================			===============================

Bridge_Post(s, a ,e:=0 ,c:=0){
	h := A_DetectHiddenWindows
	DetectHiddenWindows on
	PostMessage, %s%, %e%, %c% ,,ahk_id %a%
	DetectHiddenWindows %h%
	Return ErrorLevel
	}


Bridge_BinRun(n,c:="",m:=""){
	static p:=(h_scriptdir ? h_scriptdir : A_ScriptDira), a:=A_IsCompiled ? (FileExist(p "\AutoHotkey.exe") ? p "\AutoHotkey.exe" : A_ScriptFullPath) : A_AhkPath, e := A_IsCompiled ? "/E " : 
		Return	BinRun(a,e "`n" n,c,m)
}


ahkBridge(s:="",r:=""){
	if r
	{
		Critical
		static h:=Gosub("Bridge_Ready")
		h:=A_DetectHiddenWindows
		DetectHiddenWindows,On
		WinGetTitle, T, ahk_id %A_ScriptHwnd%
		WinSetTitle, ahk_id %A_ScriptHwnd%,,%  s:=(instr(T, "ahkBridge_") ? T "|" : "") "ahkBridge_" (s?s:A_ScriptName)
		DetectHiddenWindows % h
	}
	else
	{
		Return new Bridge(s)
	}
}

Return

Bridge_Ready:
	global Bridge_mark, Bridge_Drawer ,Bridge_Parked,h_Self
	if !Bridge_Drawer
		h_Self  ? "" : h_Self:=A_IsDll ? AhkSelf() : AhkExported(),Bridge_mark:=0, Bridge_Drawer:=[], Bridge_Parked:=[]
			,onmessage(0x4a, "Bridge_Receive",50), onmessage(0x80e, "Bridge_Receive",50)
Return

ahkBridge_List(){
	u := A_TitleMatchMode, h:=A_DetectHiddenWindows
	DetectHiddenWindows,On
	SetTitleMatchMode 2
	WinGet s,List,ahkBridge_
	SetTitleMatchMode % u
	f:=[]
	loop % s
	{
		WinGetTitle, r, % "ahk_id " b:=s%A_Index%
		f[b]:=StrReplace(r,"ahkBridge_")
	}
	DetectHiddenWindows % h
	Return f
}

;==========================			===============================

;==========================			===============================

Bridge_send(i, f){
	static n:=1
	w:=A_DetectHiddenWindows,f.Tick:=t:=A_TickCount,f.Hwnd:=A_ScriptHwnd
		,VarSetCapacity(s, 3*A_PtrSize, 0),f.id:=id:=n++,cb:= ObjDump(f,dw)
		,NumPut(&dw, &s, 2*A_PtrSize,"PTR"),NumPut(cb, &s, 1*A_PtrSize,"PTR")

	DetectHiddenWindows on
	SendMessage, 0x4a,0, &s,,ahk_id %i%,,,,% f.Time?f.Time:5000
	DetectHiddenWindows %w%

	if f.Results and (ErrorLevel!="FAIL")
		Return Bridge_Drawer.remove("_" id)
	if (f.Time=0)
		Return ErrorLevel
}

Bridge_Command(w,l){
	BridgeHandle[w](l)
}

Bridge_receive(w,l){
	f := ObjLoad(NumGet(l+A_PtrSize*2,"PTR"),NumGet(l + A_PtrSize,"PTR"))
	if IsFunc(BridgeHandle[f.Command])
	{
		if (f.Time=0)
		{
			r:=BridgeHandle[f.Command](f)
		}
		else
		{
			r:=BridgeHandle[f.Command](f)
			if f.Results and ((A_TickCount - f.Tick) < ((f.Time?f.Time:5000)-15))
				Bridge_send(f.Hwnd,{Return:r, di:f.id, Command:"var"})
		}
	}
}

Return to “脚本函数”

Who is online

Users browsing this forum: No registered users and 5 guests