多线程与单线程的区别:
- 单线程顺序执行:ABCDEFG,HIJKLMN
- 单线程异步执行:ABC,KLMN,EFGHI,错开执行避免I/O之类的长时间等待卡住线程【WinWait】
- 多线程:一个进程内可有多个线程ABCDEFG同时执行互不干扰
- 多进程:创建多个进程ABCDEFG并互相通信,来达到仿多线程的效果。
不控制主进程的话,使用方法如下:
新建进程示例,可以是代码,也可以是路径:
进程1 := ComProcess("C:\Program Files\AutoHotkey\Lib\FindText.ahk")
进程1 := ComProcess("C:\Program Files\AutoHotkey\Lib\FindText.ahk")
进程1 := ComProcess("C:\Program Files\AutoHotkey\Lib\FindText.ahk")
在目标进程中调用一个名为 "Function" 的函数:
进程1.Function(params)
进程1.Function(params)
进程1.Function(params)
获取进程1的一个全局变量:
value := 进程1["VarName"]
value := 进程1.VarName
value := 进程1["VarName"]
value := 进程1.VarName
value := 进程1["VarName"]
value := 进程1.VarName
对进程1的一个全局变量赋值:
进程1["VarName"] := value
进程1.VarName := value
进程1["VarName"] := value
进程1.VarName := value
进程1["VarName"] := value
进程1.VarName := value
对进程1创建一个Class的实例:
value := 进程1["__ComProcess"].__New("ClassName", params)
value := 进程1["__ComProcess"].__New("ClassName", params)
value := 进程1["__ComProcess"].__New("ClassName", params)
另一个精简但不能共享对象的多进程:多进程代替多线程函数 – 精简版
尝试双向通信的多进程库,ComProcess函数用来控制和调用新进程很方便。但是新进程向主进程发送控制,我写了一个Class 变量赋值回调来实现。
完整的双向通信示例:
#Requires AutoHotkey v1.1.33+
#SingleInstance Force
SetBatchLines -1
Gosub 加载新进程标签
进程1.进程共享变量 := New 变量赋值回调("新进程触发回调函数")
Gui -MinimizeBox -MaximizeBox +AlwaysOnTop
Gui Add, Edit, w300 R2 v通信显示 g同步发送
Gui Show, x850 w330 y400, P主进程 - 互相通信同步演示,请输入文字
Loop {
Sleep 80
MouseGetPos, x, y
ToolTip % "P-主进程持续运算演示-" A_Index, x+10, y-70
}
Return
同步发送:
GuiControlGet, 获取编辑框内容,, 通信显示
进程1.Gui同步更新(获取编辑框内容, "通信显示")
Return
GuiClose:
ExitApp
Return
; F3键做新进程的开、关、一键开关的演示【只有主进程端能够新建进程】
F3::
; 进程1 := ComProcess(新代码1)
进程1 := ""
; 进程1:=(Toggle:=!Toggle) ? ComProcess(新代码1) : ""
Return
新进程触发回调函数(newValue) {
GuiControl,, 通信显示, %newValue%
}
class 变量赋值回调 {
__New(changeCallback) {
this._onChangeCallback := Func(changeCallback)
}
回调变量[] {
get {
return this._value
}
set {
this._value := value
, (this._onChangeCallback && this._onChangeCallback.Call(this._value))
return this._value
}
}
}
加载新进程标签:
新代码1=
( ` %
Gui -MinimizeBox -MaximizeBox +AlwaysOnTop
Gui Add, Edit, w300 R2 v通信显示 g同步发送
Gui Show, x850 w330 y500, F3新进程 - 互相通信同步演示,请输入文字
Loop {
Sleep 80
MouseGetPos, x, y
ToolTip % "F3-新进程持续运算演示-" A_Index, x+10, y-30
}
Return
同步发送:
GuiControlGet, 获取编辑框内容,, 通信显示
进程共享变量.回调变量 := 获取编辑框内容
Return
Gui同步更新(Value, ControlID) {
GuiControl,, %ControlID%, %Value%
}
GuiClose:
ExitApp
Return
)
进程1 := ComProcess(新代码1)
Return
/*
在目标进程中调用一个名为 "Function" 的函数。
进程1.Function(params)
获取进程1的一个全局变量
value := 进程1["VarName"]
value := 进程1.VarName
对进程1的一个全局变量赋值
进程1["VarName"] := value
进程1.VarName := value
创建一个Class的实例
value := 进程1["__ComProcess"].__New("ClassName", params)
已知限制:
如果脚本在运行远程脚本调用的方法时退出,则远程脚本将收到错误。
AutoHotkey 如何在本地与 COM 对象交互以及 AutoHotkey 对象如何通过 COM 接口响应请求也存在一些限制。
变量无法通过 ByRef 传递到远程对象。
有些调用是不明确的;例如,foo.bar 触发器 foo.__Call 进而foo.__Get。
*/
; By dbgba Thank thqby
ComProcess(PathsOrCode, v1Interpreter="", Timeout=30, NoTrayIcon="#NoTrayIcon") {
Static IDispatch, ComProcessNum := 0
, _ := (VarSetCapacity(IDispatch, 16), NumPut(0x46000000000000c0, NumPut(0x20400, IDispatch, "int64"), "int64"))
, PIDLabel := DllCall("GetCurrentProcessId")
if (v1Interpreter="") {
if A_Is64bitOS
SetRegView 64
RegRead, InstallDir, HKLM\SOFTWARE\AutoHotkey, InstallDir
v1Interpreter := InstallDir="" ? A_AhkPath : InstallDir "\AutoHotkey.exe"
}
if !FileExist(v1Interpreter)
throw Exception("请将参数2的AHK解释器路径设置正确!")
lresult := DllCall("oleacc\LresultFromObject", "Ptr", &IDispatch, "Ptr", 0, "Ptr", &(client := { proxy: 0 }), "Ptr")
if IsObject(PathsOrCode) {
t := PathsOrCode, PathsOrCode := ""
For __, p in t
PathsOrCode .= "`n#include " p
}
v1script := Format("
(
#Persistent
" NoTrayIcon "
class __ComProcess {
__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 __ComProcess(), ObjRelease(idisp)), hMapping := DllCall(""kernel32\CreateFileMapping"", ""Ptr"", -1, ""Ptr"", 0, ""UInt"", 0x4, ""UInt"", 0, ""UInt"", 4, ""Str"", ""AHKLoadStatus" PIDLabel . ++ComProcessNum """), pView := DllCall(""kernel32\MapViewOfFile"", ""Ptr"", hMapping, ""UInt"", 0x2, ""UInt"", 0, ""UInt"", 0, ""UInt"", 4)
return IsObject(name) ? new name(args*) : new %name%(args*)
}
__Call(name, args*) {
Global
if (IsObject(args) && %name%!="""")
return __ComProcessVar__ := %name%
return %name%(args*)
}
; __Get(name) COM机制无法触发,故删掉
__Set(name, val) {
Global
return %name% := val
}
__Delete() {
SetTimer __ComProcessExitApp__, -1
return
__ComProcessExitApp__:
ExitApp
}
}
{}
)", lresult, FileExist(PathsOrCode) ? "" : PathsOrCode)
if (v1Interpreter ~= "i)\.dll$") {
if (!DllCall("GetModuleHandle", "str", v1Interpreter) && !DllCall("LoadLibrary", "str", v1Interpreter)) {
DllCall("oleacc\ObjectFromLresult", "ptr", lresult, "ptr", &IDispatch, "ptr", 0, "ptr*", idsp := 0), ObjRelease(idisp)
throw Exception("load AutoHotkey.dll fail")
}
if !(threadID := DllCall(v1Interpreter "\NewThread", "str", v1script "`n" (FileExist(PathsOrCode) ? "#Include " PathsOrCode : ""), "str", "", "str", "", "cdecl uint")) {
DllCall("oleacc\ObjectFromLresult", "ptr", lresult, "ptr", &IDispatch, "ptr", 0, "ptr*", idsp := 0), ObjRelease(idisp)
throw Exception("Failed to load script")
}
_exec := {ProcessID : DllCall("GetCurrentProcessId")}
} else {
if FileExist(PathsOrCode)
_exec := ComObjCreate("WScript.Shell").Exec("""" v1Interpreter """ /include """ PathsOrCode """ *")
else
_exec := ComObjCreate("WScript.Shell").Exec("""" v1Interpreter """ /CP0 *")
_exec.StdIn.Write(v1script), _exec.StdIn.Close()
}
Loop % Timeout*1000//15 {
Sleep 15
hMap := DllCall("kernel32\OpenFileMapping", "UInt", 0x2, "Int", 0, "Str", "AHKLoadStatus" PIDLabel . ComProcessNum)
, pView := DllCall("kernel32\MapViewOfFile", "Ptr", hMap, "UInt", 0x2, "UInt", 0, "UInt", 0, "UInt", 4)
} Until ((isLoaded := NumGet(pView+0, 0, "Int"))=0)
if (isLoaded!=0)
Throw Exception("AHK新进程启动超时或故障!")
Sleep 10
return client.proxy
}
#Requires AutoHotkey v1.1.33+
#SingleInstance Force
SetBatchLines -1
Gosub 加载新进程标签
进程1.进程共享变量 := New 变量赋值回调("新进程触发回调函数")
Gui -MinimizeBox -MaximizeBox +AlwaysOnTop
Gui Add, Edit, w300 R2 v通信显示 g同步发送
Gui Show, x850 w330 y400, P主进程 - 互相通信同步演示,请输入文字
Loop {
Sleep 80
MouseGetPos, x, y
ToolTip % "P-主进程持续运算演示-" A_Index, x+10, y-70
}
Return
同步发送:
GuiControlGet, 获取编辑框内容,, 通信显示
进程1.Gui同步更新(获取编辑框内容, "通信显示")
Return
GuiClose:
ExitApp
Return
; F3键做新进程的开、关、一键开关的演示【只有主进程端能够新建进程】
F3::
; 进程1 := ComProcess(新代码1)
进程1 := ""
; 进程1:=(Toggle:=!Toggle) ? ComProcess(新代码1) : ""
Return
新进程触发回调函数(newValue) {
GuiControl,, 通信显示, %newValue%
}
class 变量赋值回调 {
__New(changeCallback) {
this._onChangeCallback := Func(changeCallback)
}
回调变量[] {
get {
return this._value
}
set {
this._value := value
, (this._onChangeCallback && this._onChangeCallback.Call(this._value))
return this._value
}
}
}
加载新进程标签:
新代码1=
( ` %
Gui -MinimizeBox -MaximizeBox +AlwaysOnTop
Gui Add, Edit, w300 R2 v通信显示 g同步发送
Gui Show, x850 w330 y500, F3新进程 - 互相通信同步演示,请输入文字
Loop {
Sleep 80
MouseGetPos, x, y
ToolTip % "F3-新进程持续运算演示-" A_Index, x+10, y-30
}
Return
同步发送:
GuiControlGet, 获取编辑框内容,, 通信显示
进程共享变量.回调变量 := 获取编辑框内容
Return
Gui同步更新(Value, ControlID) {
GuiControl,, %ControlID%, %Value%
}
GuiClose:
ExitApp
Return
)
进程1 := ComProcess(新代码1)
Return
/*
在目标进程中调用一个名为 "Function" 的函数。
进程1.Function(params)
获取进程1的一个全局变量
value := 进程1["VarName"]
value := 进程1.VarName
对进程1的一个全局变量赋值
进程1["VarName"] := value
进程1.VarName := value
创建一个Class的实例
value := 进程1["__ComProcess"].__New("ClassName", params)
已知限制:
如果脚本在运行远程脚本调用的方法时退出,则远程脚本将收到错误。
AutoHotkey 如何在本地与 COM 对象交互以及 AutoHotkey 对象如何通过 COM 接口响应请求也存在一些限制。
变量无法通过 ByRef 传递到远程对象。
有些调用是不明确的;例如,foo.bar 触发器 foo.__Call 进而foo.__Get。
*/
; By dbgba Thank thqby
ComProcess(PathsOrCode, v1Interpreter="", Timeout=30, NoTrayIcon="#NoTrayIcon") {
Static IDispatch, ComProcessNum := 0
, _ := (VarSetCapacity(IDispatch, 16), NumPut(0x46000000000000c0, NumPut(0x20400, IDispatch, "int64"), "int64"))
, PIDLabel := DllCall("GetCurrentProcessId")
if (v1Interpreter="") {
if A_Is64bitOS
SetRegView 64
RegRead, InstallDir, HKLM\SOFTWARE\AutoHotkey, InstallDir
v1Interpreter := InstallDir="" ? A_AhkPath : InstallDir "\AutoHotkey.exe"
}
if !FileExist(v1Interpreter)
throw Exception("请将参数2的AHK解释器路径设置正确!")
lresult := DllCall("oleacc\LresultFromObject", "Ptr", &IDispatch, "Ptr", 0, "Ptr", &(client := { proxy: 0 }), "Ptr")
if IsObject(PathsOrCode) {
t := PathsOrCode, PathsOrCode := ""
For __, p in t
PathsOrCode .= "`n#include " p
}
v1script := Format("
(
#Persistent
" NoTrayIcon "
class __ComProcess {
__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 __ComProcess(), ObjRelease(idisp)), hMapping := DllCall(""kernel32\CreateFileMapping"", ""Ptr"", -1, ""Ptr"", 0, ""UInt"", 0x4, ""UInt"", 0, ""UInt"", 4, ""Str"", ""AHKLoadStatus" PIDLabel . ++ComProcessNum """), pView := DllCall(""kernel32\MapViewOfFile"", ""Ptr"", hMapping, ""UInt"", 0x2, ""UInt"", 0, ""UInt"", 0, ""UInt"", 4)
return IsObject(name) ? new name(args*) : new %name%(args*)
}
__Call(name, args*) {
Global
if (IsObject(args) && %name%!="""")
return __ComProcessVar__ := %name%
return %name%(args*)
}
; __Get(name) COM机制无法触发,故删掉
__Set(name, val) {
Global
return %name% := val
}
__Delete() {
SetTimer __ComProcessExitApp__, -1
return
__ComProcessExitApp__:
ExitApp
}
}
{}
)", lresult, FileExist(PathsOrCode) ? "" : PathsOrCode)
if (v1Interpreter ~= "i)\.dll$") {
if (!DllCall("GetModuleHandle", "str", v1Interpreter) && !DllCall("LoadLibrary", "str", v1Interpreter)) {
DllCall("oleacc\ObjectFromLresult", "ptr", lresult, "ptr", &IDispatch, "ptr", 0, "ptr*", idsp := 0), ObjRelease(idisp)
throw Exception("load AutoHotkey.dll fail")
}
if !(threadID := DllCall(v1Interpreter "\NewThread", "str", v1script "`n" (FileExist(PathsOrCode) ? "#Include " PathsOrCode : ""), "str", "", "str", "", "cdecl uint")) {
DllCall("oleacc\ObjectFromLresult", "ptr", lresult, "ptr", &IDispatch, "ptr", 0, "ptr*", idsp := 0), ObjRelease(idisp)
throw Exception("Failed to load script")
}
_exec := {ProcessID : DllCall("GetCurrentProcessId")}
} else {
if FileExist(PathsOrCode)
_exec := ComObjCreate("WScript.Shell").Exec("""" v1Interpreter """ /include """ PathsOrCode """ *")
else
_exec := ComObjCreate("WScript.Shell").Exec("""" v1Interpreter """ /CP0 *")
_exec.StdIn.Write(v1script), _exec.StdIn.Close()
}
Loop % Timeout*1000//15 {
Sleep 15
hMap := DllCall("kernel32\OpenFileMapping", "UInt", 0x2, "Int", 0, "Str", "AHKLoadStatus" PIDLabel . ComProcessNum)
, pView := DllCall("kernel32\MapViewOfFile", "Ptr", hMap, "UInt", 0x2, "UInt", 0, "UInt", 0, "UInt", 4)
} Until ((isLoaded := NumGet(pView+0, 0, "Int"))=0)
if (isLoaded!=0)
Throw Exception("AHK新进程启动超时或故障!")
Sleep 10
return client.proxy
}
#Requires AutoHotkey v1.1.33+
#SingleInstance Force
SetBatchLines -1
Gosub 加载新进程标签
进程1.进程共享变量 := New 变量赋值回调("新进程触发回调函数")
Gui -MinimizeBox -MaximizeBox +AlwaysOnTop
Gui Add, Edit, w300 R2 v通信显示 g同步发送
Gui Show, x850 w330 y400, P主进程 - 互相通信同步演示,请输入文字
Loop {
Sleep 80
MouseGetPos, x, y
ToolTip % "P-主进程持续运算演示-" A_Index, x+10, y-70
}
Return
同步发送:
GuiControlGet, 获取编辑框内容,, 通信显示
进程1.Gui同步更新(获取编辑框内容, "通信显示")
Return
GuiClose:
ExitApp
Return
; F3键做新进程的开、关、一键开关的演示【只有主进程端能够新建进程】
F3::
; 进程1 := ComProcess(新代码1)
进程1 := ""
; 进程1:=(Toggle:=!Toggle) ? ComProcess(新代码1) : ""
Return
新进程触发回调函数(newValue) {
GuiControl,, 通信显示, %newValue%
}
class 变量赋值回调 {
__New(changeCallback) {
this._onChangeCallback := Func(changeCallback)
}
回调变量[] {
get {
return this._value
}
set {
this._value := value
, (this._onChangeCallback && this._onChangeCallback.Call(this._value))
return this._value
}
}
}
加载新进程标签:
新代码1=
( ` %
Gui -MinimizeBox -MaximizeBox +AlwaysOnTop
Gui Add, Edit, w300 R2 v通信显示 g同步发送
Gui Show, x850 w330 y500, F3新进程 - 互相通信同步演示,请输入文字
Loop {
Sleep 80
MouseGetPos, x, y
ToolTip % "F3-新进程持续运算演示-" A_Index, x+10, y-30
}
Return
同步发送:
GuiControlGet, 获取编辑框内容,, 通信显示
进程共享变量.回调变量 := 获取编辑框内容
Return
Gui同步更新(Value, ControlID) {
GuiControl,, %ControlID%, %Value%
}
GuiClose:
ExitApp
Return
)
进程1 := ComProcess(新代码1)
Return
/*
在目标进程中调用一个名为 "Function" 的函数。
进程1.Function(params)
获取进程1的一个全局变量
value := 进程1["VarName"]
value := 进程1.VarName
对进程1的一个全局变量赋值
进程1["VarName"] := value
进程1.VarName := value
创建一个Class的实例
value := 进程1["__ComProcess"].__New("ClassName", params)
已知限制:
如果脚本在运行远程脚本调用的方法时退出,则远程脚本将收到错误。
AutoHotkey 如何在本地与 COM 对象交互以及 AutoHotkey 对象如何通过 COM 接口响应请求也存在一些限制。
变量无法通过 ByRef 传递到远程对象。
有些调用是不明确的;例如,foo.bar 触发器 foo.__Call 进而foo.__Get。
*/
; By dbgba Thank thqby
ComProcess(PathsOrCode, v1Interpreter="", Timeout=30, NoTrayIcon="#NoTrayIcon") {
Static IDispatch, ComProcessNum := 0
, _ := (VarSetCapacity(IDispatch, 16), NumPut(0x46000000000000c0, NumPut(0x20400, IDispatch, "int64"), "int64"))
, PIDLabel := DllCall("GetCurrentProcessId")
if (v1Interpreter="") {
if A_Is64bitOS
SetRegView 64
RegRead, InstallDir, HKLM\SOFTWARE\AutoHotkey, InstallDir
v1Interpreter := InstallDir="" ? A_AhkPath : InstallDir "\AutoHotkey.exe"
}
if !FileExist(v1Interpreter)
throw Exception("请将参数2的AHK解释器路径设置正确!")
lresult := DllCall("oleacc\LresultFromObject", "Ptr", &IDispatch, "Ptr", 0, "Ptr", &(client := { proxy: 0 }), "Ptr")
if IsObject(PathsOrCode) {
t := PathsOrCode, PathsOrCode := ""
For __, p in t
PathsOrCode .= "`n#include " p
}
v1script := Format("
(
#Persistent
" NoTrayIcon "
class __ComProcess {
__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 __ComProcess(), ObjRelease(idisp)), hMapping := DllCall(""kernel32\CreateFileMapping"", ""Ptr"", -1, ""Ptr"", 0, ""UInt"", 0x4, ""UInt"", 0, ""UInt"", 4, ""Str"", ""AHKLoadStatus" PIDLabel . ++ComProcessNum """), pView := DllCall(""kernel32\MapViewOfFile"", ""Ptr"", hMapping, ""UInt"", 0x2, ""UInt"", 0, ""UInt"", 0, ""UInt"", 4)
return IsObject(name) ? new name(args*) : new %name%(args*)
}
__Call(name, args*) {
Global
if (IsObject(args) && %name%!="""")
return __ComProcessVar__ := %name%
return %name%(args*)
}
; __Get(name) COM机制无法触发,故删掉
__Set(name, val) {
Global
return %name% := val
}
__Delete() {
SetTimer __ComProcessExitApp__, -1
return
__ComProcessExitApp__:
ExitApp
}
}
{}
)", lresult, FileExist(PathsOrCode) ? "" : PathsOrCode)
if (v1Interpreter ~= "i)\.dll$") {
if (!DllCall("GetModuleHandle", "str", v1Interpreter) && !DllCall("LoadLibrary", "str", v1Interpreter)) {
DllCall("oleacc\ObjectFromLresult", "ptr", lresult, "ptr", &IDispatch, "ptr", 0, "ptr*", idsp := 0), ObjRelease(idisp)
throw Exception("load AutoHotkey.dll fail")
}
if !(threadID := DllCall(v1Interpreter "\NewThread", "str", v1script "`n" (FileExist(PathsOrCode) ? "#Include " PathsOrCode : ""), "str", "", "str", "", "cdecl uint")) {
DllCall("oleacc\ObjectFromLresult", "ptr", lresult, "ptr", &IDispatch, "ptr", 0, "ptr*", idsp := 0), ObjRelease(idisp)
throw Exception("Failed to load script")
}
_exec := {ProcessID : DllCall("GetCurrentProcessId")}
} else {
if FileExist(PathsOrCode)
_exec := ComObjCreate("WScript.Shell").Exec("""" v1Interpreter """ /include """ PathsOrCode """ *")
else
_exec := ComObjCreate("WScript.Shell").Exec("""" v1Interpreter """ /CP0 *")
_exec.StdIn.Write(v1script), _exec.StdIn.Close()
}
Loop % Timeout*1000//15 {
Sleep 15
hMap := DllCall("kernel32\OpenFileMapping", "UInt", 0x2, "Int", 0, "Str", "AHKLoadStatus" PIDLabel . ComProcessNum)
, pView := DllCall("kernel32\MapViewOfFile", "Ptr", hMap, "UInt", 0x2, "UInt", 0, "UInt", 0, "UInt", 4)
} Until ((isLoaded := NumGet(pView+0, 0, "Int"))=0)
if (isLoaded!=0)
Throw Exception("AHK新进程启动超时或故障!")
Sleep 10
return client.proxy
}
声明:站内资源为整理优化好的代码上传分享与学习研究,如果是开源代码基本都会标明出处,方便大家扩展学习路径。请不要恶意搬运,破坏站长辛苦整理维护的劳动成果。本站为爱好者分享站点,所有内容不作为商业行为。如若本站上传内容侵犯了原著者的合法权益,请联系我们进行删除下架。
评论(0)