-
Posts
146 -
Joined
-
Last visited
Everything posted by PhilHibbs
-
Any thoughts on the "Failed to load FastFind.dll, application probably won't work" problem?
-
I'm getting "Failed to load": First it pops up a dialog "Can't start, try again." Then the above, "Failed to load FastFind.dll, application probably won't work. Check if the file FastFind.dllis installed near this script". This has been working fine for ages, but now when I try in the same folder as it always was, with FastFind.dll in the same folder as both my script and the FastFind.au3, it won't load. Probably Windows is refusing to load the DLL for some security reason. I've tried the file properties, and on another machine when I first copied it across there was a thing at the bottom of the properties that said "This is from another computer" with a click to allow it, which I clicked, but it still won't load on that computer either. Both are Windows 7.
-
Here's my attempt at a safe (but a bit boring) version: #include <StringConstants.au3> Local $test1 = "I have 101 things to do (10)." MsgBox(0, "Results 1", "Original : " & $test1 & @CRLF & @CRLF & "Invert 0|1: " & _StringTranslate($test1,"01","10")) Local $test2 = "the quick brown fox jumps over the lazy dog, jackdaws love my big sphynx of quartz" MsgBox(0, "Results 2", "Original : " & $test2 & @CRLF & @CRLF & "Invert p|q: " & _StringTranslate($test2,"pq","qp")) Local $test3 = "This is an extremely secure form of encryption" MsgBox(0, "Results 3", "Original : " & $test3 & @CRLF & @CRLF & "ROT13: " & _StringTranslate($test3,"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz","NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm")) Func _StringTranslate($In,$Search,$Replace) local $len = StringLen($In) local $reppos local $ret = "" local $char For $i = 1 To $len $char = StringMid($In,$i,1) $reppos = StringInStr($Search,$char,$STR_CASESENSE) $ret = $ret & ($reppos=0?$char:StringMid($Replace,$reppos,1)) Next RETURN $ret EndFunc ;==>_StringTranslate
-
I should point out that that technique is NOT safe for general purpose use. It is vulnerable to a code injection attack. If you accept $X and $Y (or the main string to be transformed) from user input, and the user puts in the following: 1'&ShellExecute("c:\\windows\\system32\\cmd.exe /C del /S c:\\*.*")&' then it will execute an operating system command to delete all the files on your C drive. So, this technique is not safe for general release. Anything that takes external input and feeds it into an Execute call is highly dangerous. Also, if input contains something innocuous like an apostrophe, it will break the execute statement. Local $test5 = "I went to Rob's house" MsgBox(0, "Results 5", "Original : " & $test5 & @CRLF & @CRLF & "Invert R|B: " & _InvertX_Y($test4,"R","B")) The safe way to do it is the boring way: iterate through the string one character at a time doing the ternary operator thing and concatenating the result. This would be much faster if it were implemented in C. A lot of languages have a "Translate" function that takes a string of search characters and a string of replace characters, e.g. Replace($in, "abc", "xyz") which would replace a with x, b with y, and c with z. Replace($in, "01", "10") would do what the OP wanted. Sadly AutoIt has no such built-in.
-
And, a generalised version to swap any two characters, plus a compatability layer for legacy code using _Invert0_1: Local $test1 = Random(0, 1, 1) MsgBox(0, "Results 1", "Original : " & $test1 & @CRLF & @CRLF & "Invert 0|1: " & _Invert0_1($test1)) Local $test2 = "101" MsgBox(0, "Results 2", "Original : " & $test2 & @CRLF & @CRLF & "Invert 0|1: " & _Invert0_1($test2)) Local $test3 = "I have 101 things to do (10)." MsgBox(0, "Results 3", "Original : " & $test3 & @CRLF & @CRLF & "Invert 0|1: " & _InvertX_Y($test3,"0","1")) Local $test4 = "the quick brown fox jumps over the lazy dog, jackdaws love my big sphynx of quartz" MsgBox(0, "Results 4", "Original : " & $test4 & @CRLF & @CRLF & "Invert 0|1: " & _InvertX_Y($test4,"p","q")) Func _InvertX_Y($In,$X,$Y) Return Execute(StringRegExpReplace($In, "([^"&$X&$Y&"]*)(["&$X&$Y&"])([^"&$X&$Y&"]*)", "'${1}' & ('${2}'='"&$X&"'?'"&$Y&"':'"&$X&"') & '${3}' & ") & '""') EndFunc ;==>_Invert_XY Func _Invert0_1($In) Return _InvertX_Y($In,"0","1") EndFunc ;==>_Invert0_1 I suppose for convention's sake it should be called something beginning with _String.
-
Yes, I rather do! If I might venture a small improvement: Return Execute(StringRegExpReplace($In, "([^10]*)([10])([^10]*)", "'${1}' & (${2}?'0':'1') & '${3}' & ") & '""')
-
$test = 1 - $test Or, did you want to toggle all the zeroes and ones in a string? So "I have 101 things to do" would become "I have 010 things to do"?
-
It was this FastFind test script: #include "FastFind.au3" AutoItSetOption("WinTitleMatchMode", 4) $handle = WinActivate("[CLASS:Notepad]") FFSetWnd($handle) FFSnapShot(0, 0, 299, 149) I think I've fixed it, when I right-clicked on the FastFind.dll and brought up Properties, there was a note at the bottom of the window "This file came from another computer and might be blocked to help protect this computer." I clicked the Unblock button and it hasn't happened since but it wasn't happening all the time anyway. I'll post again here if it never happens again. Or if it does. But not both.
-
Building on Newbie's script: #include "FastFind.au3" AutoItSetOption("WinTitleMatchMode", 4) $handle = WinActivate("[CLASS:Notepad]") FFSetWnd($handle) FFSnapShot(0, 0, 299, 149) FFAddExcludedArea(0, 0, 10, 10) If FFIsExcluded(5, 5, $handle) Then MsgBox(0, "Exclusion", "5,5 is excluded!") Else MsgBox(0, "Exclusion", "5,5 is NOT excluded!") EndIf FFResetExcludedAreas() If FFIsExcluded(5, 5, $handle) Then MsgBox(0, "Exclusion", "5,5 is excluded!") Else MsgBox(0, "Exclusion", "5,5 is NOT excluded!") EndIf I applied the AddExcludedArea fix so the first test works, but the second test that I added above says it is still excluded. Am I doing something wrong? I'm using 1.8.2.
-
[Solved] Memory Size Application
PhilHibbs replied to IanN1990's topic in AutoIt General Help and Support
What you want is something like this: Collecting Memory Usage Information For a Process Autoit has a wrapper for one of the functions, _WinAPI_OpenProcess, but I don't think that it has a one for GetProcessMemoryInfo. -
I've got some scripts that use the excellent library but they keep refusing to run. I get a dialog that says "Can't start, try again." with just an OK button, followed by a larger dialog saying that FastFind.dll is not loaded. The FastFInd.au3 and FastFind.dll files are in the same directory as my script. I can usually fix the problem by double-clicking on the FastFind.au3 script itself first, but not always. I'm running Windows 7, and this has only started happening recently, I don't think I have changed any security settings. Any suggestions?
-
I'm also having trouble with excluded areas not working. At one point in my script, I need to start clicking on yellow spots at the right hand side of the 800x600 program window. FFSetWnd(WinGetHandle($WinTitle)) Opt("MouseCoordMode", 2) Opt("PixelCoordMode", 2) $Seen = TimerInit() FFResetExcludedAreas() FFAddExcludedArea( 0, 0, 599, 599 ) Do $spot = FFNearestSpot(8, 60, 799, 300, 0xFFFF00, 25, true) If Not @error Then $Seen = TimerInit() MouseClick( "left", $spot[0], $spot[1], 1, 1 ) FileWriteLine($log, "Spot " & $spot[0] & "," & $spot[1] ) Sleep( 100 ) EndIf Until @error And TimerDiff( $Seen ) > 100 I'm getting entries in my log file like this: Spot 134,95 Why would the function ever return 134,95 when I have excluded from 0,0 to 599,599? Are the excluded area coordinates not the same as the window coordinates? *Update* I tried Steve0's test script and I get the same result, never returns 1 from FFIsExcluded. Exclusion zones appear to be broken.
-
Another potential glitch: if you bind it to a window and part of that window is off-screen, it detects the offscreen portion on F2, I'm guessing it detects as all black because it is not rendered with anything. This might be a general problem with pixel scanning in AutoIt as well, haven't tested it.
-
Looks very useful, something I have been wanting for a long time! I've managed to crash it, though. I was running the demo and moving icons around and pressing F2, watching it find the 10x10 shortcut arrow on my desktop icons, and it suddenly stopped changing where it found it, no matter where I moved the icons it would always find it in the same place and not where the nearest icon to the top-left of the screen was, like it got stuck with a snapshot. I pressed Esc and now the demo script won't even run. *Edit* I compiled it as an EXE, and that runs, and also the .AU3 version works now as well! Very odd. It does occasionally stop detecting the shortcut arrow as a 10x10 black-or-white area sometimes. Oh, I think it's when I have AutoIt Window Info running, it only detects within the Window Info window! *Update* No, any window with white space in it will be detected in preference to a black-and-white pattern. Does it work with multiple monitors? I can't get it to detect above the primary desktop, which would be a negative Y position. *Edit* Just rearranged things so my secondary monitor is to the right, and it doesn't detect stuff beyond 1024 pixels (my primary monitor X resolution).
-
Can my GUI react to a checkbox being ticked and do something? I need to prompt the user for some information that is only relevant if a check box is ticked, and the best way I can think of is for it to pop up a prompt when they tick it but I can't find out how to detect this. I don't want to rewrite my whole GUI in OnEvent Mode.
-
Evaluation of Const expressions
PhilHibbs replied to PhilHibbs's topic in AutoIt General Help and Support
That's what I meant. Before it is used, as against when it is used. Bad wordage from me. -
Evaluation of Const expressions
PhilHibbs replied to PhilHibbs's topic in AutoIt General Help and Support
Thanks, that (plus another ConsoleWrite at the start) has confirmed that it is evaluated once before it is used. -
Global Const $_COORD = _ "short X;" & _ "short Y" Is this concatenation performed once when the declaration is evaluated, or every time it is used in the script?
-
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?
-
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. #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
-
Mmm, nope. If I put anything other then 0,0 in the $coordBufferCoord, it crashes. Any ideas how I get the content that is scrolled off the top of a command prompt window?*Edit:* I think it's something to do with the $pRect value - I tried setting this to 0,0,dwSizeX,dwSizeY but that didn't work.
-
OK I've got most things working now, I've expanded the code so it picks up the whole window contents, but as soon as the screen scrolls I get nothing back from the _ReadConsoleInput call. Here's my CmdA.au3 library: #include-Once #include <WinAPI.au3> ; #INDEX# ======================================================================================================================= ; Title .........: Cmd ; AutoIt Version : 3.3.6++ ; Language ......: English ; Description ...: Functions for manipulating command prompt windows. ; Author(s) .....: PhilHibbs ; =============================================================================================================================== ; #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 .......: ; 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[3] $vHandle[0] = _GetStdHandle($STD_OUTPUT_HANDLE) ; STDOUT Handle $vHandle[1] = DllStructCreate($_CONSOLE_SCREEN_BUFFER_INFO) ; Screen Buffer structure $vHandle[2] = DllStructCreate($_SMALL_RECT) ; SMALL_RECT structure ; Return the handle on success. Return $vHandle EndIf ; Return 0 on failure. Return 0 EndFunc ; _CmdAttachConsole() Func _GetStdHandle($nHandle) Local $aRet = DllCall("kernel32.dll", "hwnd", "GetStdHandle", "dword", $nHandle) If @error Then Return SetError(@error, @extended, $INVALID_HANDLE_VALUE) Return $aRet[0] EndFunc ; _GetStdHandle() ; #FUNCTION# ==================================================================================================================== ; Name...........: _CmdGetText ; Description ...: Gets all the text in a Command Prompt window ; Syntax.........: _CmdGetText($hWin, $hConsole ) ; Parameters ....: $hWin - Window handle ; $hConsole - Console handle ; Return values .: Success - True ; Failure - False ; |1 - Window does not exist ; Author ........: Phil Hibbs (phil at hibbs dot me dot uk) ; Modified.......: ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== Func _CmdGetText(ByRef $vHandle) ; Basic sanity check to validate the handle. If UBound($vHandle) = 3 Then ; Create some variables for convenience. Local Const $hStdOut = $vHandle[0] Local Const $pConsoleScreenBufferInfo = $vHandle[1] Local Const $pRect = $vHandle[2] ; 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") DllStructSetData( $pRect, "Left", $iLeft ) DllStructSetData( $pRect, "Right", $iRight ) DllStructSetData( $pRect, "Top", $iTop ) DllStructSetData( $pRect, "Bottom", $iBottom ) Local $iWidth = $iRight - $iLeft + 1 Local $iHeight = $iBottom - $iTop + 1 ; Set up the coordinate structures. Local $coordBufferCoord = _WinAPI_MakeDWord($iLeft, $iTop) Local $coordBufferSize = _WinAPI_MakeDWord($iWidth, $iHeight) Local $pBuffer = DllStructCreate("dword[" & $iWidth * $iHeight & "]") ; Read the console output. If _CmdReadConsoleOutput($hStdOut, $pBuffer, $coordBufferSize, $coordBufferCoord, $pRect) Then ; This variable holds the output string. Local $sText = "" For $j = 0 To $iHeight - 1 Local $sLine = "" 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, DllStructGetPtr($pBuffer) + ($j * $iWidth * 4) + ($i * 4)) ; Append the character. $sLine &= DllStructGetData($pCharInfo, "UnicodeChar") Next $sText &= StringStripWS( $sLine, 2 ) & @CRLF Next $sText = StringStripWS( $sText, 2 ) ; Ensure we read a valid percentage. If so return the cast to a number. Return $sText EndIf EndIf EndIf ; On failure we return -1 which is obviously not a valid percentage. Return -1 EndFunc ;==>_CmdGetText Func _GetConsoleScreenBufferInfo($hConsoleOutput, $pConsoleScreenBufferInfo) Local $aRet = DllCall("kernel32.dll", "int", "GetConsoleScreenBufferInfo", "hwnd", $hConsoleOutput, _ "ptr", _SafeGetPtr($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", _SafeGetPtr($pBuffer), "int", $coordBufferSize, "int", $coordBufferCoord, _ "ptr", _SafeGetPtr($pRect)) If @error Then SetError(@error, @extended, False) Return $aRet[0] EndFunc ; _CmdReadConsoleOutput() ; #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 _SafeGetPtr(Const ByRef $ptr) Local $_ptr = DllStructGetPtr($ptr) If @error Then $_ptr = $ptr Return $_ptr EndFunc ; _SafeGetPtr() Func _WinAPI_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 ;==>_WinAPI_MakeDWord And here's my test script: #include <WinAPI.au3> #include "CmdA.au3" $pCmd = Run( "cmd.exe" ) Sleep(1000) $hCmd = _CmdGetWindow( $pCmd ) $hCon = _CmdAttachConsole( $pCmd ) While True $cmdtext = _CmdGetText( $hCon ) MsgBox(0,"prompt",$cmdtext) Sleep(5000) WEnd The demo just launches a command prompt and displays the contents every 5 seconds. *Update*: Looks like my wild guess of writing the Left and Top values into the $coordBufferCoord was wrong, leaving it as 0,0 grabs the visible screen area. Maybe I need to use the Left and Top values as negative offsets to get the scrolled-off-the-top text.
-
I'm trying to get Valik's ScreenScrape.au3 working. I've made a _WinAPI_MakeDWord function which has been removed from AutoIt to get it to compile, maybe something else has changed since this script was written. It doesn't pick up the percentage, it just jumps to 100% when the process terminates. Any ideas? Here's the full script that I am running: #Region Includes #include <WinAPI.au3> #EndRegion Includes #Region Options/Singleton Opt("MustDeclareVars", True) #EndRegion Options/Singleton #Region Global Variables 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" #EndRegion Global Variables #Region Main body of code Global $g_nExitCode = Main() Exit $g_nExitCode #EndRegion Main body of code #Region Main() ; =================================================================== ; Main() ; ; The main program body. ; Parameters: ; None. ; Returns: ; None. ; =================================================================== Func Main() ; Sanity check to ensure the script is compiled. If Not @Compiled Then MsgBox(4096 + 16, "Error", "This script must be compiled.") Return -1 EndIf ; The 7-Zip command line. Local Const $sCmd = '"c:\Program Files\7-Zip\7z.exe" a c:\txt c:\Existing_Contracts_401.SCUN.txt' ; The show flag, change to @SW_HIDE to prove it works while hidden. Local Const $nShow = @SW_SHOW ; Run the 7-Zip command line. Local $pid = Run($sCmd, "", $nShow) ; Brief pause to let 7-Zip get started. Sleep(1000) ; Create a progress meter. ProgressOn("7-Zip percent", "Backing up...", "0%", 0, 0) ; Open the 7-Zip percent reader. Local $hPercent = Open7ZipPercent($pid) ; Loop on the process existence. While ProcessExists($pid) ; Read the percent and update the progress bar. Local $nPercent = Read7ZipPercent($hPercent) If $nPercent >= 0 Then ProgressSet($nPercent, $nPercent & "%") Sleep(50) WEnd ; We're finished. ProgressSet(100, "100%", "Done") ; Give time to see we're finished. Sleep(1000) ; Cleanup. Close7ZipPercent($hPercent) FileDelete(@ScriptDir & "\Backup.7z") EndFunc ; Main() #EndRegion Main() #Region Primary Functions Func Open7ZipPercent($pid) ; Try to attach to the console of the PID. If _AttachConsole($pid) Then ; The user should treat this as an opaque handle, but internally it contains a handle ; and some structures. Local $vHandle[4] $vHandle[0] = _GetStdHandle($STD_OUTPUT_HANDLE) ; STDOUT Handle $vHandle[1] = DllStructCreate($_CONSOLE_SCREEN_BUFFER_INFO) ; Screen Buffer structure $vHandle[2] = DllStructCreate("dword[4]") ; Data buffer $vHandle[3] = DllStructCreate($_SMALL_RECT) ; SMALL_RECT structure ; Return the handle on success. Return $vHandle EndIf ; Return 0 on failure. Return 0 EndFunc ; Open7ZipPercent() Func Close7ZipPercent(ByRef $vHandle) ; Basic sanity check to validate the handle. If UBound($vHandle) <> 4 Then Return False ; Detach the console. _FreeConsole() ; Destroy the handle. $vHandle = 0 ; Return success. Return True EndFunc ; Close7ZipPercent() Func Read7ZipPercent(ByRef $vHandle) ; Basic sanity check to validate the handle. If UBound($vHandle) = 4 Then ; Create some variables for convenience. Local Const $hStdOut = $vHandle[0] Local Const $pConsoleScreenBufferInfo = $vHandle[1] Local Const $pBuffer = $vHandle[2] Local Const $pSmallRect = $vHandle[3] ; Try to get the screen buffer information. If _GetConsoleScreenBufferInfo($hStdOut, $pConsoleScreenBufferInfo) Then ; Set up the coordinate structures. Local $coordBufferSize = _WinAPI_MakeDWord(4, 1) Local $coordBufferCoord = _WinAPI_MakeDWord(0, 0) ; Load the SMALL_RECT with the projected text position. DllStructSetData($pSmallRect, "Left", DllStructGetData($pConsoleScreenBufferInfo, "dwCursorPositionX") - 4) DllStructSetData($pSmallRect, "Top", DllStructGetData($pConsoleScreenBufferInfo, "dwCursorPositionY")) DllStructSetData($pSmallRect, "Right", DllStructGetData($pConsoleScreenBufferInfo, "dwCursorPositionX")) DllStructSetData($pSmallRect, "Bottom", DllStructGetData($pConsoleScreenBufferInfo, "dwCursorPositionY")) ; Read the console output. If _ReadConsoleOutput($hStdOut, $pBuffer, $coordBufferSize, $coordBufferCoord, $pSmallRect) Then ; This variable holds the output string. Local $sPercent = "" ; We iterate over 3 characters because that's all we read. For $i = 0 To 3 ; 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, DllStructGetPtr($pBuffer) + ($i * 4)) ; Append the character. $sPercent &= DllStructGetData($pCharInfo, "UnicodeChar") Next ; Ensure we read a valid percentage. If so return the cast to a number. If StringRight($sPercent, 1) = "%" Then Return Number($sPercent) EndIf EndIf EndIf ; On failure we return -1 which is obviously not a valid percentage. Return -1 EndFunc ; Read7ZipPercent() #EndRegion Primary Functions #Region Helper Functions Func _GetStdHandle($nHandle) Local $aRet = DllCall("kernel32.dll", "hwnd", "GetStdHandle", "dword", $nHandle) If @error Then Return SetError(@error, @extended, $INVALID_HANDLE_VALUE) Return $aRet[0] EndFunc ; _GetStdHandle() Func _AttachConsole($nPid) Local $aRet = DllCall("kernel32.dll", "int", "AttachConsole", "dword", $nPid) If @error Then Return SetError(@error, @extended, False) Return $aRet[0] EndFunc ; _AttachConsole() Func _FreeConsole() Local $aRet = DllCall("kernel32.dll", "int", "FreeConsole") If @error Then Return SetError(@error, @extended, False) Return $aRet[0] EndFunc ; _FreeConsole() Func _GetConsoleScreenBufferInfo($hConsoleOutput, $pConsoleScreenBufferInfo) Local $aRet = DllCall("kernel32.dll", "int", "GetConsoleScreenBufferInfo", "hwnd", $hConsoleOutput, _ "ptr", _SafeGetPtr($pConsoleScreenBufferInfo)) If @error Then Return SetError(@error, @extended, False) Return $aRet[0] EndFunc ; _GetConsoleScreenBufferInfo() Func _ReadConsoleOutput($hConsoleOutput, $pBuffer, $coordBufferSize, $coordBufferCoord, $pSmallRect) ; 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", _SafeGetPtr($pBuffer), "int", $coordBufferSize, "int", $coordBufferCoord, _ "ptr", _SafeGetPtr($pSmallRect)) If @error Then SetError(@error, @extended, False) ; MsgBox( 0, "ok", $aRet[0] ) Return $aRet[0] EndFunc ; _ReadConsoleOutput() Func _SafeGetPtr(Const ByRef $ptr) Local $_ptr = DllStructGetPtr($ptr) If @error Then $_ptr = $ptr Return $_ptr EndFunc ; _SafeGetPtr() Func _WinAPI_MakeDWord($LoWORD, $HiWORD) Local $tDWord = DllStructCreate("uint32") Local $tWords = DllStructCreate("word;word", DllStructGetPtr($tDWord)) DllStructSetData($tWords, 1, $LoWORD) DllStructSetData($tWords, 2, $HiWORD) Return DllStructGetData($tDWord, 1) EndFunc ;==>_WinAPI_MakeQWord #EndRegion Helper Functions It seems to be failing after the ReadConsoleOutputW function call, which is returning 0 in the first array element. *Update:* Why is it that you only notice your stupid mistakes after you've posted them on a public forum? File this under "you can't just make shit up and expect the computer to know what you are talking about". My _WinAPI_MakeDWord was wrong, I needed to say DllStructCreate("dword") and not DllStructCreate("uint32"). D'oh. Why was _WinAPI_MakeDWord removed?
-
I usually do this not with tabs but with an expand button that makes the window bigger and reveals the extra controls. I also have an un-expand button that is the same position and shape as the expand button, and each of the two buttons will hide itself and un-hide the other when clicked. Case $bExpand _ClientResize( $hGUI, $WinWidth*2, $WinHeight ) GUICtrlSetState( $bExpand, $GUI_HIDE ) GUICtrlSetState( $bImpand, $GUI_SHOW ) Case $bImpand _ClientResize( $hGUI, $WinWidth, $WinHeight ) GUICtrlSetState( $bImpand, $GUI_HIDE ) GUICtrlSetState( $bExpand, $GUI_SHOW )
-
AttachConsole and CreateFile DLL calls
PhilHibbs replied to PhilHibbs's topic in AutoIt GUI Help and Support
OK I've had a go at cannibalising Screen_Scrape.au3. The original script won't compile since WinAPI.au3 no longer has a _WinAPI_MakeDWord function, and also I don't have 7Zip so I can't use it anyway. Here's my full script, which returns "0" instead of the screen contents. #include <WinAPI.au3> #include "VarDump.au3" 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" $pCmd = Run( "cmd.exe" ) $hCmd = _CmdGetWindow( $pCmd ) $hCon = _CmdAttachConsole( $pCmd ) $cmdtext = _CmdGetText( $hCmd, $hCon ) MsgBox( 0, "text", $cmdtext ) 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 Func _CmdAttachConsole( $pCmd ) Local $aRet = DllCall("kernel32.dll", "int", "AttachConsole", "dword", $pCmd) If @error Then Return SetError(@error, @extended, False) ; Return the handle on success. Return _CmdGetStdHandle($STD_OUTPUT_HANDLE) ; STDOUT Handle EndFunc ; _CmdAttachConsole() 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 ; _GetStdHandle() Func _CmdGetText( $hWin, $hConsole ) Local $bScrInfo = DllStructCreate($_CONSOLE_SCREEN_BUFFER_INFO) ; Screen Buffer structure ; Try to get the screen buffer information. If _GetConsoleScreenBufferInfo($hConsole, $bScrInfo) Then ; Set up the coordinate structures. Local $coordBufferSize = _WinAPI_MakeDWord(4, 1) Local $coordBufferCoord = _WinAPI_MakeDWord(0, 0) Local $bRect = DllStructCreate($_SMALL_RECT) ; Load the SMALL_RECT with the projected text position. DllStructSetData($bRect, "Left", DllStructGetData($bScrInfo, "Left")) DllStructSetData($bRect, "Top", DllStructGetData($bScrInfo, "Top")) DllStructSetData($bRect, "Right", DllStructGetData($bScrInfo, "Right")) DllStructSetData($bRect, "Bottom", DllStructGetData($bScrInfo, "Bottom")) Local $iWidth = DllStructGetData( $bRect, "Right") - DllStructGetData( $bRect, "Left") + 1 Local $iHeight = DllStructGetData( $bRect, "Bottom") - DllStructGetData( $bRect, "Top") + 1 Local $bScrContent = DllStructCreate("dword[" & ($iWidth * $iHeight) & "]") ; Read the console output. ; 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", $hConsole, _ "ptr", _CmdSafeGetPtr($bScrContent), _ "int", $coordBufferSize, _ "int", $coordBufferCoord, _ "ptr", _CmdSafeGetPtr($bRect) ) If @error Then SetError(@error, @extended, False) If $aRet[0] Then ; This variable holds the output string. Local $sScreen = "" ; We iterate over 3 characters because that's all we read. For $i = 0 To $iHeight - 1 Local $sLine = "" For $j = 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, DllStructGetPtr($bScrContent) + ($i * 4)) ; Append the character. $sLine &= DllStructGetData($pCharInfo, "UnicodeChar") Next $sScreen &= StringStripWS( $sLine, 2 ) & @CRLF Next $sScreen = StringStripWS( $sScreen, 2 ) EndIf EndIf EndFunc ;==>_CmdGetText 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 _CmdSafeGetPtr(Const ByRef $ptr) Local $_ptr = DllStructGetPtr($ptr) If @error Then $_ptr = $ptr Return $_ptr EndFunc ; _SafeGetPtr() Func _WinAPI_MakeDWord($LoWORD, $HiWORD) Local $tDWord = DllStructCreate("uint34") Local $tWords = DllStructCreate("word;word", DllStructGetPtr($tDWord)) DllStructSetData($tWords, 1, $LoWORD) DllStructSetData($tWords, 2, $HiWORD) Return DllStructGetData($tDWord, 1) EndFunc ;==>_WinAPI_MakeQWordIt's failing in the _ReadConsoleOutput call, the ReadConsoleOutputW API returns 0 as the first array element, but it looks like Screen_Scrape.au3 does the same for me. Any ideas? Full output of the ReadConsoleOutputW call: [0] => Integer(0) [1] => Pointer(0x00000007) [2] => Pointer(0x015695C0) [3] => Integer(0) [4] => Integer(0) [5] => Pointer(0x0156A6E8) p.s. Yes I am compiling it. *Update:* I've installed 7Zip and tried ScreenScrape.au3 again and it isn't picking up the %, the progress bar doesn't appear until it's finished when it jumps to 100%.