Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Getting the output of a console application


  • Please log in to reply
9 replies to this topic
Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
We don't need any external tool or dll call. Sending keystrokes allows marking and copying the whole (or part of the) content of the output buffer of the console to the clipboard. We then process the clipboard in the script, to get the output of a console application. Here is a working example: Hello World!
SetTitleMatchMode 3                          ; exact match required
!c::
   Settimer GetIt, 30                        ; another thread gets buffer
   RunWait %comspec% /k echo Hello World!    ; will be closed from GetIt
                                             ; at this point: console buffer -> ClipBoard
   StringReplace Text,ClipBoard,`r`n%A_WorkingDir%>,,R ; remove last command prompt
   MsgBox %Text%
Return

GetIt:
   IfWinNotExist %comspec%                   ; title changed while busy
      Return                                 ; keep trying until idle
   Settimer GetIt, Off                       ; need not run any more
   WinActivate %comspec%                     ; no title suffix when done
   ClipBoard =
   Send !{Space}es{Enter}                    ; select all, copy to clipboard
   ClipWait 2
   Send !{Space}c                            ; close console window
Return
While a console application runs it changes the title of the window. Monitoring the change tells us, when the application terminates. We run the desired program via cmd.exe. Its full path is stored in %comspec%, which is the title of its window when idle. "cmd.exe /k" runs the program, and remains open. Before running the program we start a timer, which checks in every 30 ms if a window exists with the idle cmd.exe title. If it is found, the checking can stop. We activate from the context menu (Alt-Space) Edit/Select all. Sending Enter copies the selection to the clipboard, from where we only need to remove the bottommost command prompt to get the output of the console application.

We have to make sure the buffer is large enough for holding the full output. We can set it up to 999 lines via the properties of the command prompt, and making it the default. The "Select all" menu item only selects the beginning of the buffer, so a large one does not slow things down. Another approach is to use "|more" and a loop to get the output one screen at a time.

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
This version is slightly faster and more robust: it is not disturbed if there are other cmd windows open. When the desired program gets started (Alt-C hotkey), the process ID of its window is saved. The GetIt subroutine checks the title of the corresponding window every 30 ms. If it becomes %comspec%, it indicates that the console program has finished. Then the used part of the buffer is copied to the clipboard and the cmd window gets closed. The original thread now continues and processes the output (in this case the directory listing of c:\).
RunWait %comspec%                      ; another cmd window for DEMONSTRATION only

ExitApp



!c::

   Settimer GetIt, 30                  ; the GetIt thread will get the buffer

   RunWait %comspec% /k dir c:\,,,PID  ; will be closed from GetIt

                                       ; at this point: console buffer -> ClipBoard

   StringReplace Text,ClipBoard,`r`n%A_WorkingDir%>,,R ; remove last command prompt

   MsgBox %Text%                       ; put here the code to process Text

Return



GetIt:

   WinGetTitle Title, ahk_pid %PID%    ; get the changing window title

   If Title <> %comspec%               ; program name affixed while busy

      Return                           ; keep trying until idle

   Settimer GetIt, Off                 ; need not run any more

   WinActivate ahk_pid %PID%           ; go to our console window

   ClipBoard =                         ; empty ClibBoard to see data comming

   Send !{Space}es{Enter}              ; select all = used buffer, copy to clipboard

   ClipWait 2                          ; don't hang here at an error

   WinClose ahk_pid %PID%              ; close console window

Return
Tested under XP SP2, with 999 lines long buffer and default command prompt (for different prompts you need to adapt the Text processing).

Dragonscloud
  • Members
  • 96 posts
  • Last active: Jul 21 2010 08:33 PM
  • Joined: 16 Jul 2005
Looks like that should replace cb.exe for most uses. :D Way cool!
I've added the post to my database.
“yields falsehood when preceded by its quotation” yields falsehood when preceded by its quotation.

AHKnow*
  • Guests
  • Last active:
  • Joined: --
Interesting... Good work.

LazyLarry
  • Guests
  • Last active:
  • Joined: --
I do not have a lot of scripitng knowledge, but play around when time is available.

I have always wanted a way to find when an exact webpage has loaded, not just some web page.

I use Control A, then copy, then look in string which works very good except it is flashy and attracts attendtion.

