#include-once #include #include #include #Region Global Variables and Constants Global Const $STILL_ACTIVE = 0x103 Global Enum $MULTIPROCESS_WAITING = -5, $MULTIPROCESS_RUNNING, $MULTIPROCESS_FINISH, $MULTIPROCESS_CANCEL, $MULTIPROCESS_ERROR Global $i__MultiProcess_Adlibregistred = 0 Global $a__MultiProcessJobs[1][3] = [[0]], $i__MultiProcess_LastJobId = 0, $a__MultiProcessItems[1][2] = [[0]], $a__MultiProcessEvents[10] #EndRegion Global Variables and Constants #Region Functions list ; #CURRENT# ===================================================================================================================== ; _MultiProcess_AddTask ; _MultiProcess_CancelTask ; _MultiProcess_Close ; _MultiProcess_Create ; _MultiProcess_GetJobId ; _MultiProcess_GetResult ; _MultiProcess_GetState ; _MultiProcess_GetTask ; _MultiProcess_Run ; _MultiProcess_SetOnEvent ; _MultiProcess_WaitClose ; =============================================================================================================================== ; #INTERNAL_USE_ONLY#============================================================================================================ ; __MultiProcess_Adlib ; __MultiProcess_Event ; __MultiProcess_GetTaskId ; __MultiProcess_MonitorTasks ; =============================================================================================================================== #EndRegion Functions list ; #FUNCTION# ==================================================================================================================== ; Name ..........: _MultiProcess_AddTask ; Description ...: Adds a task to a job. A task is an external program to run. ; Syntax ........: _MultiProcess_AddTask($sProgram[, $sWorkingDir = @WorkingDir[, $iShowFlag = @SW_SHOW[, $iJobId = -1]]]) ; Parameters ....: $sProgram - The full path of the program. ; $sWorkingDir - [optional] The working directory. Blank ("") uses the current working directory. This ; is not the path to the program. ; $iShowFlag - [optional] The "show" flag of the executed program: ; @SW_HIDE = Hidden window (or Default keyword) ; @SW_MINIMIZE = Minimized window ; @SW_MAXIMIZE = Maximized window ; $iJobId - [optional] ID of the job to which the task belong, or -1 for the last created job. ; Return values .: Success - ID of the task. ; Failure - 0 and set @error to non-sero value. ; Author ........: jguinch ; =============================================================================================================================== Func _MultiProcess_AddTask($sProgram, $sWorkingDir = @WorkingDir, $iShowFlag = @SW_SHOW, $iJobId = -1) If $iJobId = -1 Then If Not $i__MultiProcess_LastJobId Then Return SetError(1, 0, 0) $iJobId = $i__MultiProcess_LastJobId ElseIf $iJobId < 1 Or $iJobId >= UBound($a__MultiProcessItems) Then Return SetError(1, 0, 0) EndIf If $a__MultiProcessItems[$iJobId][1] Then Return SetError(2, 0, 0) Local $iJobRowId = $a__MultiProcessItems[$iJobId][0] Local $iTaskId = UBound($a__MultiProcessItems) Local $aTasks = $a__MultiProcessJobs[$iJobRowId][1] Local $iTaskRowId = $aTasks[0][0] + 1 ReDim $a__MultiProcessItems[$iTaskId + 1][2] Redim $aTasks[$iTaskRowId + 1][5] $aTasks[$iTaskRowId ][0] = $MULTIPROCESS_WAITING $aTasks[$iTaskRowId ][1] = -1 $aTasks[$iTaskRowId ][2] = $sProgram $aTasks[$iTaskRowId ][3] = $sWorkingDir $aTasks[$iTaskRowId ][4] = $iShowFlag $aTasks[0][0] = $iTaskRowId $a__MultiProcessItems[0][0] = $iTaskId $a__MultiProcessItems[$iTaskId][0] = $iJobRowId $a__MultiProcessItems[$iTaskId][1] = $iTaskRowId If $aTasks[0][1] = "" Then $aTasks[0][1] = 0 If Not $aTasks[0][2] Then $aTasks[0][2] = 1 $a__MultiProcessJobs[$iJobRowId][1] = $aTasks __MultiProcess_Event($MULTIPROCESS_WAITING, $iTaskId) Return $iTaskId EndFunc ; ===> _MultiProcess_AddTask ; #FUNCTION# ==================================================================================================================== ; Name ..........: _MultiProcess_CancelTask ; Description ...: Cancels a running task or prevent its execution. ; Syntax ........: _MultiProcess_CancelTask($iTaskId) ; Parameters ....: $iTaskId - The task ID returned by _MultiProcess_AddTask. ; Return values .: Success - 1 ; Failure - 0 and set @error to non-sero value. ; Author ........: jguinch ; =============================================================================================================================== Func _MultiProcess_CancelTask($iTaskId) If $iTaskId < 1 Or $iTaskId >= UBound($a__MultiProcessItems) Then Return SetError(1, 0, 0) Local $iJobRowId = $a__MultiProcessItems[$iTaskId][0] Local $iTaskRowId = $a__MultiProcessItems[$iTaskId][1] If Not $iTaskRowId Then Return SetError(2, 0, 0) Local $aTasks = $a__MultiProcessJobs[$iJobRowId][1] Local $iState = _MultiProcess_GetState($iTaskId) If $iState <> $MULTIPROCESS_WAITING And $iState <> $MULTIPROCESS_RUNNING Then Return SetError(3, 0, 1) If $aTasks[$iTaskRowId][0] = $MULTIPROCESS_RUNNING Then Local $iPid = _WinAPI_GetProcessID($aTasks[$iTaskRowId][1]) If Not $iPid Then Return SetError(4, 0, 0) ProcessClose($iPid) If @error Then Return SetError(5, 0, 0) _WinAPI_CloseHandle($aTasks[$iTaskRowId][1]) $aTasks[$iTaskRowId][0] = $MULTIPROCESS_CANCEL $aTasks[$iTaskRowId][1] = -1 $aTasks[0][1] -= 1 $a__MultiProcessJobs[$iJobRowId][1] = $aTasks __MultiProcess_Event($MULTIPROCESS_CANCEL, $iTaskId) Else SetError(6, 0, 1) EndIf Return 1 EndFunc ; ===> _MultiProcess_CancelTask ; #FUNCTION# ==================================================================================================================== ; Name ..........: _MultiProcess_Close ; Description ...: Closes a MultiProcess job ; Syntax ........: _MultiProcess_Close([$iForce = False[, $iJobId = -1]]) ; Parameters ....: $iForce - [optional] Set it to 1 to force the job to close . Default is 0. ; $iJobId - [optional] The Job ID returned by _MultiProcess_Create, or -1 for the last created job. ; Return values .: Success - 1 ; Failure - 0 and set @error to non-sero value. ; Author ........: jguinch ; =============================================================================================================================== Func _MultiProcess_Close($iForce = False, $iJobId = -1) If $iJobId = -1 Then If Not $i__MultiProcess_LastJobId Then Return SetError(1, 0, 0) $iJobId = $i__MultiProcess_LastJobId ElseIf $iJobId < 1 Or $iJobId >= UBound($a__MultiProcessJobs) Then Return SetError(1, 0, 0) EndIf Local $aTasks Local $iState, $iTaskRowId, $iError = 0, $iResult = 0 Local $iJobRowId = $a__MultiProcessItems[$iJobId][0] If _MultiProcess_GetState($iJobId) <> $MULTIPROCESS_RUNNING Then Return SetError(2, 0, 0) Local $iMaxTasks = $a__MultiProcessJobs[$iJobRowId][2] $a__MultiProcessJobs[$iJobRowId][2] = 0 If $iForce Then For $iItemId = 1 To $a__MultiProcessItems[0][0] $iState = _MultiProcess_GetState($iItemId) If $a__MultiProcessItems[$iItemId][0] = $iJobRowId And $a__MultiProcessItems[$iItemId][1] And $iState = $MULTIPROCESS_RUNNING Then $iTaskRowId = $a__MultiProcessItems[$iItemId][1] _MultiProcess_CancelTask($iItemId) If @error Then $a__MultiProcessJobs[$iJobRowId][2] = $iMaxTasks $iError = 3 ExitLoop EndIf EndIf Next Else Do Until ($a__MultiProcessJobs[$iJobRowId][1])[0][1] = 0 $a__MultiProcessJobs[$iJobRowId][0] = $MULTIPROCESS_CANCEL __MultiProcess_Event($MULTIPROCESS_CANCEL, $iJobId) $iResult = 1 EndIf Return SetError($iError, 0, $iResult) EndFunc ; ===> _MultiProcess_Close ; #FUNCTION# ==================================================================================================================== ; Name ..........: _MultiProcess_Create ; Description ...: Create a MultiProcess job. ; Syntax ........: _MultiProcess_Create() ; Parameters ....: None ; Return values .: Success - ID of the job. ; Failure - 0 and set @error to non-sero value. ; Author ........: jguinch ; =============================================================================================================================== Func _MultiProcess_Create() Local $iJobId = UBound($a__MultiProcessItems) Local $iJobRowId = UBound($a__MultiProcessJobs) Local $aTasks[1][5] = [[0]] ReDim $a__MultiProcessJobs[$iJobRowId + 1][3] ReDim $a__MultiProcessItems[$iJobId + 1][2] $a__MultiProcessItems[0][0] = $iJobId $a__MultiProcessItems[$iJobId][0] = $iJobRowId $a__MultiProcessJobs[0][0] = $iJobRowId $a__MultiProcessJobs[$iJobRowId][0] = $MULTIPROCESS_WAITING $a__MultiProcessJobs[$iJobRowId][1] = $aTasks $i__MultiProcess_LastJobId = $iJobId __MultiProcess_Event($MULTIPROCESS_WAITING, $iJobId) Return $iJobId EndFunc ; ===> _MultiProcess_Create ; #FUNCTION# ==================================================================================================================== ; Name ..........: _MultiProcess_GetJobId ; Description ...: Gets the job ID from a task ID. ; Syntax ........: _MultiProcess_GetJobId($iTaskId) ; Parameters ....: $iTaskId - The task ID returned by _MultiProcess_AddTask. ; Return values .: Success - The job ID. ; Failure - 0 and set @error to non-sero value. ; Author ........: jguinch ; =============================================================================================================================== Func _MultiProcess_GetJobId($iTaskId) If $iTaskId < 1 Or $iTaskId >= UBound($a__MultiProcessItems) Then Return SetError(1, 0, 0) Local $iJobRowId = $a__MultiProcessItems[$iTaskId][0] For $i = $iTaskId To 1 Step -1 If $a__MultiProcessItems[$i][0] = $iJobRowId And Not $a__MultiProcessItems[$i][1] Then Return $i Next Return 0 EndFunc ; ===> _MultiProcess_GetJobId ; #FUNCTION# ==================================================================================================================== ; Name ..........: _MultiProcess_GetResult ; Description ...: Gets the results of a job, or the result of a task. ; Syntax ........: _MultiProcess_GetResult($iItemId) ; Parameters ....: $iItemId - [optional] A job ID or a task ID returned by _MultiProcess_Create or ; _MultiProcess_AddTask. Use -1 for the last created job. ; Return values .: Success - If $iItemId is a job ID, returns a 2D array containing the result for each task for the ; specified job ID. See remarks ; $array[0][0] : task ID ; $array[0][1] : task result ; - If $iItemId is a task ID, returns the result of the task. ; Failure - 0 and set @error to non-sero value. ; Author ........: jguinch ; Remarks .......: The result of a task is the exit code returned by its process. If the process is not finished, the result will ; be set to a negative value corresponding to a MultiProcess state ($MULTIPROCESS_XXX) ; =============================================================================================================================== Func _MultiProcess_GetResult($iItemId = -1) If $iItemId = -1 Then If Not $i__MultiProcess_LastJobId Then Return SetError(1, 0, 0) $iItemId = $i__MultiProcess_LastJobId ElseIf $iItemId < 1 Or $iItemId >= UBound($a__MultiProcessItems) Then Return SetError(1, 0, 0) EndIf Local $iJobRowId = $a__MultiProcessItems[$iItemId][0] Local $iTaskRowId = $a__MultiProcessItems[$iItemId][1] Local $aTasks = $a__MultiProcessJobs[$iJobRowId][1] Local $iError = 0, $vResult[1], $n = 0 If $iTaskRowId Then Local $iRet = ($a__MultiProcessJobs[$iJobRowId][1])[$iTaskRowId][1] If $iRet < 0 Then $iError = 3 $vResult = ($a__MultiProcessJobs[$iJobRowId][1])[$iTaskRowId][0] Else $vResult = $iRet EndIf Else Redim $vResult[$aTasks[0][0]][2] For $iItemId = 1 To $a__MultiProcessItems[0][0] If $a__MultiProcessItems[$iItemId][0] = $iJobRowId And $a__MultiProcessItems[$iItemId][1] Then $iTaskRowId = $a__MultiProcessItems[$iItemId][1] $vResult[$n][0] = $iItemId $vResult[$n][1] = _MultiProcess_GetResult($iItemId) $n += 1 EndIf Next EndIf Return SetError($iError, 0, $vResult) EndFunc ; ===> _MultiProcess_GetResult ; #FUNCTION# ==================================================================================================================== ; Name ..........: _MultiProcess_GetState ; Description ...: Gets the state of a job or a task. ; Syntax ........: _MultiProcess_GetState($iItemId) ; Parameters ....: $iItemId - A job ID or a task ID returned by _MultiProcess_Create or _MultiProcess_AddTask. ; Return values .: Success - The state of the specified item. States are defined in the $MULTIPROCESS constants ; enumaration. ; Failure - 0 and set @error to non-sero value. ; Author ........: jguinch ; =============================================================================================================================== Func _MultiProcess_GetState($iItemId) Local $iResult If $iItemId < 1 Or $iItemId >= UBound($a__MultiProcessItems) Then Return SetError(1, 0, 0) Local $iJobRowId = $a__MultiProcessItems[$iItemId][0] Local $iTaskRowId = $a__MultiProcessItems[$iItemId][1] If $iTaskRowId Then $iResult = ($a__MultiProcessJobs[$iJobRowId][1])[$iTaskRowId][0] Else $iResult = $a__MultiProcessJobs[$iJobRowId][0] EndIf Return $iResult EndFunc ; ===> _MultiProcess_GetState ; #FUNCTION# ==================================================================================================================== ; Name ..........: _MultiProcess_GetTask ; Description ...: Gets the task infos for a give task ; Syntax ........: _MultiProcess_GetTask($iTaskId) ; Parameters ....: $iTaskId - The task ID returned by _MultiProcess_AddTask. ; Return values .: None ; Author ........: Your Name ; Modified ......: ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func _MultiProcess_GetTask($iTaskId) Local $aRet[3] If $iTaskId < 1 Or $iTaskId >= UBound($a__MultiProcessItems) Then Return SetError(1, 0, 0) Local $iJobRowId = $a__MultiProcessItems[$iTaskId][0] Local $iTaskRowId = $a__MultiProcessItems[$iTaskId][1] Local $aTasks = $a__MultiProcessJobs[$iJobRowId][1] $aRet[0] = $aTasks[$iTaskRowId][2] $aRet[1] = $aTasks[$iTaskRowId][3] $aRet[2] = $aTasks[$iTaskRowId][4] Return $aRet EndFunc ; ===> _MultiProcess_GetTask ; #FUNCTION# ==================================================================================================================== ; Name ..........: _MultiProcess_Run ; Description ...: Runs a MultiProcess job. ; Syntax ........: _MultiProcess_Run([$iMaxTasks = 10[, $iJobId = -1]]) ; Parameters ....: $iMaxTasks - [optional] Number of coucurrent process that MultiProcess can support. Default is 10. ; $iJobId - [optional] The job ID returned by _MultiProcess_Create, or -1 for the last created job. ; Return values .: Success - 1 ; Failure - 0 and set @error to non-sero value. ; Author ........: jguinch ; =============================================================================================================================== Func _MultiProcess_Run($iMaxTasks = 10, $iJobId = -1) If $iJobId = -1 Then If Not $i__MultiProcess_LastJobId Then Return SetError(1, 0, 0) $iJobId = $i__MultiProcess_LastJobId ElseIf $iJobId < 1 Or $iJobId >= UBound($a__MultiProcessJobs) Then Return SetError(1, 0, 0) EndIf Local $iJobRowId = $a__MultiProcessItems[$iJobId][0] If $iMaxTasks < 1 Then Return SetError(2, 0, 0) If $a__MultiProcessJobs[$iJobRowId][0] = $MULTIPROCESS_RUNNING Then Return SetError(3, 0, 0) $a__MultiProcessJobs[$iJobRowId][0] = $MULTIPROCESS_RUNNING $a__MultiProcessJobs[$iJobRowId][2] = $iMaxTasks If Not $i__MultiProcess_Adlibregistred Then $i__MultiProcess_Adlibregistred = 1 AdlibRegister("__MultiProcess_Adlib") EndIf __MultiProcess_Event($MULTIPROCESS_RUNNING, $iJobId) Return 1 EndFunc ; ===> _MultiProcess_Run ; #FUNCTION# ==================================================================================================================== ; Name ..........: _MultiProcess_SetOnEvent ; Description ...: Defines a user function to be called when the state of a job or a task matches with the specified state. ; Syntax ........: _MultiProcess_SetOnEvent($iMultiProcessState, $sFuncName) ; Parameters ....: $iMultiProcessState - The job or task state. States are defined in the $MULTIPROCESS constants. ; $sFuncName - The name of the user function to call. See remarks. ; Return values .: Success - 1 ; Failure - 0 and set @error to non-sero value. ; Author ........: jguinch ; Remarks .......: To make the user function workable you have to define it with 2 function parameters. ; When the user function is called then these 2 parameters have the following values: ; iMultiProcessState Job or task state. States are defined in the $MULTIPROCESS constants. ; iItemId ID of the job or task to which the state refers. ; =============================================================================================================================== Func _MultiProcess_SetOnEvent($iMultiProcessState, $sFuncName) If $iMultiProcessState < $MULTIPROCESS_WAITING Or $iMultiprocessState > $MULTIPROCESS_ERROR Then Return SetError(1, 0, 0) Local $iIndex = -1 - $iMultiProcessState $a__MultiProcessEvents[$iIndex] = $sFuncName Return 1 EndFunc ; ===> _MultiProcess_SetOnEvent ; #FUNCTION# ==================================================================================================================== ; Name ..........: _MultiProcess_WaitClose ; Description ...: Pauses script execution while a given job is running. ; Syntax ........: _MultiProcess_WaitClose([$iJobId = -1]) ; Parameters ....: $iJobId - [optional] The job ID returned by _MultiProcess_Create, or -1 for the last created job. ; Return values .: Success - 1 ; Failure - 0 and set @error to non-sero value. ; Author ........: jguinch ; =============================================================================================================================== Func _MultiProcess_WaitClose($iJobId = -1) If $iJobId = -1 Then If Not $i__MultiProcess_LastJobId Then Return SetError(1, 0, 0) $iJobId = $i__MultiProcess_LastJobId ElseIf $iJobId < 1 Or $iJobId >= UBound($a__MultiProcessJobs) Then Return SetError(1, 0, 0) EndIf Do Until (_MultiProcess_GetState($iJobId) = $MULTIPROCESS_FINISH) Or (_MultiProcess_GetState($iJobId) = $MULTIPROCESS_CANCEL) If @error Then Return SetError(@error, 0, 0) Return 1 EndFunc ; ===> _MultiProcess_WaitClose ; # Internal use only ###################################################################################### Func __MultiProcess_Adlib() Local $iCountJobsRunning = 0 For $iJobRowId = 1 To $a__MultiProcessJobs[0][0] If $a__MultiProcessJobs[$iJobRowId][0] = $MULTIPROCESS_RUNNING Then $iCountJobsRunning += 1 __MultiProcess_MonitorTasks($iJobRowId, $a__MultiProcessJobs[$iJobRowId][1]) EndIf Next If Not $iCountJobsRunning Then AdlibUnRegister("__MultiProcess_Adlib") Return 1 EndFunc ; ===> __MultiProcess_Adlib Func __MultiProcess_Event($iMultiProcessState, $iItemId) Local $iIndex = -1 - $iMultiprocessState If Not $a__MultiProcessEvents[$iIndex] Then Return 0 Local $vRet = Call($a__MultiProcessEvents[$iIndex], $iMultiProcessState, $iItemId) Return SetError(@error, @extended, $vRet) EndFunc ; ===> __MultiProcess_Event Func __MultiProcess_GetTaskId($iJobRowId, $iTaskRowId) For $i = 1 To $a__MultiProcessItems[0][0] If $a__MultiProcessItems[$i][0] = $iJobRowId And $a__MultiProcessItems[$i][1] = $iTaskRowId Then Return $i Next Return 0 EndFunc ; ===> __MultiProcess_GetTaskId Func __MultiProcess_MonitorTasks($iJobRowId, ByRef $aTasks) Local $iMaxTasks = $a__MultiProcessJobs[$iJobRowId][2], $iExitCode, $iJobId, $iTaskId Local $iPid, $hProcess, $iCountRunning = 0 For $iTaskItemId = $aTasks[0][2] To $aTasks[0][0] $iTaskId = __MultiProcess_GetTaskId($iJobRowId, $iTaskItemId) $iJobId = _MultiProcess_GetJobId($iTaskId) Switch $aTasks[$iTaskItemId][0] Case $MULTIPROCESS_WAITING If $aTasks[0][1] < $iMaxTasks Then $iPid = Run($aTasks[$iTaskItemId][2], $aTasks[$iTaskItemId][3], $aTasks[$iTaskItemId][4]) If @error Then $aTasks[$iTaskItemId][0] = $MULTIPROCESS_ERROR $aTasks[$iTaskItemId][1] = -1 __MultiProcess_Event($MULTIPROCESS_ERROR, $iTaskId) Else $aTasks[$iTaskItemId][0] = $MULTIPROCESS_RUNNING $aTasks[$iTaskItemId][1] = _WinAPI_OpenProcess($PROCESS_QUERY_LIMITED_INFORMATION, 0, $iPID) $aTasks[0][1] += 1 $iCountRunning += 1 __MultiProcess_Event($MULTIPROCESS_RUNNING, $iTaskId) EndIf EndIf Case $MULTIPROCESS_RUNNING $iExitCode = _WinAPI_GetExitCodeProcess($aTasks[$iTaskItemId][1]) If $iExitCode = $STILL_ACTIVE Then If Not $iCountRunning Then $aTasks[0][2] = $iTaskItemId $iCountRunning += 1 Else _WinAPI_CloseHandle($aTasks[$iTaskItemId][1]) $aTasks[$iTaskItemId][0] = $MULTIPROCESS_FINISH $aTasks[$iTaskItemId][1] = $iExitCode $aTasks[0][1] -= 1 __MultiProcess_Event($MULTIPROCESS_FINISH, $iTaskId) EndIf EndSwitch Next If Not $iCountRunning Then $a__MultiProcessJobs[$iJobRowId][0] = $MULTIPROCESS_FINISH __MultiProcess_Event($MULTIPROCESS_FINISH, $iJobId) EndIf Return 1 EndFunc ; ===> __MultiProcess_MonitorTasks