Jump to content

Pid help


Recommended Posts

I have an issue where I am launching an executable which I gather the pid number and watch for this closing. The issue is the Pid closes quite quickly and spawns another program that then does all the work I am waiting to complete.

Since my initail pid closes My program thinks the work has been done so falls over as it has not picked up the pid launched with the spawned process..

Any idea how to read this process and wait for it to close

Many Thanks

Link to comment
Share on other sites

Maybe...

$Progy = "Notepad.exe"
$List1 = ProcessList()
$New_Progy = ""

Run($Progy) ; run your program
ProcessWaitClose($Progy)
Sleep(2000) ; wait for new process


$List2 = ProcessList()
For $i = 1 To $List2[0][0]
    If $List1[$i][0] == $List2[$i][0] Then ContinueLoop
    $New_Progy = $List2[$i][0]
    ExitLoop
Next

If $New_Progy = "" Then Exit MsgBox(4096, "eror", "This did not work     ", 5)
ProcessWaitClose($New_Progy)

8)

NEWHeader1.png

Link to comment
Share on other sites

Better idea...

Save the parent process ID, wait for the child to launch (sleep for a few seconds), then use CreateToolhelp32Snapshot and Process32Next to walk the process list and compare each process's parent PID to your saved value.

Link to comment
Share on other sites

Maybe this will help:

;===================================================================================================


;
; Function Name:    _ProcessGetParent()
;
; Description:      Retrieve parent process for a child process
;
; Parameter(s):     $i_pid: The process identifier of the process you want to get the parent       
;                       process identifier for
;
; Return Value(s):
;                 On Success:
;                   Parent PID (process identifier)
;
;                 On Failure:
;                   PID of process passed (Check @error to make sure it is a parent and didn't     
;                       fail)
;
;                 @Error:
;                   (1): CreateToolhelp32Snapshot failed
;                   (2): Process32First failed
;
; Remark(s):        Tested on Windows XP SP2
;
; Author(s):        SmOke_N (Ron Nielsen)
;
;===================================================================================================

MsgBox(0, "Parent Process", _ProcessGetParent(@AutoItPID))

Func _ProcessGetParent($i_pid)
    Local Const $TH32CS_SNAPPROCESS = 0x00000002
   
    Local $a_tool_help = DllCall("Kernel32.dll", "long", "CreateToolhelp32Snapshot", "int", $TH32CS_SNAPPROCESS, "int", 0)
    If IsArray($a_tool_help) = 0 Or $a_tool_help[0] = -1 Then Return SetError(1, 0, $i_pid)
   
    Local $tagPROCESSENTRY32 = _
        DllStructCreate _
            ( _
                "dword dwsize;" & _
                "dword cntUsage;" & _
                "dword th32ProcessID;" & _
                "uint th32DefaultHeapID;" & _
                "dword th32ModuleID;" & _
                "dword cntThreads;" & _
                "dword th32ParentProcessID;" & _
                "long pcPriClassBase;" & _
                "dword dwFlags;" & _
                "char szExeFile[260]" _
            )
    DllStructSetData($tagPROCESSENTRY32, 1, DllStructGetSize($tagPROCESSENTRY32))
   
    Local $p_PROCESSENTRY32 = DllStructGetPtr($tagPROCESSENTRY32)
   
    Local $a_pfirst = DllCall("Kernel32.dll", "int", "Process32First", "long", $a_tool_help[0], "ptr", $p_PROCESSENTRY32)
    If IsArray($a_pfirst) = 0 Then Return SetError(2, 0, $i_pid)
   
    Local $a_pnext, $i_return = 0
    If DllStructGetData($tagPROCESSENTRY32, "th32ProcessID") = $i_pid Then
        $i_return = DllStructGetData($tagPROCESSENTRY32, "th32ParentProcessID")
        DllCall("Kernel32.dll", "int", "CloseHandle", "long", $a_tool_help[0])
        If $i_return Then Return $i_return
        Return $i_pid
    EndIf
   
    While 1
        $a_pnext = DLLCall("Kernel32.dll", "int", "Process32Next", "long", $a_tool_help[0], "ptr", $p_PROCESSENTRY32)
        If IsArray($a_pnext) And $a_pnext[0] = 0 Then ExitLoop
        If DllStructGetData($tagPROCESSENTRY32, "th32ProcessID") = $i_pid Then
            $i_return = DllStructGetData($tagPROCESSENTRY32, "th32ParentProcessID")
            If $i_return Then ExitLoop
            $i_return = $i_pid
            ExitLoop
        EndIf
    WEnd
   
    If $i_return = "" Then $i_return = $i_pid
   
    DllCall("Kernel32.dll", "int", "CloseHandle", "long", $a_tool_help[0])
    Return $i_return
EndFunc

#include <array.au3>
$a_children = _ProcessGetChildren(ProcessExists("explorer.exe"))
_ArrayDisplay($a_children)
;===================================================================================================

