Jump to content

Watch Child Processes recursively

Recommended Posts


based on @JerryD 's function I added some lines to watch for child processes recursively.

That's helful for installing Autodesk patches silently all-in-a-row: Some of these patches respawn the setup program, then terminate the original PID, and the respawned PID as well spawns other child processes. Before launching the next patch, it's required to wait for *ALL* child PID to vanish.


The sample script below will show what I mean. the script launches a CMD.EXE and then checks for child / grand-child /... processes over and over again.

After every step close the _debugarraydisplay() to refresh it!

  1. Lauch a new CMD box by typing 
    start cmd


  2. do that two more times in each new opened CMD box

  3. Now launch from box #1 another program, e.g.
    start notepad.exe
  4. Do the same for the box #2 with a different program
    start winword.exe


  5. and for box #3 as well
    start calc.exe



Now you can close the original box#1 and box#2, if you launch new processes from box#3 they will be captured and monitored as well.


#include <Debug.au3>
#include <array.au3>

Dim $aCHLDPIDs[0][2]
Enum $iPID,$iName

    AddChldPidsRec($TLDPID) ; recursively search for Children, Grandchildren, Grand-grand-children...
    _DebugArrayDisplay($aCHLDPIDs,"Alle Child PIDs")
    for $y = 0 to UBound($aCHLDPIDs) - 1
        AddChldPidsRec($aCHLDPIDs[$y][$iPID]) ; Check all PIDs in the list again: There might be a new "Grand-Child" we need to wait for, while the "child" has died *ALREADY* (chain broken)
until AllGone()

Func AddChldPidsRec($_PID)
    ConsoleWrite($SubLevel & @TAB & $_PID & @CRLF)
    Local $p,$NextPID,$KnownPID
    if IsArray($a2Children) Then
        ; _DebugArrayDisplay($a2Children,$SubLevel & " [" & $_PID & "]")
        for $p = 1 to $a2Children[0][0]
            ;~  MsgBox(0,"NextPID",$NextPID & @CRLF & $NextProg)
            if (_ArraySearch($aCHLDPIDs,$NextPID)= -1) then _ArrayAdd($aCHLDPIDs,$NextPID & "|" & $NextProg) ; diese PID ist noch nicht erfasst.
            AddChldPidsRec($NextPID) ; Check this PID for decendent child PIDs, too. (recursive check)
        MsgBox(0,$_PID,"no child PIDs")

Func AllGone()
    local $x
    for $x = UBound($aCHLDPIDs) - 1 to 0 Step -1
        if ProcessExists($aCHLDPIDs[$x][$iPID]) Then
            ; Prozess läuft noch
    ; _DebugArrayDisplay($aCHLDPIDs,"AllGoneCheck: Noch was da!")
    if UBound($aCHLDPIDs) > 0 or ProcessExists($TLDPID) Then
        Return False
        MsgBox(0,"All gone","Ready for exit")
        Return True

#endregion Sample Code

; Function Name:    _ChildProcess
; Description:      Returns an array containing child process info
; Parameter(s):     $iParentPID - Parent Process PID
; Requirement(s):   AutoIt 3.8+
; Return Value(s):  two dimensional array $aChildren[][] as follows
;                   $aChildren[0][0] = Number of children found
;                   $aChildren[x][0] = Child Process's PID (called Handle, but not a handle object)
;                   $aChildren[x][1] = Child Process's Name
;                   $aChildren[x][2] = Child Process's Command Line
;                   $aChildren[x][3] = Child Process's Executable Path
;                   $aChildren[x][4] = Child Process's Creation Date and Time
;                   $aChildren[x][5] = Child Process's Session Id
;                   $aChildren[x][6] = Child Process's Status
;                   $aChildren[x][7] = Child Process's Termination Date
; AutoIt Version:
; Author:           JerryD

Func _ChildProcess ( $iParentPID )
    Local Const $wbemFlagReturnImmediately = 0x10, $wbemFlagForwardOnly = 0x20
    Local Const $sQuery = 'SELECT * FROM Win32_Process Where ParentProcessId = ' & $iParentPID & ' AND Handle <> ' & $iParentPID
    Local $aChildren[1][8]
    $aChildren[0][0] = 0
    $aChildren[0][1] = 'Name'
    $aChildren[0][2] = 'Command Line'
    $aChildren[0][3] = 'Executable Path'
    $aChildren[0][4] = 'Creation Date and Time'
    $aChildren[0][5] = 'Session Id'
    $aChildren[0][6] = 'Status'
    $aChildren[0][7] = 'Termination Date'

    Local $objWMIService = ObjGet ( 'winmgmts:\\localhost\root\CIMV2' )
    If NOT IsObj ( $objWMIService ) Then
        SetError ( 1 )
        Return $aChildren
    Local $colItems = $objWMIService.ExecQuery ( $sQuery, 'WQL', $wbemFlagReturnImmediately + $wbemFlagForwardOnly )
    If IsObj($colItems) then
        For $objItem In $colItems
            $aChildren[0][0] += 1
            ReDim $aChildren[$aChildren[0][0]+1][8]
            $aChildren[$aChildren[0][0]][0] = $objItem.Handle
            $aChildren[$aChildren[0][0]][1] = $objItem.Name
            $aChildren[$aChildren[0][0]][2] = $objItem.CommandLine
            $aChildren[$aChildren[0][0]][3] = $objItem.ExecutablePath
            $aChildren[$aChildren[0][0]][4] = $objItem.CreationDate
            $aChildren[$aChildren[0][0]][5] = $objItem.SessionId
            $aChildren[$aChildren[0][0]][6] = $objItem.Status
            $aChildren[$aChildren[0][0]][7] = $objItem.TerminationDate
        SetError ( 2 )
        Return $aChildren
    SetError ( 0 )
    Return $aChildren


Edited by rudi

Earth is flat, pigs can fly, and Nuclear Power is SAFE!

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

  • Create New...