bourny Posted June 9, 2009 Share Posted June 9, 2009 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 More sharing options...
bourny Posted June 9, 2009 Author Share Posted June 9, 2009 Searched everywhere - There does not seem to be a solution to it Does anyone know a workaround if it cant be done. Link to comment Share on other sites More sharing options...
Valuater Posted June 9, 2009 Share Posted June 9, 2009 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) Link to comment Share on other sites More sharing options...
wraithdu Posted June 9, 2009 Share Posted June 9, 2009 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 More sharing options...
Valuater Posted June 9, 2009 Share Posted June 9, 2009 Better Idea...Stick with what I gave you...Unless wraithdu wants to teach you how to write with dll's8) Link to comment Share on other sites More sharing options...
wraithdu Posted June 9, 2009 Share Posted June 9, 2009 I'm bored...gimme a few minutes... Link to comment Share on other sites More sharing options...
Valik Posted June 9, 2009 Share Posted June 9, 2009 wraithdu, introducing a race condition is no better of a solution than what Valuater provided. Link to comment Share on other sites More sharing options...
Valuater Posted June 9, 2009 Share Posted June 9, 2009 wraithdu, introducing a race condition is no better of a solution than what Valuater provided.... and I know mine's not perfect... 8) Link to comment Share on other sites More sharing options...
UEZ Posted June 9, 2009 Share Posted June 9, 2009 (edited) Maybe this will help:expandcollapse popup;=================================================================================================== ; ; 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] EndFuncOr look here: http://www.autoitscript.com/forum/index.php?showtopic=78445UEZ Edited June 9, 2009 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 More sharing options...
wraithdu Posted June 9, 2009 Share Posted June 9, 2009 (edited) 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 June 10, 2009 by wraithdu Link to comment Share on other sites More sharing options...
Valik Posted June 9, 2009 Share Posted June 9, 2009 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 More sharing options...
wraithdu Posted June 9, 2009 Share Posted June 9, 2009 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 More sharing options...
Valuater Posted June 9, 2009 Share Posted June 9, 2009 ...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.@wraithduI agree with that part @OPremove this "Sleep(2000) ; wait for new process" from my code and you will have a better chance8) Link to comment Share on other sites More sharing options...
wraithdu Posted June 9, 2009 Share Posted June 9, 2009 Valuator, just so you know, I mean no disrespect in my above comments Link to comment Share on other sites More sharing options...
Valuater Posted June 9, 2009 Share Posted June 9, 2009 Valuator, just so you know, I mean no disrespect in my above comments Me either... thanks for noting it!! 8) Link to comment Share on other sites More sharing options...
Inverted Posted June 9, 2009 Share Posted June 9, 2009 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. Link to comment Share on other sites More sharing options...
Valik Posted June 9, 2009 Share Posted June 9, 2009 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 More sharing options...
Valik Posted June 9, 2009 Share Posted June 9, 2009 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 More sharing options...
PsaltyDS Posted June 9, 2009 Share Posted June 9, 2009 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. 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 More sharing options...
Inverted Posted June 9, 2009 Share Posted June 9, 2009 (edited) Or hijack the target's CreateProcess or Shellexecute API (whichever is used) Edited June 9, 2009 by Inverted Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now