;
; Function Name:    _ProcessGetChildren()
;
; Description:      Retrieve an array of all top level child processes
;
; Parameter(s):     $i_pid: The process identifier of the process you want to list the child       
;                       processes from
;
; Return Value(s):
;                 On Success:
;                   2 dimensional array:
;                   [n][0] is the process id of the child
;                   [n][1] is the process name of the child
;
;                 On Failure:
;                   Non array
;
;                 @Error:
;                   (1): CreateToolhelp32Snapshot failed
;                   (2): Process32First failed
;                   (3): No children processes found
;
; Remark(s):        Tested on Windows XP SP2
;
; Author(s):        SmOke_N (Ron Nielsen)
;
;===================================================================================================

Func _ProcessGetChildren($i_pid) ; First level children processes only
    Local Const $TH32CS_SNAPPROCESS = 0x00000002
   
    Local $a_tool_help = DllCall("Kernel32.dll", "long", "CreateToolhelp32Snapshot", "int", $TH32CS_SNAPPROCESS, "int", 0)
    If IsArray($a_tool_help) = 0 Or $a_tool_help[0] = -1 Then Return SetError(1, 0, $i_pid)
   
    Local $tagPROCESSENTRY32 = _
        DllStructCreate _
            ( _
                "dword dwsize;" & _
                "dword cntUsage;" & _
                "dword th32ProcessID;" & _
                "uint th32DefaultHeapID;" & _
                "dword th32ModuleID;" & _
                "dword cntThreads;" & _
                "dword th32ParentProcessID;" & _
                "long pcPriClassBase;" & _
                "dword dwFlags;" & _
                "char szExeFile[260]" _
            )
    DllStructSetData($tagPROCESSENTRY32, 1, DllStructGetSize($tagPROCESSENTRY32))
   
    Local $p_PROCESSENTRY32 = DllStructGetPtr($tagPROCESSENTRY32)
   
    Local $a_pfirst = DllCall("Kernel32.dll", "int", "Process32First", "long", $a_tool_help[0], "ptr", $p_PROCESSENTRY32)
    If IsArray($a_pfirst) = 0 Then Return SetError(2, 0, $i_pid)
   
    Local $a_pnext, $a_children[11][2] = [[10]], $i_child_pid, $i_parent_pid, $i_add = 0
    $i_child_pid = DllStructGetData($tagPROCESSENTRY32, "th32ProcessID")
    If $i_child_pid <> $i_pid Then
        $i_parent_pid = DllStructGetData($tagPROCESSENTRY32, "th32ParentProcessID")
        If $i_parent_pid = $i_pid Then
            $i_add += 1
            $a_children[$i_add][0] = $i_child_pid
            $a_children[$i_add][1] = DllStructGetData($tagPROCESSENTRY32, "szExeFile")
        EndIf
    EndIf
   
    While 1
        $a_pnext = DLLCall("Kernel32.dll", "int", "Process32Next", "long", $a_tool_help[0], "ptr", $p_PROCESSENTRY32)
        If IsArray($a_pnext) And $a_pnext[0] = 0 Then ExitLoop
        $i_child_pid = DllStructGetData($tagPROCESSENTRY32, "th32ProcessID")
        If $i_child_pid <> $i_pid Then
            $i_parent_pid = DllStructGetData($tagPROCESSENTRY32, "th32ParentProcessID")
            If $i_parent_pid = $i_pid Then
                If $i_add = $a_children[0][0] Then
                    ReDim $a_children[$a_children[0][0] + 11][2]
                    $a_children[0][0] = $a_children[0][0] + 10
                EndIf
                $i_add += 1
                $a_children[$i_add][0] = $i_child_pid
                $a_children[$i_add][1] = DllStructGetData($tagPROCESSENTRY32, "szExeFile")
            EndIf
        EndIf
    WEnd
   
    If $i_add <> 0 Then
        ReDim $a_children[$i_add + 1][2]
        $a_children[0][0] = $i_add
    EndIf
   
    DllCall("Kernel32.dll", "int", "CloseHandle", "long", $a_tool_help[0])
    If $i_add Then Return $a_children
    Return SetError(3, 0, 0)
EndFunc


MsgBox(0, "Process Path", _ProcessGetPath(_ProcessGetParent(@AutoItPID)))