Would you comment on if this script of yours would help me with http://www.webscrape.com, which looks like it might, but would take some experimenting to see if it does?

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
The script above is monitoring the window title. Unfortunately, in case of a website, it changes when the content starts loading, not when it is done. I would use instead the status bar and (part of) the window title
#Persistent

SetTimer Wait

Return



Wait:

   ControlGetText Text, msctls_statusbar321, PageScrape

   If Text = Done

   {

      SetTimer Wait, Off

      MsgBox It says is has loaded

   }

Return


AHKnow*
  • Guests
  • Last active:
  • Joined: --

I do not have a lot of scripting knowledge, but play around when time is available.

I have always wanted a way to find when an exact webpage has loaded, not just some web page.

I use Control A, then copy, then look in string which works very good except it is flashy and attracts attention.


You can use the WinHide command with Internet Explorer.
You can use "Hide" with Run, Target [, WorkingDir, Max|Min|Hide|UseErrorLevel, OutputVarPID]

WinHide and Hide w/ Run/RunWait work well. I've noticed some behavioral differences in comparison to windows that are visible though... and its better to use WinActivate, IfWinExist, etc... but beware of issues with using WinWait and some other commands. Also, when using WinHide with Internet Explorer it seems ControlSetText or some combination would forcibly show the Window and I would have to re-WinHide it or use something else.

Before I proceed further, people can still determine if AutoHotkey scripts are running by looking for tray icons, checking the processes that are running, and by some other methods... I would advise against, trying to sneakily or illegally run scripts without a user's knowledge and have your scripts classified as malware or get yourself in legal trouble.

The advantage of WinHide and Hide, is that a number of things you do with AutoHotkey may annoy users of your script or various users may actively interfere with the operation of your script. People don't usually try to interfere with what they can't see. By hiding the Window or certain operations of your script you can avoid problems with users or even not annoy yourself, especially if you have numerous AutoHotkey scripts running at the same time.

tain
  • Members
  • 62 posts
  • Last active: May 21 2014 10:02 PM
  • Joined: 16 Feb 2010
Anyone get this to work post-XP?

  • Guests
  • Last active:
  • Joined: --
In WinXP SP3 it opens a cmd.exe window and just sits there.

garry
  • Spam Officer
  • 3219 posts
  • Last active: Sep 20 2018 02:47 PM
  • Joined: 19 Apr 2005
tested with XP SP3
important is what you send to DOS console when copy ( depending language )

(I think)
English
-Edit
-Select All
means
SendInput !{Space}es{Enter}

German
-Bearbeiten
-Alles Markieren
means
SendInput !{Space}ba{Enter}

;-- this copies a DOS-window to notepad -

f2=%a_scriptdir%\CopyDos.txt

Run, %ComSpec% /k ,,,PIDD
WinActivate ahk_pid %PIDD%
WinWaitActive ahk_pid %PIDD%

ifwinexist,ahk_pid %PIDD%
 {
 sleep,500
   ControlSend, ,CLS,ahk_pid %PIDD%, , ,                  ;send clear screen
   ControlSend, ,{enter},ahk_pid %PIDD%, , ,              ;send enter
 sleep,500
   ControlSend, ,dir,ahk_pid %PIDD%, , ,                  ;send Dos command dir
   ControlSend, ,{enter},ahk_pid %PIDD%, , ,              ;send enter
 sleep,1500
 ClipBoard =
  SendInput !{Space}es{Enter}            ; <<<<  important select/copy DOS english
  ;SendInput !{Space}ba{Enter}           ; select/copy DOS german
 ClipWait 2
 C2:=clipboard
 Fileappend,%C2%,%f2%             ;-- write copied DOS-window to a file
 run,%f2%
 }
return



another example

;-- example send to DOS window dir command hidden ----
;SetKeyDelay,10,10,
SendMode, Input
DetectHiddenWindows On
SetTitleMatchMode 2
F1="%A_scriptdir%\test55.txt"
DosCommand=dir>%f1%

Run %ComSpec% /k %DosCommand%,,hide,PID1
  WinWait %ComSpec% ahk_pid %PID1%
  WinActivate ahk_pid %PID1%
  ControlSend,,%doscommand% ,ahk_pid %PID1%
sleep,1000
process,close,%PID1%
run,%f1%
exitapp