To use Thread() you will need AutoHotkey.dll and CreatePipe() function.
You need also to save AutoHotkey.dll in A_WorkingDir :!:
How to use
Read about Multithreading Consideration and Terminate Thread on MSDN
Download Zip
Many thanks to tinku99 for AutoHotkey.dll and Lexikos for How to: Run Dynamic Script... Through a Pipe!
Example:
#Persistent
Next("Create a new thread",0)
ThreadID:=Thread("MsgBox I am a new thread")
Next("Replace script in thread with new script")
Thread("Msgbox New script in same thread","newFile",ThreadID)
Next("Remove script, add a script and go to its label")
Thread("`n","newFile",ThreadID) ;remove script
Sleep, 100
;Add a Label into the thread without executing it
Thread("Label:`nMsgbox This is a label in thread: %A_ThisLabel%`nReturn","addFile",ThreadID)
Sleep, 500
;Jump to the label in the thread
Thread("Label","ahkLabel",ThreadID)
Next("Add a Goto label from current script and jump to it")
Thread("aLabel:aLabelEnd","addFile",ThreadID)
Sleep, 500
Thread("aLabel","ahkLabel",ThreadID)
Next("Replace script with a combination of script, label and function")
Thread("`n","newFile",ThreadID) ;remove script
;Combination of script, label and function
Thread("Msgbox AutoExecute section`nGoSub, aLabel`nfunc(""a"",""b"")`nfinished:=1`nReturn`naLabel:aLabelEnd`nfunc{}","newFile",ThreadID)
Loop
If Sleep(100) && Thread("finished","ahkgetvar",ThreadID) ;get a variable from the thread
break
Next("Run the function in thread from AutoHotkey.exe",0)
Thread("func(x,y)","ahkFunction",ThreadID)
Next("Get some build in parameters")
MsgBox % Thread("A_AhkPath","A_AhkPath",ThreadID)
. "`n" Thread("A_ScriptFullPath","A_ScriptFullPath",ThreadID)
. "`n" Thread("A_ScriptName","A_ScriptName",ThreadID)
. "`n" Thread("A_TickCount","A_TickCount",ThreadID)
Next("ExitApp",0)
ExitApp
sleep(t){
Sleep %t%
Return 1
}
Next(text="",wait=3){
WinWaitActive ahk_class #32770,,%wait%
WinWaitClose ahk_class #32770,,%wait%
MsgBox % "Click ok for next example:`n`n" text
IfWinActive ahk_class #32770
WinClose
}
aLabel:
MsgBox % "This is a label: " A_ThisLabel
Return
aLabelEnd:
Return
func(p1,p2){
MsgBox % "func`n" p1 "`n" p2
}Function Thread()
Thread(FileOrTextOrLabel,Params="",ThreadId=""){
static
local _thread,lib,h,#__PIPE_NAME_,#__PIPE_,#__PIPE_GA_,thread_,result,isfile,FileExtract_ToMem:="FileExtract_ToMem"
,dllcall:="|A_AhkPath|A_AhkVersion|A_AppData|A_AutoTrim|A_BatchLines|A_Caret|A_ComSpec|A_ControlDelay|A_Cursor|A_DateTime"
. "|A_DefaultMouseSpeed|A_Desktop|A_DetectHiddenText|A_DetectHiddenWindows|A_EndChar|A_EventInfo|A_ExitReason|A_FormatFloat"
. "|A_FormatInteger|A_Gui|A_GuiControl|A_GuiEvent|A_IconFile|A_IconHidden|A_IconNumber|A_IconTip|A_IPAddress|A_IsAdmin"
. "|A_IsCritical|A_IsPaused|A_IsSuspended|A_KeyDelay|A_Language|A_LastError|A_LineFile|A_LineNumber|A_LoopField|A_LoopFileAttrib"
. "|A_LoopFileDir|A_LoopFileExt|A_LoopFileFullPath|A_LoopFileLongPath|A_LoopFileName|A_LoopFileShortName|A_LoopFileShortPath"
. "|A_LoopFileSize|A_LoopFileTime|A_LoopIndex|A_LoopReadLine|A_LoopRegKey|A_LoopRegName|A_LoopRegSubKey|A_LoopRegTimeModified"
. "|A_LoopRegType|A_MMM|A_MouseDelay|A_MyDocuments|A_Now|A_OSType|A_OSVersion|A_PriorHotkey|A_ProgramFiles|A_Programs"
. "|A_ScreenWidth|A_ScriptDir|A_ScriptFullPath|A_ScriptName|A_Space|A_StartMenu|A_Startup|A_StringCaseSense|A_Temp|A_ThisFunc"
. "|A_ThisHotkey|A_ThisLabel|A_ThisMenu|A_ThisMenuItem|A_ThisMenuItemPos|A_TickCount|A_TimeIdle|A_TimeIdlePhysical"
. "|A_TimeSincePriorHotkey|A_TimeSinceThisHotkey|A_TitleMatchMode|A_TitleMatchModeSpeed|A_True|A_UserName|A_WinDelay|A_WinDir"
. "|A_WorkingDir|newFile|addFile|ahkLabel|ahkFindFunc|ahkgetvar|ahkContinue|ahkTerminate|ahkFunction|ahkassign|Terminate|Suspend|Resume|Priority|ExitCode|"
If (!_DllPath){
CheckDir := A_WorkingDir . "\AutoHotkey*.dll`n" . A_ScriptDir . "\AutoHotkey*.dll`n" . SubStr(A_AhkPath,1,InStr(A_AhkPath,"\",1,0)) . "AutoHotkey*.dll`n" . SubStr(A_AhkPath,1,InStr(A_AhkPath,"\",1,0)) . "Lib\AutoHotkey*.dll`n" . A_MyDocuments . "\Lib\AutoHotkey*.dll"
While (!FileExist(_DllPath ? _DllPath : (_DllPath:=A_WorkingDir . "\AutoHotkey.dll"))){
Sleep, 50
Loop,Parse,CheckDir,`n
{
Loop % A_LoopField
FileMove,%A_LoopFileFullPath%,% (_DllPath:=RegExReplace(A_LoopField,"\*"))
If (FileExist(_DllPath) and breaked:=1)
break
}
If A_Index<21
Continue
MsgBox AutoHotkey.dll was not found
ExitApp
}
StringReplace,_DllPath,_DllPath,\\,\,A
DllCall("LoadLibrary","Str",_DllPath)
Sleep,10
}
iscritical:=A_IsCritical
Critical, On
If (ThreadId<>""){
If (ThreadId=0 || ThreadId="Main")
_thread:=_DllPath
else if ThreadId is not digit
{
_thread:=ThreadId
DllCall("LoadLibrary","Str",_thread)
} else If ThreadId is digit
_thread:=thread%ThreadId%
else {
_thread := "AutoHotkey_" A_TickCount . ".dll"
WorkingDir:=A_WorkingDir
SetWorkingDir % SubStr(_DllPath,1,InStr(_DllPath,"\",1,0)-1)
FileMove, %_DllPath%, %_thread%
lib := DllCall("LoadLibrary", "str", _thread)
FileMove, %_thread%,%_DllPath%
SetWorkingDir % WorkingDir
Sleep, 10
}
} else {
_thread := "AutoHotkey_" A_TickCount . ".dll"
WorkingDir:=A_WorkingDir
SetWorkingDir % SubStr(_DllPath,1,InStr(_DllPath,"\",1,0)-1)
FileMove, %_DllPath%, %_thread%
lib := DllCall("LoadLibrary", "str", _thread)
FileMove, %_thread%,%_DllPath%
SetWorkingDir % WorkingDir
Sleep, 10
}
Critical, %iscritical%
If !FileExist(FileOrTextOrLabel){
StringReplace,FileOrTextOrLabel,FileOrTextOrLabel,`n,`r`n
StringReplace,FileOrTextOrLabel,FileOrTextOrLabel,`r`r,`r
If RegExMatch(FileOrTextOrLabel,"m)^[^:]+:[^:]+|[^\{}]+\{}$"){
If !(fullscript){
If (A_IsCompiled and !fullScript and IsFunc(FileExtract_ToMem)){
pData:=0,DataSize:=0
If (%FileExtract_ToMem%(">AUTOHOTKEY SCRIPT<", pData, DataSize)
|| %FileExtract_ToMem%(">AHF WITH ICON<", pData, DataSize)){
VarSetCapacity(fullScript,DataSize)
DllCall("lstrcpyn", "str", fullScript, "uint", pData, "int", DataSize+1)
VarSetCapacity(fullScript,-1)
StringReplace,fullScript,fullScript,`n,`r`n
StringReplace,fullScript,fullScript,`r`r,`r
fullScript .="`r`n"
}
} else if (!fullScript){
FileRead,fullScript,%A_ScriptFullPath%
StringReplace,fullScript,fullScript,`n,`r`n
StringReplace,fullScript,fullScript,`r`r,`r
fullScript .= "`r`n"
}
}
Loop,Parse,FileOrTextOrLabel,`n,`r
{
If A_LoopField=
Continue
If A_Index=1
FileOrTextOrLabel=
If (RegExMatch(A_LoopField,"^[^:\s]+:[^:\s=]+$")){
StringSplit,label,A_LoopField,:
If (label0=2 and IsLabel(label1) and IsLabel(label2)){
FileOrTextOrLabel .=SubStr(fullScript
, ErrorLevel:=InStr(fullScript,"`r`n" label1 ":`r`n")
, InStr(fullScript,"`r`n" label2 ":`r`n")-ErrorLevel) . "`r`n"
}
} else if RegExMatch(A_LoopField,"^[^\{}\s]+\{}$"){
StringTrimRight,label,A_LoopField,2
FileOrTextOrLabel .= SubStr(fullScript
, h:=RegExMatch(fullScript,"i)\R" label "\([^)\R]*\)\R?\{")
, RegExMatch(fullScript,"\R\s*}\s*\K\R",1,h)-h) . "`r`n"
} else
FileOrTextOrLabel .= A_LoopField "`r`n"
}
}
} else isfile:=1
If InStr(dllcall,"|" . Params . "|")
{
If Params=Terminate
Return DllCall("TerminateThread","UInt",ThreadID,"Int",99999)
else if Params=Suspend
Return DllCall("SuspendThread","UInt",ThreadID)
else if Params=Resume
Return DllCall("ResumeThread","UInt",ThreadID)
else if Params=GetExitCode
Return DllCall("GetExitCodeThread","UInt",ThreadID,"UIntP",ErrorLevel)
else if Params=Priority
Return DllCall("SetThreadPriority","UInt",ThreadID,"Int",FileOrTextOrLabel)
Loop,Parse,dllcall,|
If (Params=A_LoopField)
Params:=A_LoopField
If (ThreadId<>"")
{
If (Params = "newFile"){
If !(isfile){
FileOrTextOrLabel:="#Persistent`n" . FileOrTextOrLabel
result := DllCall(_thread . "\addFile", "str", CreatePipe(FileOrTextOrLabel,"AhkDll newFile @ " A_Hour ":" A_Min ":" A_Sec ":" A_MSec,0), "uchar", 1,"uchar" , 2, "Cdecl UInt")
Return result
} else
Return DllCall(_thread . "\addFile", "str", FileOrTextOrLabel, "uchar", 1,"uchar" , 2, "Cdecl UInt")
} else if (Params="addFile"){
If !(isfile){
FileOrTextOrLabel:="#Persistent`n" . FileOrTextOrLabel
result := DllCall(_thread . "\addFile", "str", CreatePipe(FileOrTextOrLabel,"AhkDll addFile @ " A_Hour ":" A_Min ":" A_Sec ":" A_MSec,0), "uchar", 1,"uchar" , 1, "Cdecl UInt")
Return result
} else if FileExist(FileOrTextOrLabel)
Return DllCall(_thread . "\addFile", "str", FileOrTextOrLabel, "uchar", 1,"uchar" , 1, "Cdecl UInt")
} else if Params in A_AhkPath,A_AhkVersion,A_AppData,A_AutoTrim,A_BatchLines,A_Caret,A_ComSpec,A_ControlDelay
,A_Cursor,A_DateTime,A_DefaultMouseSpeed,A_Desktop,A_DetectHiddenText,A_DetectHiddenWindows
,A_EndChar,A_EventInfo,A_ExitReason,A_FormatFloat,A_FormatInteger,A_Gui,A_GuiControl,A_GuiEvent
,A_IconFile,A_IconHidden,A_IconNumber,A_IconTip,A_IPAddress,A_IsAdmin,A_IsCritical,A_IsPaused
,A_IsSuspended,A_KeyDelay,A_Language,A_LastError,A_LineFile,A_LineNumber,A_LoopField,A_LoopFileAttrib
,A_LoopFileDir,A_LoopFileExt,A_LoopFileFullPath,A_LoopFileLongPath,A_LoopFileName,A_LoopFileShortName
,A_LoopFileShortPath,A_LoopFileSize,A_LoopFileTime,A_LoopIndex,A_LoopReadLine,A_LoopRegKey
,A_LoopRegName,A_LoopRegSubKey,A_LoopRegTimeModified,A_LoopRegType,A_MMM,A_MouseDelay,A_MyDocuments
,A_Now,A_OSType,A_OSVersion,A_PriorHotkey,A_ProgramFiles,A_Programs,A_ScreenWidth,A_ScriptDir
,A_ScriptFullPath,A_ScriptName,A_Space,A_StartMenu,A_Startup,A_StringCaseSense,A_Temp,A_ThisFunc
,A_ThisHotkey,A_ThisLabel,A_ThisMenu,A_ThisMenuItem,A_ThisMenuItemPos,A_TickCount,A_TimeIdle
,A_TimeIdlePhysical,A_TimeSincePriorHotkey,A_TimeSinceThisHotkey,A_TitleMatchMode
,A_TitleMatchModeSpeed,A_True,A_UserName,A_WinDelay,A_WinDir,A_WorkingDir
{
Varsetcapacity(result,100000000)
DllCall(_thread . "\EBIV" . SubStr(Params,2), "str", result,"str",Params, "Cdecl UInt")
Return result
} else if Params in ahkgetvar
{
Varsetcapacity(result,100000000)
DllCall(_thread . "\ahkgetvar", "str", FileOrTextOrLabel, "str", result, "Cdecl uint")
Return result
} else if Params in ahkLabel,ahkFindFunc,ahkContinue,ahkTerminate
Return DllCall(_thread . "\" . Params, "str", FileOrTextOrLabel, "Cdecl UInt")
else if Params in ahkassign
{
If InStr(FileOrTextOrLabel,"="){
label:=SubStr(FileOrTextOrLabel,InStr(FileOrTextOrLabel,"=")+1)
FileOrTextOrLabel:=SubStr(FileOrTextOrLabel,1,InStr(FileOrTextOrLabel,"=")-1)
}
Return DllCall(_thread . "\" . Params, "str", FileOrTextOrLabel, "Str", label, "Cdecl UInt")
} else if Params = ahkFunction
{
IfInString,FileOrTextOrLabel,(
{
label:=SubStr(FileOrTextOrLabel,1,InStr(FileOrTextOrLabel,"(")-1)
StringReplace,FileOrTextOrLabel,FileOrTextOrLabel,(
StringReplace,FileOrTextOrLabel,FileOrTextOrLabel,)
StringReplace,FileOrTextOrLabel,FileOrTextOrLabel,% label
IfInString,FileOrTextOrLabel,`,
StringSplit,label,FileOrTextOrLabel,`,
else
label1:=FileOrTextOrLabel,label2:=""
result:=DllCall(_thread . "\ahkFunction", "str", label,"str",label1,"str",label2, "Cdecl UInt")
DllCall("Sleep","Int",50)
Return result
} else {
result:=DllCall(_thread . "\ahkFunction", "str", FileOrTextOrLabel,"Cdecl UInt")
DllCall("Sleep","Int",50)
Return result
}
}
}
} else {
If !(isfile){
FileOrTextOrLabel:="#Persistent`n" . FileOrTextOrLabel
thread_ := DllCall(_thread . "\ahkdll", "str", CreatePipe(FileOrTextOrLabel,"AhkDll @ " A_Hour ":" A_Min ":" A_Sec ":" A_MSec,1), "str", _thread, "str", Params, "Cdecl Int")
} else {
thread_ := DllCall(_thread . "\ahkdll", "str", FileOrTextOrLabel, "str", _thread, "str", Params, "Cdecl Int")
}
DllCall("Sleep","Int",50)
}
thread%thread_%:=_thread
lib%thread_% := lib
Return thread_
}




