Allow2010 Posted March 3, 2012 Posted March 3, 2012 (edited) hi all, i run a dos process from my script and capture its output like this. expandcollapse popupFunc _RunRead($doscmd, $workingdir = @ScriptDir, $flag = @SW_HIDE) $retval = -2 $stdflag = 2 $i_Pid = Run($doscmd, $workingdir, $flag, $stdflag) ; Get process handle Sleep(100) ; or DllCall may fail - experimental $h_Process = DllCall('kernel32.dll', 'ptr', 'OpenProcess', 'int', 0x400, 'int', 0, 'int', $i_Pid) $sStdOut = "" $chkstdout = 1 Do If $chkstdout = 0 Then ExitLoop If $chkstdout = 1 Then $sStdOut = $sStdOut & StdoutRead($i_Pid) If @error Then $chkstdout = 0 $stdoutlines = StringSplit($sStdOut, @CR, 1) $counter = 1 For $counter = 1 To $stdoutlines[0] - 1 ; write to logfile here ;Logfile(CleanDSLogtext($stdoutlines[$counter])) Next If StringInStr($stdoutlines[$stdoutlines[0]], @CR) Then ; write to logfile here ;Logfile(CleanDSLogtext($stdoutlines[0])) $sStdOut = "" Else $sStdOut = $stdoutlines[$stdoutlines[0]] EndIf EndIf Sleep(1000) Until Not ProcessExists($i_Pid) ; fetch exit code and close process handle If IsArray($h_Process) Then Sleep(100) ; or DllCall may fail - experimental $i_ExitCode = DllCall('kernel32.dll', 'ptr', 'GetExitCodeProcess', 'ptr', $h_Process[0], 'int*', 0) If IsArray($i_ExitCode) Then $retval = $i_ExitCode[2] Else $retval = -1 EndIf Sleep(100) ; or DllCall may fail - experimental DllCall('kernel32.dll', 'ptr', 'CloseHandle', 'ptr', $h_Process[0]) EndIf Return $retval EndFunc ;==>_RunRead sometimes it is neccessary to stop the process by sending ctrl+c (and not by processclose() as the process will do some cleanup when closed by ctrl+c) from another script. Is there a way i can send ctrl-c to this running process from a second script? As it is usally run hidden, there is no window to send keystrokes to... any ideas are welcome... Thanks! Edited March 3, 2012 by Allow2010
wakillon Posted March 3, 2012 Posted March 3, 2012 Try to use WinClose for the ConsoleWindowClass window of your hidden dos command. Get his handle with WinGetHandle ( "CLASS:ConsoleWindowClass]" ) AutoIt 3.3.14.2 X86 - SciTE 3.6.0 - WIN 8.1 X64 - Other Example Scripts
Allow2010 Posted March 3, 2012 Author Posted March 3, 2012 thanks for the idea, i will try this.... but is there a way to make sure i kill the right process? I have the PID, can this be helpful?
wakillon Posted March 3, 2012 Posted March 3, 2012 thanks for the idea, i will try this....but is there a way to make sure i kill the right process? I have the PID, can this be helpful?List all windows with WinList ( 'CLASS:ConsoleWindowClass]' )If there is several windows of this classe, use WinGetProcess function.And it doesn't kill the process, it close his window ! AutoIt 3.3.14.2 X86 - SciTE 3.6.0 - WIN 8.1 X64 - Other Example Scripts
Allow2010 Posted March 8, 2012 Author Posted March 8, 2012 Thanks for the info...i tried it but it does not work they way i need it to work. When i press ctrl+c inside the dos window the command closes fine and does some cleanup, when i do this by WinClose, the command also closes, but does not cleanup, so sending ctrl+c is different from using WinClose. Any othe idea how i can send ctrl+c to a hidden dos window?
LoWang Posted March 8, 2012 Posted March 8, 2012 (edited) Hello, I also would really like this to be figured out. I found a lot of other questions regarding this problem in other programming languages too. It has also been and it looks like a really juicy problem :-) Edited March 8, 2012 by LoWang
LoWang Posted March 8, 2012 Posted March 8, 2012 Fixed the link...Also I wonder if maybe using windows command taskkill would not do the same thing as pressing ctrl+c in the application window? Maybe the signal is the same if I ommit /f parameter...
ZacUSNYR Posted March 8, 2012 Posted March 8, 2012 You should check out the Console UDF by Mathttp://matdiesel.co.uk/autoit/_Console_GenerateConsoleCtrlEventHaven't messed around with it much myself.
Allow2010 Posted March 8, 2012 Author Posted March 8, 2012 ahh, this look interesting...thank you !!!
Allow2010 Posted March 8, 2012 Author Posted March 8, 2012 (edited) hmmm it comes down to this: DllCall("kernel32.dll", "bool", "GenerateConsoleCtrlEvent", "dword", 0, "dword", $processgroup) the problem is i can not figure out what $processgroup is:-) I tried the pid and also the window handle, but it did nothing.... can anyone give an example on how to use _Console_GenerateCtrlEvent ? I could not get it to do anything.... Any help is really apreciated ! Edited March 8, 2012 by Allow2010
LoWang Posted March 8, 2012 Posted March 8, 2012 You should check out the Console UDF by Mat http://matdiesel.co.uk/autoit/ _Console_GenerateConsoleCtrlEvent Haven't messed around with it much myself.Unfortunatelly this looks to be intended for different use. Not to read or write something to another process STDOUT or STDIN...
ZacUSNYR Posted March 9, 2012 Posted March 9, 2012 You need to alloc a console, then attach a process to that console. The Ctrl-C send works sending to that console. In the UDF he wrote you can interact with input/output via the UDF (the standard auto it functions don't interact with the console window). I was able to successfully start a ping -t and send a ctrl c via _Console_GenerateCtrlEvent("CTRL_C_EVENT") It appears to only works when the script is compiled and not via 'Go' Console window. A way I did this for an app I wrote as well. I found a little utility that sends a ctrl-break. I had to collect the child pid due to what I was running and I ran this app (SendSignal.exe - you'll find a link in google). Capture the "Control-Break" text and taskkill it. Not a clean exit.
Allow2010 Posted March 9, 2012 Author Posted March 9, 2012 (edited) >I was able to successfully start a ping -t and send a ctrl c via _Console_GenerateCtrlEvent("CTRL_C_EVENT") could you post this as an example? Edit: SendSignal.exe works fine (i can call it with the pid, that is great), thank you for finding this... I still would love to get this done in autoit without an external app... EDIT: >I was able to successfully start a ping -t and send a ctrl c via _Console_GenerateCtrlEvent("CTRL_C_EVENT") It seems to me that this is wrong, as the console.au3 defines Global Const $CTRL_C_EVENT = 0 Global Const $CTRL_BREAK_EVENT = 1 so you should have used _Console_GenerateCtrlEvent($CTRL_C_EVENT) which is equivalent to _Console_GenerateCtrlEvent(0) or am i getting something wrong here? Edited March 9, 2012 by Allow2010
rover Posted March 9, 2012 Posted March 9, 2012 (edited) You can put it all in one script if you use a console event handler with an attached console. The script does not close when Ctrl-C is sent to the shared console of the parent/child processes. Edit: removed AttachConsole Edit: added code for sending Ctrl-C to process not opened by script Edit: replaced WinList with GetConsoleWindow Use the popup option to copy the script, Expand or drag selecting the text screws up the @Tabs expandcollapse popup;coded by rover 2k12 ;Ref: ;http://stackoverflow.com/questions/813086/can-i-send-a-ctrl-c-sigint-to-an-application-on-windows #NoTrayIcon ;#AutoIt3Wrapper_Change2CUI=y If Not @Compiled Then Exit #include <windowsconstants.au3> Opt("MustDeclareVars", 1) Global $iCallback OnAutoItExitRegister("_Exit") Global Const $CTRL_BREAK_EVENT = 1 Global Const $CTRL_C_EVENT = 0 Global $fCloseFlag = False $iCallback = _InitConsole() _Main() Func _Main() GUICreate("", 600, 400) Local $iMemo = GUICtrlCreateEdit("", 2, 28, 596, 370, $WS_VSCROLL) GUICtrlSetLimit(-1, 1048576) Local $cCtrl_C = GUICtrlCreateButton("Ctrl-C", 2, 2, 120, 25) GUISetState() Local $iExitCode = Cmd("cmd.exe /c dir c:\ /s", $iMemo, $cCtrl_C) MsgBox(262144, "Exit Code", $iExitCode & @TAB & @TAB & @TAB) GUICtrlSetData($iMemo, "") $iExitCode = Cmd("ping.exe -t " & @IPAddress1, $iMemo, $cCtrl_C) MsgBox(262144, "Exit Code", $iExitCode & @TAB & @TAB & @TAB) ;Local $Archiv = @TempDir & "\" & @HOUR & "_" & @MIN & "_" & @SEC & "_test.zip" ;GUICtrlSetData($iMemo, "") ;$iExitCode = Cmd(@ProgramFilesDir & "\7-Zip\7z a -tzip "&$Archiv&" "&@TempDir & "\*.*", $iMemo, $cCtrl_C) ;MsgBox(262144, "Exit Code", $iExitCode&@TAB&@TAB&@TAB) ;send ctrl-c to console process not launched by script GUICtrlSetData($iMemo, "") DllCall("kernel32.dll", "bool", "FreeConsole") ;free console so we can attach to another console process MsgBox(262144, "Open CMD prompt", "open a single cmd prompt with ping.exe -t yourIP, then continue") Local $aCon = WinList("[CLASS:ConsoleWindowClass]"), $PID For $i = 0 To $aCon[0][0] $PID = WinGetProcess($aCon[$i][1]) If $PID <> @AutoItPID Then DllCall("kernel32.dll", "bool", "AttachConsole", "dword", $PID) Next GUICtrlSetData($iMemo, "Ctrl-C to close existing console") While 1 Switch GUIGetMsg() Case -3 ExitLoop Case $cCtrl_C ;send ctrl-c to script and child process event handler, script event handler will block exit DllCall("kernel32.dll", "bool", "GenerateConsoleCtrlEvent", "dword", $CTRL_C_EVENT, "dword", 0) EndSwitch WEnd DllCall("kernel32.dll", "bool", "FreeConsole") Exit EndFunc ;==>_Main Func _Exit() DllCall("kernel32.dll", "bool", "FreeConsole") DllCall("Kernel32.dll", "bool", "SetConsoleCtrlHandler", "ptr", 0, "bool", 0) DllCallbackFree($iCallback) EndFunc ;==>_Exit Func Cmd($sCmd, $cEdit, $cBtn) Local $iPid = Run($sCmd, @ScriptDir, @SW_HIDE, 2) Local $h_Process = DllCall('kernel32.dll', 'ptr', 'OpenProcess', 'int', 0x400, 'int', 0, 'int', $iPid) Local $sData, $retval = -1 While 1 $sData = StdoutRead($iPid) If @error Then ExitLoop $sData = StringReplace($sData, @CR & @CR, @CR) If $sData Then GUICtrlSetData($cEdit, $sData & @CRLF, 1) #cs If $fCloseFlag Then ;continually send ctrl-c until child process exits (not all child processes will respond to Ctrl-C the first time) DllCall("kernel32.dll", "bool", "GenerateConsoleCtrlEvent", "dword", $CTRL_C_EVENT, "dword", 0) If ProcessExists($iPid) = 0 Then ExitLoop EndIf #ce Switch GUIGetMsg() Case -3 ;ExitLoop Case $cBtn ;send ctrl-c to script and child process event handler, script event handler will block exit DllCall("kernel32.dll", "bool", "GenerateConsoleCtrlEvent", "dword", $CTRL_C_EVENT, "dword", 0) EndSwitch WEnd $fCloseFlag = False If IsArray($h_Process) Then Local $i_ExitCode = DllCall('kernel32.dll', 'ptr', 'GetExitCodeProcess', 'ptr', $h_Process[0], 'int*', 0) If IsArray($i_ExitCode) Then $retval = $i_ExitCode[2] DllCall('kernel32.dll', 'ptr', 'CloseHandle', 'ptr', $h_Process[0]) EndIf Return $retval EndFunc ;==>Cmd Func _InitConsole() DllCall("kernel32.dll", "int", "AllocConsole") ;DllCall("kernel32.dll", "bool", "AttachConsole", "dword", -1) Local $hConsolehWnd = DllCall("Kernel32.dll", "hwnd", "GetConsoleWindow") If @error Then Return WinSetState($hConsolehWnd[0], "", @SW_HIDE) Local $iCB = DllCallbackRegister("_ConsoleEventHandler", "long", "dword") DllCall("Kernel32.dll", "bool", "SetConsoleCtrlHandler", "ptr", DllCallbackGetPtr($iCB), "bool", 1) Return $iCB EndFunc ;==>_InitConsole Func _ConsoleEventHandler($dwCtrlType) Switch $dwCtrlType Case $CTRL_C_EVENT, $CTRL_BREAK_EVENT $fCloseFlag = True ; set flag for checking if child process exists Return True ; exiting blocked, exit must be called from loop ;Return False ;exit normally EndSwitch Return False EndFunc ;==>_ConsoleEventHandler Edited March 9, 2012 by rover I see fascists...
Allow2010 Posted March 9, 2012 Author Posted March 9, 2012 thanks, looks interesting...will try it...
Allow2010 Posted March 9, 2012 Author Posted March 9, 2012 (edited) #include "console.au3" $iPid = Run("ping.exe -t " & @IPAddress1) Sleep(1000) $h_Process = DllCall('kernel32.dll', 'ptr', 'OpenProcess', 'int', 0x400, 'int', 0, 'int', $iPid) _Console_GenerateCtrlEvent($CTRL_C_EVENT,$h_Process[0]) From what i found i was thinking this should work, but it does not...anyone know why? Edited March 9, 2012 by Allow2010
rover Posted March 9, 2012 Posted March 9, 2012 (edited) #include "console.au3" $iPid = Run("ping.exe -t " & @IPAddress1) Sleep(1000) $h_Process = DllCall('kernel32.dll', 'ptr', 'OpenProcess', 'int', 0x400, 'int', 0, 'int', $iPid) _Console_GenerateCtrlEvent($CTRL_C_EVENT,$h_Process[0]) From what i found i was thinking this should work, but it does not...anyone know why? That 2nd param can only be used if you use _WinAPI_CreateProcess() with the CREATE_NEW_PROCESS_GROUP flag instead of Run() MSDN: http://msdn.microsoft.com/en-us/library/windows/desktop/ms683155(v=vs.85).aspx dwProcessGroupId [in] The identifier of the process group to receive the signal. A process group is created when the CREATE_NEW_PROCESS_GROUP flag is specified in a call to the CreateProcess function. The process identifier of the new process is also the process group identifier of a new process group. The process group includes all processes that are descendants of the root process. Only those processes in the group that share the same console as the calling process receive the signal. In other words, if a process in the group creates a new console, that process does not receive the signal, nor do its descendants. If this parameter is zero, the signal is generated in all processes that share the console of the calling process. either compile as CUI or use AllocConsole Edit: restored UDF name (conflicted with existing Console.au3) If Not @Compiled Then Exit #include "Console.au3" _Console_Alloc() $iPid = Run("ping.exe -t " & @IPAddress1) Sleep(1000) _Console_GenerateCtrlEvent($CTRL_C_EVENT, 0) Do Until Not Sleep(1000) #AutoIt3Wrapper_Change2CUI=y If Not @Compiled Then Exit #include "Console.au3" $iPid = Run("ping.exe -t " & @IPAddress1) Sleep(1000) _Console_GenerateCtrlEvent($CTRL_C_EVENT, 0) Do Until Not Sleep(1000) Edited March 9, 2012 by rover I see fascists...
Allow2010 Posted March 9, 2012 Author Posted March 9, 2012 thanks a lot for explaining, but my problem still exist: i have to send ctrl-c to a process that was started by another autoit script, so i can not use the method above...:-(
rover Posted March 9, 2012 Posted March 9, 2012 (edited) thanks a lot for explaining, but my problem still exist: i have to send ctrl-c to a process that was started by another autoit script, so i can not use the method above...:-(After much f* around with the malfunctioning editor and code tags,I managed to add a fourth example I was about to upload when you posted.It occured to me I hadn't included an example for another processYou may have to click the Ctrl-C button a 2nd time to close the program running in the console Edited March 9, 2012 by rover I see fascists...
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