Func _ProcessGetPath($vProcess) ;get the program path done by MrCreatoR
    Local $iPID = ProcessExists($vProcess)
    If Not $iPID Then Return SetError(1, 0, -1)
   
    Local $aProc = DllCall('kernel32.dll', 'hwnd', 'OpenProcess', 'int', BitOR(0x0400, 0x0010), 'int', 0, 'int', $iPID)
    If Not IsArray($aProc) Or Not $aProc[0] Then Return SetError(2, 0, -1)
   
    Local $vStruct = DllStructCreate('int[1024]')
   
    Local $hPsapi_Dll = DllOpen('Psapi.dll')
    If $hPsapi_Dll = -1 Then $hPsapi_Dll = DllOpen(@SystemDir & '\Psapi.dll')
    If $hPsapi_Dll = -1 Then $hPsapi_Dll = DllOpen(@WindowsDir & '\Psapi.dll')
    If $hPsapi_Dll = -1 Then Return SetError(3, 0, '')
   
    DllCall($hPsapi_Dll, 'int', 'EnumProcessModules', _
        'hwnd', $aProc[0], _
        'ptr', DllStructGetPtr($vStruct), _
        'int', DllStructGetSize($vStruct), _
        'int_ptr', 0)
    Local $aRet = DllCall($hPsapi_Dll, 'int', 'GetModuleFileNameEx', _
        'hwnd', $aProc[0], _
        'int', DllStructGetData($vStruct, 1), _
        'str', '', _
        'int', 2048)
   
    DllClose($hPsapi_Dll)
   
    If Not IsArray($aRet) Or StringLen($aRet[3]) = 0 Then Return SetError(4, 0, '')
    Return $aRet[3]
EndFunc

Or look here: http://www.autoitscript.com/forum/index.php?showtopic=78445

UEZ

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

Mini launcher (npad.au3) -

Run("notepad.exe")

Script -

Global $child = -1, $parent = Run("npad.exe") ; launches notepad as a child
ProcessWaitClose($parent) ; wait for parent to finish

Global $tagPROCESSENTRY32 = "dword dwSize;dword cntUsage;dword th32ProcessID;ulong_ptr th32DefaultHeapID;dword th32ModuleID;" & _
                            "dword cntThreads;dword th32ParentProcessID;long pcPriClassBase;dword dwFlags;wchar szExeFile[260]"
Global $TH32CS_SNAPPROCESS = 0x00000002
Global $PE32 = DllStructCreate($tagPROCESSENTRY32)
DllStructSetData($PE32, "dwSize", DllStructGetSize($PE32))

Global $hSnap = DllCall("kernel32.dll", "ptr", "CreateToolhelp32Snapshot", "dword", $TH32CS_SNAPPROCESS, "dword", 0)
$hSnap = $hSnap[0]
If $hSnap = 0 Then Exit

Global $proc = DllCall("kernel32.dll", "int", "Process32FirstW", "ptr", $hSnap, "ptr", DllStructGetPtr($PE32))
If $proc[0] <> 0 Then
    Do
        If $parent = DllStructGetData($PE32, "th32ParentProcessID") Then
            $child = DllStructGetData($PE32, "th32ProcessID")
            ExitLoop
        EndIf
        $proc = DllCall("kernel32.dll", "int", "Process32NextW", "ptr", $hSnap, "ptr", DllStructGetPtr($PE32))
    Until ($proc[0] = 0)
EndIf

DllCall("kernel32.dll", "int", "CloseHandle", "ptr", $hSnap)

MsgBox(0, "Get Child", "Child process ID:  " & $child)

EDITED to use ProcessWaitClose() to wait for parent to finish, and to be reasonably sure the child has been created.

Edited by wraithdu
Link to comment
Share on other sites

I don't see the race though.

Apparently you don't know what a race condition is, then.

As long as enough time is given for the child to launch, if it ends before we get there, then $child = -1 and he can assume his child process has ended.

^^^ That's a race condition. When you start saying things like "if enough time..." then you have a race condition.

Your code takes a single snapshot and if it doesn't hit at the exact moment the parent exists and the child has started then it's worthless. Valuater's code is 10x more reliable and it's still a flawed method.

Link to comment
Share on other sites

Alright, is it a reasonable assumption that the child exists if the parent 'launcher' is executed with RunWait()?

The thing I don't like about Valuator's solution is that it will flag *any* process that starts between the two snapshots, even if unrelated.

Link to comment
Share on other sites

...

The thing I don't like about Valuator's solution is that it will flag *any* process that starts between the two snapshots, even if unrelated.

@wraithdu

I agree with that part

@OP

remove this "Sleep(2000) ; wait for new process" from my code and you will have a better chance

8)

NEWHeader1.png

Link to comment
Share on other sites

Alright, is it a reasonable assumption that the child exists if the parent 'launcher' is executed with RunWait()?

About as reasonable as you are going to get.

The thing I don't like about Valuator's solution is that it will flag *any* process that starts between the two snapshots, even if unrelated.

That is more reasonable than taking a snapshot an arbitrary amount of time after the parent has started. The odds are better that your method will miss the magic moment than Valuater's catching the wrong process.
Link to comment
Share on other sites

Why not just look for the launched process. It must have a process exe name, a window or something. Just because you launch a process that launches another, doesn't mean you have to get sidetracked.

I get the impression it's an (un)installer that launches a randomly named process to do the work.
Link to comment
Share on other sites

The _ProcessListProperties() UDF in Example Scripts includes the PPID field for each process. There is still a bit of a race condition possible, but for anything other than extremely short-lived children, it should work fine.

If you want to get down and geeky, I think you can get a WMI event for new process creations and check the parent IDs from that.

:D

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...