; #INDEX# ======================================================================================================================= ; Title .........: AutoThreadV3 ; AutoIt Version : 3.3.14.3 ; Language ......: English ; Description ...: Functions that emulates and manage multithreading features from Autoit ; Author ........: KingPaic M.P ; Modified ......: ; Dll ...........: ; =============================================================================================================================== #include #include #include #Region #VARIABLES# ; ======================================================================================================================= ;MAIN WORKING PATHS FOR EXCIANGE MESSAGES global $_AuThread_MainPath = @TempDir & "\AutoitThreadByPaic\"&@ScriptName&"\" ;[TO BE CONFIGURED !!!CAN'T!!! BE CHANGED DURING EXEC] global $_AuThread_WorkPath = @TempDir & "\AutoitThreadByPaic\"&@ScriptName&"\" ;[TO BE CONFIGURED !!!CAN'T!!! BE CHANGED DURING EXEC] ;EXCIANGE FILES ELEMENTS Global $_AuThread_SlaveMsgFile = "Slave.Threadmsg" ;[TO BE CONFIGURED !!!CAN'T!!! BE CHANGED DURING EXEC] Global $_AuThread_MasterMsgFile = "Master.Threadmsg" ;[TO BE CONFIGURED !!!CAN'T!!! BE CHANGED DURING EXEC] global $__AuThrd_LockPrefix = ".lock" ;[TO BE CONFIGURED !!!CAN'T!!! BE CHANGED DURING EXEC] global $__AuThrd_ThreadClosed = "_Clo§ed" ;[TO BE CONFIGURED !!!CAN'T!!! BE CHANGED DURING EXEC] global $__AuThrd_DebugActive = false; ;[TO BE CONFIGURED CAN BE CHANGED DURING EXEC] global $__AuThrd_MaxKbFile = 50 ;[TO BE CONFIGURED CAN BE CHANGED DURING EXEC] SIZE AFTER CLOSE & CREATE NEW FILE global $__AuThrd_StartTime = TimerInit(); ;[!DONT CHANGE DURING EXECUTION] ;PRECESS IDS/PIDS global $_AuThread_ImMaster = false ;[!!!DONT CHANGE DURING EXECUTION] global $_AuThread_Master_Pid = @AutoItPID ;[!!!DONT CHANGE DURING EXECUTION] global $_AuThread_CurrentSlaveAlive = 0 ;[!!!DONT CHANGE DURING EXECUTION] global $_AuThread_ExitIfMainNotAlive= TRUE ;[TO BE CONFIGURED CAN BE CHANGED DURING EXEC] ;PIDs COMUNICATION global $_AuThread_MSGPointer ;[!!!DONT CHANGE DURING EXECUTION] global $_AuThread_PendingReadMSG; ;[!!!DONT CHANGE DURING EXECUTION] global $_AuThread_NumberSlaveAlive = 0 ;[!!!DONT CHANGE DURING EXECUTION] ;GENERAL SW USED VARS dim $_AuThread_MSGPointer[2] = [1,0] ;[!!!DONT CHANGE DURING EXECUTION] global $_AuThrd_MasterMsgs = ObjCreate("Scripting.Dictionary") ;[!!!DONT CHANGE DURING EXECUTION] global $_AuThrd_MasterPointers = ObjCreate("Scripting.Dictionary") ;[!!!DONT CHANGE DURING EXECUTION] global $__AuThrd_CloseRequest ;[!!!DONT CHANGE DURING EXECUTION] dim $__AuThrd_CloseRequest[0] ;[!!!DONT CHANGE DURING EXECUTION] global $_AuThrd_AliveThreadName = "" ;[!!!DONT CHANGE DURING EXECUTION] ;================================================================================================================================ #EndRegion ; USER CURRENT# ===================================================================================================================== ;PRIMARY PUBLIC ;_AuThread_Startup ;_AuThread_StartThread ;_AuThread_SendMsg ;_AuThread_ReadNewMsg ;__AuThread_CheckMainAlive ;NO COMMON PUBLIC ;__AuThread_RefreshAliveThreads ;__AuThread_OnExit ;___DBG_Writeline ;================================================================================================================================ #Region #PUBLIC FUNCS# ; #PUBLIC FUNC# =========================================================================================================== ; Name...........: _AuThread_Startup ; Description ...: Startup MultyThreading system ; Fields ........: $DEBUG - =TRUE enable log files =FALSE no log files ; $EraseAllSession - =TRUE close all previews session of same sw (deleting msg folders) =FALSE keep alive sessions using same sw. ; Author ........: King Paic ; Remarks .......: Session files is located in $_AuThread_MainPath ; ========================================================================================================================= Func _AuThread_Startup($DEBUG=false,$EraseAllSession=true) ;sebug startup $__AuThrd_DebugActive=$DEBUG if $__AuThrd_DebugActive Then $_AuThread_SlaveMsgFile=$_AuThread_SlaveMsgFile&".txt" $_AuThread_MasterMsgFile=$_AuThread_MasterMsgFile&".txt" EndIf ;REGISTER EXIT FUNCTION OnAutoItExitRegister("__AuThread_OnExit") ;SLAVE If $CmdLine[0] = 4 And $CmdLine[1] = "--au-thread" Then $_AuThread_Master_Pid=$CmdLine[3] __AuThread_InitSlave($_AuThread_MainPath,$_AuThread_Master_Pid) AdlibRegister("__AuThread_CheckMainAlive",500) if $CmdLine[4]="false" then TraySetState (2) EndIf Call($CmdLine[2]) Exit Else ;MASTER $_AuThread_ImMaster=true; __AuThread_InitMaster($_AuThread_MainPath,$EraseAllSession) AdlibRegister("__AuThread_RefreshAliveThreads",1000) EndIf Return $_AuThread_MainPath EndFunc ; #PUBLIC FUNC# =========================================================================================================== ; Name...........: _AuThread_StartThread ; Description ...: Start new thread ; Fields ........: $sCallback - Name of func of main script where is contained single thread code ; $MainThreadId - PID of master thread ; $MainThreadId - show icon in icon box ; Author ........: King Paic ; Remarks .......: ; ========================================================================================================================== Func _AuThread_StartThread($sCallback, $MainThreadId, $ShowIcon=false) Local $iPID If @Compiled Then $iPID = Run(@ScriptFullPath & ' --au-thread "'&$sCallback&'" "'&$MainThreadId&'" "'&$ShowIcon&'"') Else $iPID = Run(@AutoItExe & ' "' & @ScriptFullPath & '" --au-thread "'&$sCallback&'" "'&$MainThreadId&'" "'&$ShowIcon&'"') EndIf Return $iPID EndFunc ; #PUBLIC FUNC# =========================================================================================================== ; Name...........: _AuThread_SendMsg ; Description ...: Send MSG to another thread or to all threads ; Fields ........: $msg - Body (text) of msg ; $SpecificThread - PID specific thread where send msg, if is -1 then send to all alive threads ; Author ........: King Paic ; Remarks .......: ; ========================================================================================================================== func _AuThread_SendMsg($msg,$SpecificThread=-1) if $_AuThread_ImMaster Then ;;master msg ;single slave msg if $SpecificThread<>-1 then $msgfile=$_AuThread_MainPath&$SpecificThread If FileExists($msgfile) then $msgfile=$_AuThread_MainPath&$SpecificThread&"\"&$_AuThread_MasterMsgFile ;MsgBox(0,"",$msgfile) __MsgSender($msgfile, $msg,500, "Master send MSG to "&$SpecificThread ) EndIf Else ;msg to all __AuThread_RefreshAliveThreads() for $i=1 to $_AuThread_CurrentSlaveAlive[0] $msgfile=$_AuThread_WorkPath&"\"&$_AuThread_CurrentSlaveAlive[$i] If FileExists($_AuThread_MainPath&$_AuThread_CurrentSlaveAlive[$i]) and $_AuThread_CurrentSlaveAlive[$i]<>"" then $msgfile=$_AuThread_WorkPath&$_AuThread_CurrentSlaveAlive[$i]&"\"&$_AuThread_MasterMsgFile __MsgSender($msgfile, $msg,500, "Master send MSG to "&$_AuThread_CurrentSlaveAlive[$i] ) ___DBG_Writeline($_AuThread_CurrentSlaveAlive[$i]&" Master Write:"&$msg) EndIf Next EndIf Else ;;slave msg __MsgSender($_AuThread_WorkPath&$_AuThread_SlaveMsgFile, $msg,500, "Slave Send Msg To Master" ) EndIf EndFunc ; #PUBLIC FUNC# =========================================================================================================== ; Name...........: _AuThread_ReadNewMsg ; Description ...: Read his missing MSG queue from other threads ; Fields ........: $SpecificThread - PID of specific thread where you want read read queue, if is -1 is reading queue from all thread ; Author ........: King Paic ; Remarks .......: IS RETURNING AN ARRAY WHERE [0] IS THE SENDER PID [1] IS THE MSG ; ========================================================================================================================== func _AuThread_ReadNewMsg($SpecificThread=-1) $SpecificThread=String ( $SpecificThread) if $_AuThread_ImMaster Then AdlibUnRegister("__AuThread_RefreshAliveThreads") __AuThread_RefreshAliveThreads() ;;--------------------MASTER MSG READ------------------------- ;single slave msg if ($SpecificThread<>-1) Then $slavefile= $_AuThread_WorkPath&$SpecificThread&"\"&$_AuThread_SlaveMsgFile if __islocked($slavefile) Then SetError(-1) Return -1 EndIf $filepointer=$_AuThrd_MasterPointers.item($SpecificThread) $MsgQueue=__MsgReader($slavefile,$filepointer,500,"Master read SINGLE") $_AuThrd_MasterPointers.item($SpecificThread)=$MsgQueue[0] ;i read last msg because the process is closed __DeleteClosed_SlavePid($SpecificThread) IF UBound($MsgQueue[1])>0 THEN $_AuThrd_MasterMsgs.item($SpecificThread)=$MsgQueue[1] AdlibRegister("__AuThread_RefreshAliveThreads",1000) Return $MsgQueue[1] Else $_AuThrd_MasterMsgs.item($SpecificThread,"") AdlibRegister("__AuThread_RefreshAliveThreads",1000) Return "" EndIf Else ;ALLSLAVE slave msg dim $ALLMSQUEUE[0]; $NewMsgfromPid=0 for $i=1 to $_AuThread_CurrentSlaveAlive[0] $msgfile=$_AuThread_WorkPath&$_AuThread_CurrentSlaveAlive[$i] If FileExists($_AuThread_MainPath&$_AuThread_CurrentSlaveAlive[$i]) then $slavefile= $_AuThread_WorkPath&$_AuThread_CurrentSlaveAlive[$i]&"\"&$_AuThread_SlaveMsgFile if __islocked($slavefile) Then $_AuThrd_MasterMsgs.item($_AuThread_CurrentSlaveAlive[$i])=-1 EndIf $filepointer=$_AuThrd_MasterPointers.item($_AuThread_CurrentSlaveAlive[$i]) $MsgQueue=__MsgReader($slavefile,$filepointer,500,"Master read ALL") $_AuThrd_MasterPointers.item($_AuThread_CurrentSlaveAlive[$i])=$MsgQueue[0] ;i read last msg because the process is closed __DeleteClosed_SlavePid($_AuThread_CurrentSlaveAlive[$i]) IF UBound($MsgQueue[1])>0 THEN $_AuThrd_MasterMsgs.item($_AuThread_CurrentSlaveAlive[$i])=$MsgQueue[1] $NewMsgfromPid=$NewMsgfromPid+1; redim $ALLMSQUEUE[$NewMsgfromPid][2] $ALLMSQUEUE[($NewMsgfromPid-1)][0]=$_AuThread_CurrentSlaveAlive[$i] $ALLMSQUEUE[($NewMsgfromPid-1)][1]=$MsgQueue[1] EndIf EndIf Next ;no one reads if $NewMsgfromPid = 0 Then $ALLMSQUEUE=-1 EndIf $_AuThread_PendingReadMSG=$ALLMSQUEUE AdlibRegister("__AuThread_RefreshAliveThreads",1000) Return $_AuThread_PendingReadMSG EndIf Else ;;--------------------SLAVE MSG READ------------------------- if __islocked($_AuThread_WorkPath&$_AuThread_MasterMsgFile) Then SetError(-1) Return -1 EndIf $MsgQueue=__MsgReader($_AuThread_WorkPath&$_AuThread_MasterMsgFile,$_AuThread_MSGPointer,500,"Slave Read") $_AuThread_MSGPointer=$MsgQueue[0] IF UBound($MsgQueue[1])>0 THEN Return $MsgQueue[1] Else Return "" EndIf EndIf EndFunc ; PUBLIC FUNC ============================================================================================================= ; Name...........: __AuThread_CheckMainAlive ; Description ...: USED ONLY BY SLAVES is used to check if main PID is alive or not ; Fields ........: $exitifnot - =TRUE start safe exiting sequence =FALSE return only FALSE if noth exist or TRUE is existing ; Author ........: King Paic ; Remarks .......: ; ========================================================================================================================== FUNC __AuThread_CheckMainAlive() if not ProcessExists($_AuThread_Master_Pid) then ___DBG_Writeline("Main Die") if $_AuThread_ExitIfMainNotAlive then __AuThread_OnExit() Else return False endif EndIf return true EndFunc #EndRegion #Region PUBLIC BUT NO COMMON FUNCS ; NO COMMON func =========================================================================================================== ; Name...........: __AuThread_RefreshAliveThreads ; Description ...: Check and refresh the list of alive threads SLAVES ; Author ........: King Paic ; Remarks .......: $_AuThread_CurrentSlaveAlive is returning array of all PID of alive SLAVES ; ========================================================================================================================== func __AuThread_RefreshAliveThreads() local $pathtocheck=StringLeft($_AuThread_MainPath,StringLen($_AuThread_MainPath)-1) ;MsgBox(0,"",$pathtocheck,0.5) $__AuThrd_CloseRequest="" dim $__AuThrd_CloseRequest[0] $_AuThread_NumberSlaveAlive=0 $_AuThread_CurrentSlaveAlive=_FileListToArray($pathtocheck,"*.",2) dim $_AuThrd_AliveThreadName[0] ; _ArrayDisplay($_AuThread_CurrentSlaveAlive) if IsArray($_AuThread_CurrentSlaveAlive) then for $i=1 to $_AuThread_CurrentSlaveAlive[0] ; _ArrayDisplay($_AuThread_CurrentSlaveAlive) ;doublecheck process exist $processname=_ProcessGetName ( $_AuThread_CurrentSlaveAlive[$i] ) $dirlosed=StringInStr($_AuThread_CurrentSlaveAlive[$i],$__AuThrd_ThreadClosed)<>0 if (not ProcessExists($_AuThread_CurrentSlaveAlive[$i]) or not ($processname=@ScriptName or StringInStr(StringLower ($processname),"autoit") <>0 ) or $dirlosed) then ;process closed or folder is closed redim $__AuThrd_CloseRequest[UBound($__AuThrd_CloseRequest)+1] $__AuThrd_CloseRequest[UBound($__AuThrd_CloseRequest)-1]=$_AuThread_CurrentSlaveAlive[$i] $_AuThread_CurrentSlaveAlive[$i]=StringReplace($_AuThread_CurrentSlaveAlive[$i],$__AuThrd_ThreadClosed,"") Else $_AuThread_NumberSlaveAlive=$_AuThread_NumberSlaveAlive+1 $_AuThread_CurrentSlaveAlive[$i]=StringReplace($_AuThread_CurrentSlaveAlive[$i],$__AuThrd_ThreadClosed,"") redim $_AuThrd_AliveThreadName[UBound($_AuThrd_AliveThreadName)+1] $_AuThrd_AliveThreadName[UBound($_AuThrd_AliveThreadName)-1]=$_AuThread_CurrentSlaveAlive[$i] ;;ADDING NEW SLAVE (close when read msg*) if not $_AuThrd_MasterMsgs.Exists($_AuThread_CurrentSlaveAlive[$i]) Then dim $pointer[2]=[1,0] $_AuThrd_MasterPointers.Add(($_AuThread_CurrentSlaveAlive[$i]),$pointer) $_AuThrd_MasterMsgs.Add(($_AuThread_CurrentSlaveAlive[$i]),"") EndIf endif Next ;_ArrayDisplay($_AuThread_CurrentSlaveAlive) Else dim $_AuThread_CurrentSlaveAlive[1]=[0] EndIf if not IsArray($_AuThread_CurrentSlaveAlive) Then dim $_AuThread_CurrentSlaveAlive[1]=[0] EndIf Return $_AuThread_CurrentSlaveAlive[0] EndFunc ; NO COMMON func =========================================================================================================== ; Name...........: ___DBG_Writeline ; Description ...: Write some debug string using internal debugging files ; Fields ........: $text - Text to log ; $destfile - Possible different file where write log ; Author ........: King Paic ; Remarks .......: ; ========================================================================================================================== func ___DBG_Writeline($text, $destfile="") if $__AuThrd_DebugActive Then ConsoleWrite($text&@cr); if $destfile = "" then FileWriteLine($_AuThread_MainPath&"_Log.txt",@MSEC&"."&@SEC&"."&@min&"."&@HOUR&"."&@YDAY&"@"&@AutoItPID&": "&$text) Else FileWriteLine($_AuThread_MainPath&$destfile&"_Log.txt",@MSEC&"."&@SEC&"."&@min&"."&@HOUR&"."&@YDAY&"@"&@AutoItPID&": "&$text) endif EndIf EndFunc #EndRegion ; private func =========================================================================================================== ; Name...........: __AuThread_InitMaster ; Description ...: Init master therad msg system & values ; Author ........: King Paic ; Remarks .......: is form _AuThread_Startup who decide if is master o slave ; ========================================================================================================================== Func __AuThread_InitMaster($MainPath,$eraseSesion=true) if $eraseSesion Then $rem=DirRemove ($_AuThread_MainPath,1) if $rem = 0 and FileExists($_AuThread_MainPath) then MsgBox(16,"Can't reset folder", "I can't delete:"& $_AuThread_MainPath) EndIf EndIf $_AuThread_MainPath=$MainPath&@AutoItPID DirRemove($_AuThread_MainPath,1) if not FileExists ($_AuThread_MainPath) Then DirCreate($_AuThread_MainPath) EndIf $_AuThread_MainPath=$_AuThread_MainPath&"\" $_AuThread_WorkPath=$_AuThread_MainPath EndFunc ; private func =========================================================================================================== ; Name...........: __AuThread_InitSlave ; Description ...: Init master therad msg system & values ; Author ........: King Paic ; Remarks .......: is form _AuThread_Startup who decide if is master o slave ; ========================================================================================================================== Func __AuThread_InitSlave($MainPath, $MasterId) $_AuThread_MainPath=$MainPath&$MasterId $_AuThread_WorkPath=$MainPath&$MasterId&"\"&@AutoItPID DirRemove($_AuThread_WorkPath,1) ;reinit if just existing foolder if FileExists ($_AuThread_WorkPath) Then DirRemove($_AuThread_WorkPath,1) EndIf ;MsgBox(0,"",$_AuThread_WorkPath) DirCreate($_AuThread_WorkPath) $_AuThread_WorkPath=$_AuThread_WorkPath&"\" ; _AuThread_SendMsg("ALIVE"&@MSEC&"."&@SEC&"."&@min&"."&@HOUR&"."&@YDAY&"@"&@AutoItPID) EndFunc #Region PRIVATE FUNCTION / CORE ; private func =========================================================================================================== ; Name...........: __AuThread_OnExit ; Description ...: close propely threads ; Author ........: King Paic ; Remarks .......: ; ========================================================================================================================== func __AuThread_OnExit() local $pathtocheck=StringLeft($_AuThread_WorkPath,StringLen($_AuThread_WorkPath)-1) if not $_AuThread_ImMaster Then if $__AuThrd_DebugActive Then ___DBG_Writeline(@AutoItPID&" CUTTED OF") _AuThread_SendMsg( @AutoItPID&" EXIT:"&@MSEC&"."&@SEC&"."&@min&"."&@HOUR&"."&@YDAY & " After:"&TimerDiff($__AuThrd_StartTime)/1000&"s") DirMove($pathtocheck,$pathtocheck&$__AuThrd_ThreadClosed,1) Else ;DirRemove($pathtocheck,1) EndIf EndIf Exit ProcessClose(@autoitpid) EndFunc ;MESSAGE SENDER CORE Func __MsgSender($file, $msg,$TimeForceskypIfLocked=500, $LockReason="" ) __WaitEndLockFile($file,$TimeForceskypIfLocked,$LockReason) __ResetFileIfToobig($file,$__AuThrd_MaxKbFile) $msg=StringReplace($msg,@CR,"§") $msg=StringReplace($msg,@CRlf,"§") FileWriteLine($file,$msg) __Unlock($file) EndFunc ;MAG READER CORE Func __MsgReader($file, $curentPointer,$TimeForceskypIfLocked=500, $LockReason="") dim $return[2]=[$curentPointer,""]; dim $msgs[0] $filesize=FileGetSize ( $file )/1024 if $filesize <> $curentPointer[1] and not @error then if $filesize<$curentPointer[1] then $curentPointer[0]=1 if IsArray($_AuThread_PendingReadMSG) then redim $_AuThread_PendingReadMSG[0] Else Dim $_AuThread_PendingReadMSG[0] EndIf Else $curentPointer[1]=$filesize ;resetted file start from begin EndIf ;read all pending msg readin each line __WaitEndLockFile($file,$TimeForceskypIfLocked,$LockReason) while (true) $msg=FileReadLine ( $file,$curentPointer[0] ) if not @error then $msg=StringReplace($msg,"§",@CRLF) ReDim $msgs[ubound($msgs)+1] $msgs[ubound($msgs)-1]=$msg $curentPointer[0] = $curentPointer[0] + 1; Else ExitLoop EndIf WEnd __Unlock($file) $return[0]=$curentPointer $return[1]=$msgs endif Return $return EndFunc ;WAIT UNLOCK SPECIFIC FILE FOR BE WRITTEN Func __WaitEndLockFile($file,$TimeForceskyp=500,$reason="") local $time =TimerInit() local $lockFile=$file&$__AuThrd_LockPrefix if $__AuThrd_DebugActive Then $lockFile=$lockFile&".txt" EndIf While (FileExists($lockFile)) if (TimerDiff($time)>$TimeForceskyp) Then ___DBG_Writeline("!FORCE UNLOCK! " & $file&" "&$reason) FileDelete($lockFile) ExitLoop EndIf Sleep(10+random(10)) WEnd FileWrite($lockFile,$reason) EndFunc ;UNLOC FILE Func __Unlock($file) local $lockFile=$file&$__AuThrd_LockPrefix if $__AuThrd_DebugActive Then $lockFile=$lockFile&".txt" EndIf FileDelete($lockFile) EndFunc ;CHECK IF FILE IS LOCKED func __islocked($file) local $lockFile=$file&$__AuThrd_LockPrefix if $__AuThrd_DebugActive Then $lockFile=$lockFile&".txt" EndIf Return FileExists($lockFile) or not FileExists($file) EndFunc ;RESET FILE IF IS TOO BIG func __ResetFileIfToobig($file,$limitkb) if (FileGetSize ( $file )/1024 )>$limitkb Then return FileDelete($file) EndIf return false EndFunc ;DELETED FIES RELATIVE TO CLOSED PID func __DeleteClosed_SlavePid($pid) if not $__AuThrd_DebugActive then $find=_ArraySearch ($__AuThrd_CloseRequest, $pid) ; _ArrayDisplay($__AuThrd_CloseRequest) if $find>-1 Then DirRemove($_AuThread_WorkPath&$pid,1) ; MsgBox(0,"remove",$_AuThread_WorkPath&$pid) if $_AuThrd_MasterMsgs.Exists($pid) Then $_AuThrd_MasterMsgs.Remove($pid) $_AuThrd_MasterPointers.Remove($pid) EndIf EndIf EndIf EndFunc #EndRegion