PhilHibbs Posted March 30, 2010 Share Posted March 30, 2010 (edited) Here is my "Cmd.au3" include file, maybe this could become an official UDF library at some point. It has three functions - one to get the window handle from a process ID (GetProcessWin doesn't work for command prompts), the other pair both copy and searche through a Command Prompt's text buffer. I'm not entirely happy about the $aText mechanism in the _CmdWaitList function, which takes a list of values to wait for and returns the index of the first one found. I don't like having to construct the array of strings. Also I'm not sure about setting SendKeepActive() inside a UDF. Maybe I should leave that to be the caller's responsibility. expandcollapse popup#include-Once ; #INDEX# ======================================================================================================================= ; Title .........: Cmd ; AutoIt Version : 3.3.6++ ; Language ......: English ; Description ...: Functions for manipulating command prompt windows. ; Author(s) .....: PhilHibbs ; =============================================================================================================================== ; #CURRENT# ===================================================================================================================== ;_CmdGetWindow ;_CmdWaitFor ;_CmdWaitList ; =============================================================================================================================== ; #FUNCTION# ==================================================================================================================== ; Name...........: _CmdGetWindow ; Description ...: Locates the window handle for a given Command Prompt process. ; Syntax.........: _CmdGetWindow($pCmd) ; Parameters ....: $pCmd - Process id of the Command Prommpt application ; Return values .: Success - Window handle ; Failure - -1, sets @error ; |1 - Process $pCmd not found ; Author ........: Phil Hibbs (phil at hibbs dot me dot uk) ; Modified.......: ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== Func _CmdGetWindow( $pCmd ) Local $WinList, $i $WinList = WinList() For $i = 1 to $WinList[0][0] If $WinList[$i][0] <> "" And WinGetProcess( $WinList[$i][1] ) = $pCmd Then Return $WinList[$i][1] EndIf Next Return SetError(1, 0, -1) EndFunc ;==>_CmdGetWindow ; #FUNCTION# ==================================================================================================================== ; Name...........: _CmdWaitFor ; Description ...: Waits for a particular string to be found in a Command Prompt window ; Syntax.........: _CmdWaitFor($hWin, $text, $timeout = -1, $period, $prefix = "" ) ; Parameters ....: $hWin - Window handle ; $text - String to search for ; $timeout - How long to wait for in ms, 0 = look once and return, -1 = keep looking for ever ; $period - How long to pause between each content grab ; $prefix - Prefix string, anything prior to this prefix is discarded before searching for $text ; Return values .: Success - True ; Failure - False ; |1 - Text is not found within the time limit ; |2 - Window does not exist ; Author ........: Phil Hibbs (phil at hibbs dot me dot uk) ; Modified.......: ; Remarks .......: The prefix is for searching for something that might occur multiple times, for instance if you issue a command ; and want to wait for the User@ prompt, the command itself should be the preifx. If you are issuing the same ; command multiple times, you could echo a unique string and use that as the prefix, e.g. ; Send( "echo :cmd123:;ls -l{Enter}" ) ; _CmdWaitFor( $hTelnet, $User & "@", -1, ":cmd123:" ) ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== Func _CmdWaitFor( $hWin, $text, $timeout = Default, $period = Default, $prefix = "" ) Local $timer, $con, $i If $timeout = Default Then $timeout = -1 If $period = Default Then $period = 1000 SendKeepActive( $hWin ) $timer = TimerInit() While ($timeout <= 0 Or TimerDiff($timer) < $timeout) And WinExists( $hWin ) Send( "! es{Enter}" ) $con = ClipGet() If $prefix <> "" Then $con = StringMid( $con, StringInStr( $con, $prefix, False, -1 ) + StringLen( $prefix ) ) EndIf If StringInStr( $con, $text ) > 0 Then Return True EndIf If $timeout = 0 Then ExitLoop Sleep($period) WEnd Return False EndFunc ;==>_CmdWaitFor ; #FUNCTION# ==================================================================================================================== ; Name...........: _CmdWaitList ; Description ...: Waits for one of a set of strings to be found in a Command Prompt window ; Syntax.........: _CmdWaitList($hWin, $aText, $timeout = -1, $period, $prefix = "" ) ; Parameters ....: $hWin - Window handle ; $aText - Array of strings to search for ; $timeout - How long to wait for in ms, 0 = look once and return, -1 = keep looking for ever ; $period - How long to pause between each content grab ; $prefix - Prefix string, anything prior to this prefix is discarded before searching for $text ; Return values .: Success - Element number found ; Failure - -1, sets @error ; |1 - Text is not found within the time limit ; |2 - Window does not exist ; Author ........: Phil Hibbs (phil at hibbs dot me dot uk) ; Modified.......: ; Remarks .......: The prefix is for searching for something that might occur multiple times, for instance if you issue a command ; and want to wait for the User@ prompt, the command itself should be the preifx. If you are issuing the same ; command multiple times, you could echo a unique string and use that as the prefix. ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== Func _CmdWaitList( $hWin, ByRef $aText, $timeout = Default, $period = Default, $prefix = "" ) Local $timer, $con, $i If $timeout = Default Then $timeout = -1 If $period = Default Then $period = 1000 SendKeepActive( $hWin ) $timer = TimerInit() While ($timeout <= 0 Or TimerDiff($timer) < $timeout) And WinExists( $hWin ) Send( "! es{Enter}" ) $con = ClipGet() If $prefix <> "" Then $con = StringMid( $con, StringInStr( $con, $prefix, False, -1 ) + StringLen( $prefix ) ) EndIf For $i = 0 To UBound( $aText ) - 1 If StringInStr( $con, $aText[$i] ) > 0 Then Return $i EndIf Next If $timeout = 0 Then ExitLoop Sleep($period) WEnd If Not(WinExists( $hWin )) Then Return SetError(2, 0, -1) Return SetError(1, 0, -1) EndFunc ;==>_CmdWaitList Demonstration: #include "Cmd.au3" $pCmd = Run( "cmd.exe" ) Sleep( 1000 ) $hCmd = _CmdGetWindow( $pCmd ) SendKeepActive( $hCmd ) If _CmdWaitFor( $hCmd, "Microsoft Corp", 1000 ) Then ; Clipboard will contain the contents of the cmd buffer $cmdtext = ClipGet() ; Pick up the last line, this will be the prompt string for future use $cmdprompt = StringMid( $cmdtext, StringInStr( $cmdtext, @LF, False, -1 ) + 1) Send( "dir{Enter}" ) If _CmdWaitFor( $hCmd, "bytes free" ) Then $cmdtext = ClipGet() $bytesfree = StringStripWS(StringMid( $cmdtext, StringInStr( $cmdtext, "Dir(s)" ) + 7, 16 ), 3) MsgBox( 0, "DIR", "You have " & $bytesfree & " bytes free" ) EndIf EndIf Edited March 30, 2010 by PhilHibbs Link to comment Share on other sites More sharing options...
happy2help Posted March 30, 2010 Share Posted March 30, 2010 Looks useful - thanks Link to comment Share on other sites More sharing options...
BrettF Posted March 30, 2010 Share Posted March 30, 2010 What happened to STDIO? Vist my blog!UDFs: Opens The Default Mail Client | _LoginBox | Convert Reg to AU3 | BASS.au3 (BASS.dll) (Includes various BASS Libraries) | MultiLang.au3 (Multi-Language GUIs!)Example Scripts: Computer Info Telnet Server | "Secure" HTTP Server (Based on Manadar's Server)Software: AAMP- Advanced AutoIt Media Player | WorldCam | AYTU - Youtube Uploader Tutorials: Learning to Script with AutoIt V3Projects (Hardware + AutoIt): ArduinoUseful Links: AutoIt 1-2-3 | The AutoIt Downloads Section: | SciTE4AutoIt3 Full Version! Link to comment Share on other sites More sharing options...
PhilHibbs Posted March 30, 2010 Author Share Posted March 30, 2010 (edited) What happened to STDIO?Nothing, it's still there. This is just another way of doing something similar, for instance if you have a Command Prompt that is launched separately from AutoIt. Or, more specifically in my case, when you want to leave the Command Prompt application running for the user to carry on interacting with at the end of the AutoIt script.*Edit:* Also this will work for text-gui applications like Edit, Xtree, or old applications with text menus. Edited March 31, 2010 by PhilHibbs Link to comment Share on other sites More sharing options...
Shafayat Posted March 31, 2010 Share Posted March 31, 2010 I see how that could be useful. Thanks. [Not using this account any more. Using "iShafayet" instead] Link to comment Share on other sites More sharing options...
BrettF Posted March 31, 2010 Share Posted March 31, 2010 Nothing, it's still there. This is just another way of doing something similar, for instance if you have a Command Prompt that is launched separately from AutoIt. Or, more specifically in my case, when you want to leave the Command Prompt application running for the user to carry on interacting with at the end of the AutoIt script.Valid point.Cheers,Brett Vist my blog!UDFs: Opens The Default Mail Client | _LoginBox | Convert Reg to AU3 | BASS.au3 (BASS.dll) (Includes various BASS Libraries) | MultiLang.au3 (Multi-Language GUIs!)Example Scripts: Computer Info Telnet Server | "Secure" HTTP Server (Based on Manadar's Server)Software: AAMP- Advanced AutoIt Media Player | WorldCam | AYTU - Youtube Uploader Tutorials: Learning to Script with AutoIt V3Projects (Hardware + AutoIt): ArduinoUseful Links: AutoIt 1-2-3 | The AutoIt Downloads Section: | SciTE4AutoIt3 Full Version! Link to comment Share on other sites More sharing options...
Mat Posted March 31, 2010 Share Posted March 31, 2010 Check out these functions, though I'm not sure if they will work for external applications. http://msdn.microsoft.com/en-us/library/ms682073(VS.85).aspx AutoIt Project Listing Link to comment Share on other sites More sharing options...
PhilHibbs Posted March 31, 2010 Author Share Posted March 31, 2010 Check out these functions, though I'm not sure if they will work for external applications.http://msdn.microsoft.com/en-us/library/ms682073(VS.85).aspxYes, I saw those after finding the _WinAPI_WriteConsole function. ReadConsoleOutput looks interesting, but I have no idea whether it's even possible to get the console handle. Link to comment Share on other sites More sharing options...
PhilHibbs Posted March 31, 2010 Author Share Posted March 31, 2010 (edited) New test script, using the && command separator in order to demonstrate the $prefix mechanism: #include "Cmd.au3" $pCmd = Run( "cmd.exe" ) $hCmd = _CmdGetWindow( $pCmd ) SendKeepActive( $hCmd ) If _CmdWaitFor( $hCmd, "Microsoft Corp", 1000 ) Then ; Clipboard will contain the contents of the cmd buffer $cmdtext = ClipGet() ; Pick up the last line, this will be the prompt string for future use $cmdprompt = StringMid( $cmdtext, StringInStr( $cmdtext, @LF, False, -1 ) + 1) Send( "echo :cmd001:&&dir{Enter}" ) If _CmdWaitFor( $hCmd, $cmdprompt, Default, Default, ":cmd001:" ) Then $cmdtext = ClipGet() $bytesfree = StringStripWS(StringMid( $cmdtext, StringInStr( $cmdtext, "Dir(s)" ) + 7, 16 ), 3) MsgBox( 0, "DIR", "You have " & $bytesfree & " bytes free" ) EndIf EndIf *Edit:* Of course, that $cmdprompt mechanism will fail if you have some kind of funky prompt like "$t $p$g". Edited March 31, 2010 by PhilHibbs Link to comment Share on other sites More sharing options...
PhilHibbs Posted April 28, 2010 Author Share Posted April 28, 2010 (edited) Totally new version of Cmd.Au3, this uses proper API calls rather than stuffing the Select All keys and reading the clipboard. The _CmdAttachConsole returns a "handle" which needs to be passed to the other _Cmd functions, the _CmdWaitFor and _CmdWaitList also still need the window handle so that they can check if the prompt has disappeared (although the script seems to die if the window is closed). The script using this library must be run outside of SciTE, but does not need to be compiled. expandcollapse popup#include-Once #include <WinAPI.au3> #Include <Misc.au3> ; #INDEX# ======================================================================================================================= ; Title .........: Cmd ; AutoIt Version : 3.3.6++ ; Language ......: English ; Description ...: Functions for manipulating command prompt windows. ; Author(s) .....: PhilHibbs ; Valik ; =============================================================================================================================== ; #CONSTANTS# =================================================================================================================== Global Const $STD_INPUT_HANDLE = -10 Global Const $STD_OUTPUT_HANDLE = -11 Global Const $STD_ERROR_HANDLE = -12 Global Const $_CONSOLE_SCREEN_BUFFER_INFO = _ "short dwSizeX;" & _ "short dwSizeY;" & _ "short dwCursorPositionX;" & _ "short dwCursorPositionY;" & _ "short wAttributes;" & _ "short Left;" & _ "short Top;" & _ "short Right;" & _ "short Bottom;" & _ "short dwMaximumWindowSizeX;" & _ "short dwMaximumWindowSizeY" Global Const $_COORD = _ "short X;" & _ "short Y" Global Const $_CHAR_INFO = _ "wchar UnicodeChar;" & _ "short Attributes" Global Const $_SMALL_RECT = _ "short Left;" & _ "short Top;" & _ "short Right;" & _ "short Bottom" ; =============================================================================================================================== ; #CURRENT# ===================================================================================================================== ;_CmdGetWindow ;_CmdAttachConsole ;_CmdWaitFor ;_CmdWaitList ; =============================================================================================================================== ; #FUNCTION# ==================================================================================================================== ; Name...........: _CmdGetWindow ; Description ...: Locates the window handle for a given Command Prompt process. ; Syntax.........: _CmdGetWindow($pCmd) ; Parameters ....: $pCmd - Process id of the Command Prommpt application ; Return values .: Success - Window handle ; Failure - -1, sets @error ; |1 - Process $pCmd not found ; Author ........: Phil Hibbs (phil at hibbs dot me dot uk) ; Modified.......: ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== Func _CmdGetWindow( $pCmd ) Local $WinList, $i While True $WinList = WinList() For $i = 1 to $WinList[0][0] If $WinList[$i][0] <> "" And WinGetProcess( $WinList[$i][1] ) = $pCmd Then Return $WinList[$i][1] EndIf Next WEnd EndFunc ;==>_CmdGetWindow ; #FUNCTION# ==================================================================================================================== ; Name...........: _CmdAttachConsole ; Description ...: Locates the console handle for a given Command Prompt process. ; Syntax.........: _CmdAttachConsole($pCmd) ; Parameters ....: $pCmd - Process id of the Command Prommpt application ; Return values .: Success - Window handle structure ; Failure - -1, sets @error ; |1 - Unable to attach console ; |2 - Unable to create file handle ; Author ........: Phil Hibbs (phil at hibbs dot me dot uk) ; Modified.......: ; Remarks .......: Thanks to Valik for original Screen_Scrape.Au3 ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== Func _CmdAttachConsole($nPid) ; Try to attach to the console of the PID. Local $aRet = DllCall("kernel32.dll", "int", "AttachConsole", "dword", $nPid) If @error Then Return SetError(@error, @extended, False) If $aRet[0] Then ; The user should treat this as an opaque handle, but internally it contains a handle ; and some structures. Local $vHandle[2] $vHandle[0] = _CmdGetStdHandle($STD_OUTPUT_HANDLE) ; STDOUT Handle $vHandle[1] = DllStructCreate($_CONSOLE_SCREEN_BUFFER_INFO) ; Screen Buffer structure ; Return the handle on success. Return $vHandle EndIf ; Return 0 on failure. Return 0 EndFunc ; _CmdAttachConsole() ; #FUNCTION# ==================================================================================================================== ; Name...........: _CmdGetText ; Description ...: Gets all the text in a Command Prompt window ; Syntax.........: _CmdGetText($vHandle, $bAll ) ; Parameters ....: $hConsole - Console handle ; $bAll - True = all text up to bottom of visible area, False = just visible area ; Return values .: Success - Text contents of window ; Failure - "", sets @error ; |1 - Invalid handle structure ; |2 - Screen Buffer API call failed ; Author ........: Phil Hibbs (phil at hibbs dot me dot uk) ; Modified.......: ; Remarks .......: Thanks to Valik for original Screen_Scrape.Au3 ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== Func _CmdGetText(ByRef $vHandle, $bAll = False) ; Basic sanity check to validate the handle. If UBound($vHandle) = 2 Then ; Create some variables for convenience. Local Const $hStdOut = $vHandle[0] Local Const $pConsoleScreenBufferInfo = $vHandle[1] ; Try to get the screen buffer information. If _GetConsoleScreenBufferInfo($hStdOut, $pConsoleScreenBufferInfo) Then ; Load the SMALL_RECT with the projected text position. Local $iLeft = DllStructGetData( $pConsoleScreenBufferInfo, "Left") Local $iRight = DllStructGetData( $pConsoleScreenBufferInfo, "Right") Local $iTop = DllStructGetData( $pConsoleScreenBufferInfo, "Top") Local $iBottom = DllStructGetData( $pConsoleScreenBufferInfo, "Bottom") Local $iWidth = $iRight - $iLeft + 1 ; Set up the coordinate structures. Local $coordBufferCoord = _CmdWinAPI_MakeDWord(0, 0) Local $coordBufferSize = _CmdWinAPI_MakeDWord($iWidth, 1) ;MsgBox( 0, "coords", "L=" & $iLeft & "T=" & $iTop & "R=" & $iRight & "B=" & $iBottom ) Local $pBuffer = DllStructCreate("dword[" & $iWidth & "]") Local Const $pRect = DllStructCreate($_SMALL_RECT) ; This variable holds the output string. Local $sText = "" For $j = _IIf( $bAll, 0, $iTop ) To $iBottom Local $sLine = "" DllStructSetData( $pRect, "Left", $iLeft ) DllStructSetData( $pRect, "Right", $iRight ) DllStructSetData( $pRect, "Top", $j ) DllStructSetData( $pRect, "Bottom", $j ) ; Read the console output. If _CmdReadConsoleOutput($hStdOut, $pBuffer, $coordBufferSize, $coordBufferCoord, $pRect) Then Local $pPtr = DllStructGetPtr($pBuffer) For $i = 0 To $iWidth - 1 ; We offset the buffer each iteration by 4 bytes because that is the size of the CHAR_INFO ; structure. We do this so we can read each individual character. Local $pCharInfo = DllStructCreate($_CHAR_INFO, $pPtr) $pPtr += 4 ; Append the character. $sLine &= DllStructGetData($pCharInfo, "UnicodeChar") Next $sText &= StringStripWS( $sLine, 2 ) & @CRLF EndIf Next $sText = StringStripWS( $sText, 2 ) Return $sText EndIf Return SetError( 2, 0, "" ) EndIf Return SetError( 1, 0, "" ) EndFunc ;==>_CmdGetText ; #FUNCTION# ==================================================================================================================== ; Name...........: _CmdWaitFor ; Description ...: Waits for a particular string to be found in a Command Prompt window ; Syntax.........: _CmdWaitFor( $hWin, $vHandle, $text, $timeout = -1, $period, $prefix = "" ) ; Parameters ....: $hWin - Window handle ; $text - String to search for ; $timeout - How long to wait for in ms, 0 = look once and return, -1 = keep looking for ever ; $period - How long to pause between each content grab ; $prefix - Prefix string, anything prior to this prefix is discarded before searching for $text ; Return values .: Success - True ; Failure - False ; |1 - Text is not found within the time limit ; |2 - Window does not exist ; Author ........: Phil Hibbs (phil at hibbs dot me dot uk) ; Modified.......: ; Remarks .......: The prefix is for searching for something that might occur multiple times, for instance if you issue a command ; and want to wait for the User@ prompt, the command itself should be the preifx. If you are issuing the same ; command multiple times, you could echo a unique string and use that as the prefix, e.g. ; Send( "echo :cmd123:;ls -l{Enter}" ) ; _CmdWaitFor( $hTelnet, $wTelnet, $User & "@", -1, ":cmd123:" ) ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== Func _CmdWaitFor( $hWin, ByRef $vHandle, $text, $timeout = Default, $period = Default, $prefix = "" ) Local $bScrInfo, $bScrContent, $timer, $con, $i If $timeout = Default Then $timeout = -1 If $period = Default Then $period = 1000 $timer = TimerInit() While ($timeout <= 0 Or TimerDiff($timer) < $timeout) And WinExists( $hWin ) $con = _CmdGetText( $vHandle ) If $prefix <> "" Then $con = StringMid( $con, StringInStr( $con, $prefix, False, -1 ) + StringLen( $prefix ) ) EndIf If StringInStr( $con, $text ) > 0 Then Return True EndIf If $timeout = 0 Then ExitLoop Sleep($period) WEnd Return False EndFunc ;==>_CmdWaitFor ; #FUNCTION# ==================================================================================================================== ; Name...........: _CmdWaitList ; Description ...: Waits for one of a set of strings to be found in a Command Prompt window ; Syntax.........: _CmdWaitList($hWin, $vHandle, $aText, $timeout = -1, $period, $prefix = "" ) ; Parameters ....: $hWin - Window handle ; $aText - Array of strings to search for ; $timeout - How long to wait for in ms, 0 = look once and return, -1 = keep looking for ever ; $period - How long to pause between each content grab ; $prefix - Prefix string, anything prior to this prefix is discarded before searching for $text ; Return values .: Success - Element number found ; Failure - -1, sets @error ; |1 - Text is not found within the time limit ; |2 - Window does not exist ; Author ........: Phil Hibbs (phil at hibbs dot me dot uk) ; Modified.......: ; Remarks .......: The prefix is for searching for something that might occur multiple times, for instance if you issue a command ; and want to wait for the User@ prompt, the command itself should be the preifx. If you are issuing the same ; command multiple times, you could echo a unique string and use that as the prefix. ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== Func _CmdWaitList( $hWin, ByRef $vHandle, ByRef $aText, $timeout = Default, $period = Default, $prefix = "" ) Local $timer, $con, $i If $timeout = Default Then $timeout = -1 If $period = Default Then $period = 1000 SendKeepActive( $hWin ) $timer = TimerInit() While ($timeout <= 0 Or TimerDiff($timer) < $timeout) And WinExists( $hWin ) $con = _CmdGetText( $vHandle ) If $prefix <> "" Then $con = StringMid( $con, StringInStr( $con, $prefix, False, -1 ) + StringLen( $prefix ) ) EndIf For $i = 0 To UBound( $aText ) - 1 If StringInStr( $con, $aText[$i] ) > 0 Then Return $i EndIf Next If $timeout = 0 Then ExitLoop Sleep($period) WEnd If Not(WinExists( $hWin )) Then Return SetError(2, 0, -1) Return SetError(1, 0, -1) EndFunc ;==>_CmdWaitList Func _CmdGetStdHandle($nHandle) Local $aRet = DllCall("kernel32.dll", "hwnd", "GetStdHandle", "dword", $nHandle) If @error Then Return SetError(@error, @extended, $INVALID_HANDLE_VALUE) Return $aRet[0] EndFunc ; _CmdGetStdHandle() Func _GetConsoleScreenBufferInfo($hConsoleOutput, $pConsoleScreenBufferInfo) Local $aRet = DllCall("kernel32.dll", "int", "GetConsoleScreenBufferInfo", "hwnd", $hConsoleOutput, _ "ptr", _CmdSafeGetPtr($pConsoleScreenBufferInfo)) If @error Then Return SetError(@error, @extended, False) Return $aRet[0] EndFunc ; _GetConsoleScreenBufferInfo() Func _CmdReadConsoleOutput($hConsoleOutput, $pBuffer, $coordBufferSize, $coordBufferCoord, $pRect) ; We lie about the types for the COORD structures. Since they are the size of an int we expect a packed ; int. Otherwise we may crash or just pass garbage. Local $aRet = DllCall("kernel32.dll", "int", "ReadConsoleOutputW", "ptr", $hConsoleOutput, _ "ptr", _CmdSafeGetPtr($pBuffer), "int", $coordBufferSize, "int", $coordBufferCoord, _ "ptr", _CmdSafeGetPtr($pRect)) If @error Then SetError(@error, @extended, False) Return $aRet[0] EndFunc ; _CmdReadConsoleOutput() Func _CmdSafeGetPtr(Const ByRef $ptr) Local $_ptr = DllStructGetPtr($ptr) If @error Then $_ptr = $ptr Return $_ptr EndFunc ; _CmdSafeGetPtr() Func _CmdWinAPI_MakeDWord($LoWORD, $HiWORD) Local $tDWord = DllStructCreate("dword") Local $tWords = DllStructCreate("word;word", DllStructGetPtr($tDWord)) DllStructSetData($tWords, 1, $LoWORD) DllStructSetData($tWords, 2, $HiWORD) Return DllStructGetData($tDWord, 1) EndFunc ;==>_CmdWinAPI_MakeDWord Simple demo script: #include <WinAPI.au3> #include "Cmd.au3" $pCmd = Run( "cmd.exe" ) Sleep(1000) $hCmd = _CmdGetWindow( $pCmd ) $hCon = _CmdAttachConsole( $pCmd ) If _CmdWaitFor( $hCmd, $hCon, "Microsoft Corp", 100 ) Then $cmdtext = _CmdGetText( $hCon, True ) ;MsgBox(0,"text",$cmdtext) ; Pick up the last line, this will be the prompt string for future use $cmdprompt = StringMid( $cmdtext, StringInStr( $cmdtext, @LF, False, -1 ) + 1) Send( "dir{Enter}" ) If _CmdWaitFor( $hCmd, $hCon, $cmdprompt, 10000 ) Then $cmdtext = _CmdGetText( $hCon, True ) ;MsgBox(0,"text",$cmdtext) $bytesfree = StringStripWS(StringMid( $cmdtext, StringInStr( $cmdtext, "Dir(s)" ) + 7, 16 ), 3) MsgBox( 0, "DIR", "You have " & $bytesfree & " bytes free" ) EndIf EndIf Edited April 28, 2010 by PhilHibbs Link to comment Share on other sites More sharing options...
Mat Posted April 28, 2010 Share Posted April 28, 2010 ; #CURRENT# =====================================================================================================================;_CmdGetWindow;_CmdAttachConsole;_CmdWaitFor;_CmdWaitList; ===============================================================================================================================You are missing the get text function from that list AutoIt Project Listing Link to comment Share on other sites More sharing options...
PhilHibbs Posted April 28, 2010 Author Share Posted April 28, 2010 (edited) You are missing the get text function from that list Thanks. Fixed that in my version.One thing I'm not entirely sure about is how to determine how much of the buffer to fetch. There could be thousands of lines un-used in the buffer, it would be wasteful to fetch it all. At present, it stops reading when it reaches the bottom of the visible window, so you lose sight of stuff if you scroll up. I have a development version that uses the current cursor position instead of the bottom line of the screen, that's ok but I guess the cursor can move under some circumstances. When you do Select All, it only highlights the part of the screen that has been used, so on a fresh command prompt only the first 4 lines are highlighed. Any idea how I replicate that? Keep reading until the $pRect (lpReadRegion) is altered to indicate that nothing was read? Is that what would happen if I try to read past the end of the used area of the buffer? Edited April 28, 2010 by PhilHibbs Link to comment Share on other sites More sharing options...
Mat Posted May 1, 2010 Share Posted May 1, 2010 (edited) I lost the will to live with this, but I just dug it out of one of my old backups and figured that you would would be the guy to make it into a proper UDF. Right now its only functions, and not much works - but its a start, and with a bit of work can be turned into a very useful set of functions. http://code.google.com/p/m-a-t/downloads/detail?name=Console.au3 Unfortunately I've lost the msdn parser I wrote to do most of the work. Mat Edited June 18, 2010 by Mat AutoIt Project Listing Link to comment Share on other sites More sharing options...
gadi Posted June 30, 2010 Share Posted June 30, 2010 Here is my "Cmd.au3" include file, maybe this could become an official UDF library at some point. It has three functions - one to get the window handle from a process ID (GetProcessWin doesn't work for command prompts), the other pair both copy and searche through a Command Prompt's text buffer. I'm not entirely happy about the $aText mechanism in the _CmdWaitList function, which takes a list of values to wait for and returns the index of the first one found. I don't like having to construct the array of strings. Also I'm not sure about setting SendKeepActive() inside a UDF. Maybe I should leave that to be the caller's responsibility. expandcollapse popup#include-Once ; #INDEX# ======================================================================================================================= ; Title .........: Cmd ; AutoIt Version : 3.3.6++ ; Language ......: English ; Description ...: Functions for manipulating command prompt windows. ; Author(s) .....: PhilHibbs ; =============================================================================================================================== ; #CURRENT# ===================================================================================================================== ;_CmdGetWindow ;_CmdWaitFor ;_CmdWaitList ; =============================================================================================================================== ; #FUNCTION# ==================================================================================================================== ; Name...........: _CmdGetWindow ; Description ...: Locates the window handle for a given Command Prompt process. ; Syntax.........: _CmdGetWindow($pCmd) ; Parameters ....: $pCmd - Process id of the Command Prommpt application ; Return values .: Success - Window handle ; Failure - -1, sets @error ; |1 - Process $pCmd not found ; Author ........: Phil Hibbs (phil at hibbs dot me dot uk) ; Modified.......: ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== Func _CmdGetWindow( $pCmd ) Local $WinList, $i $WinList = WinList() For $i = 1 to $WinList[0][0] If $WinList[$i][0] <> "" And WinGetProcess( $WinList[$i][1] ) = $pCmd Then Return $WinList[$i][1] EndIf Next Return SetError(1, 0, -1) EndFunc ;==>_CmdGetWindow ; #FUNCTION# ==================================================================================================================== ; Name...........: _CmdWaitFor ; Description ...: Waits for a particular string to be found in a Command Prompt window ; Syntax.........: _CmdWaitFor($hWin, $text, $timeout = -1, $period, $prefix = "" ) ; Parameters ....: $hWin - Window handle ; $text - String to search for ; $timeout - How long to wait for in ms, 0 = look once and return, -1 = keep looking for ever ; $period - How long to pause between each content grab ; $prefix - Prefix string, anything prior to this prefix is discarded before searching for $text ; Return values .: Success - True ; Failure - False ; |1 - Text is not found within the time limit ; |2 - Window does not exist ; Author ........: Phil Hibbs (phil at hibbs dot me dot uk) ; Modified.......: ; Remarks .......: The prefix is for searching for something that might occur multiple times, for instance if you issue a command ; and want to wait for the User@ prompt, the command itself should be the preifx. If you are issuing the same ; command multiple times, you could echo a unique string and use that as the prefix, e.g. ; Send( "echo :cmd123:;ls -l{Enter}" ) ; _CmdWaitFor( $hTelnet, $User & "@", -1, ":cmd123:" ) ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== Func _CmdWaitFor( $hWin, $text, $timeout = Default, $period = Default, $prefix = "" ) Local $timer, $con, $i If $timeout = Default Then $timeout = -1 If $period = Default Then $period = 1000 SendKeepActive( $hWin ) $timer = TimerInit() While ($timeout <= 0 Or TimerDiff($timer) < $timeout) And WinExists( $hWin ) Send( "! es{Enter}" ) $con = ClipGet() If $prefix <> "" Then $con = StringMid( $con, StringInStr( $con, $prefix, False, -1 ) + StringLen( $prefix ) ) EndIf If StringInStr( $con, $text ) > 0 Then Return True EndIf If $timeout = 0 Then ExitLoop Sleep($period) WEnd Return False EndFunc ;==>_CmdWaitFor ; #FUNCTION# ==================================================================================================================== ; Name...........: _CmdWaitList ; Description ...: Waits for one of a set of strings to be found in a Command Prompt window ; Syntax.........: _CmdWaitList($hWin, $aText, $timeout = -1, $period, $prefix = "" ) ; Parameters ....: $hWin - Window handle ; $aText - Array of strings to search for ; $timeout - How long to wait for in ms, 0 = look once and return, -1 = keep looking for ever ; $period - How long to pause between each content grab ; $prefix - Prefix string, anything prior to this prefix is discarded before searching for $text ; Return values .: Success - Element number found ; Failure - -1, sets @error ; |1 - Text is not found within the time limit ; |2 - Window does not exist ; Author ........: Phil Hibbs (phil at hibbs dot me dot uk) ; Modified.......: ; Remarks .......: The prefix is for searching for something that might occur multiple times, for instance if you issue a command ; and want to wait for the User@ prompt, the command itself should be the preifx. If you are issuing the same ; command multiple times, you could echo a unique string and use that as the prefix. ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== Func _CmdWaitList( $hWin, ByRef $aText, $timeout = Default, $period = Default, $prefix = "" ) Local $timer, $con, $i If $timeout = Default Then $timeout = -1 If $period = Default Then $period = 1000 SendKeepActive( $hWin ) $timer = TimerInit() While ($timeout <= 0 Or TimerDiff($timer) < $timeout) And WinExists( $hWin ) Send( "! es{Enter}" ) $con = ClipGet() If $prefix <> "" Then $con = StringMid( $con, StringInStr( $con, $prefix, False, -1 ) + StringLen( $prefix ) ) EndIf For $i = 0 To UBound( $aText ) - 1 If StringInStr( $con, $aText[$i] ) > 0 Then Return $i EndIf Next If $timeout = 0 Then ExitLoop Sleep($period) WEnd If Not(WinExists( $hWin )) Then Return SetError(2, 0, -1) Return SetError(1, 0, -1) EndFunc ;==>_CmdWaitList Demonstration: #include "Cmd.au3" $pCmd = Run( "cmd.exe" ) Sleep( 1000 ) $hCmd = _CmdGetWindow( $pCmd ) SendKeepActive( $hCmd ) If _CmdWaitFor( $hCmd, "Microsoft Corp", 1000 ) Then ; Clipboard will contain the contents of the cmd buffer $cmdtext = ClipGet() ; Pick up the last line, this will be the prompt string for future use $cmdprompt = StringMid( $cmdtext, StringInStr( $cmdtext, @LF, False, -1 ) + 1) Send( "dir{Enter}" ) If _CmdWaitFor( $hCmd, "bytes free" ) Then $cmdtext = ClipGet() $bytesfree = StringStripWS(StringMid( $cmdtext, StringInStr( $cmdtext, "Dir(s)" ) + 7, 16 ), 3) MsgBox( 0, "DIR", "You have " & $bytesfree & " bytes free" ) EndIf EndIf Hi, Do you have a sample to *WRITE* to a command line, like using the function WriteConsoleOutput? Link to comment Share on other sites More sharing options...
Juvigy Posted January 26, 2017 Share Posted January 26, 2017 I tried to use this but i got an error on _CmdGetText($hCon) , @error=2 What am i doing wrong ? $pCmd = ProcessExists( "cmd.exe" ) $hCmd = _CmdGetWindow( $pCmd ) MsgBox(0,"text",$hCmd) $hCon = _CmdAttachConsole( $pCmd ) MsgBox(0,"text",$hCon) $text = _CmdGetText($hCon) MsgBox(0,@error,$text) 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