Jump to content
Sign in to follow this  
tremolux66

Looking for a clean way to capture RunWait output

Recommended Posts

Initial Problem

I've written several scripts with the following sequence:

  1. Execute a program using Run w/stdout+stderr captured
    • Typically processes all the files in one directory tree to populate a second tree
  2. Execute a second program (also with Run) to monitor the products of the first program and
    • Display a progress bar (percentage of output files complete)
    • Also monitor the first program's process and exit when it terminates
  3. The script then calls ProcessWaitClose (no timeout) on the first program's process and
    • Checks the first program's results
    • Kills the monitor program if it hasn't already exited on its own.

Sometimes, ProcessWaitClose returns 1 with @error = 0 and @extended = 0xCCCCCCCC (actually, 0xFFFFFFFFCCCCCCCC), which seems ambiguous: the documentation says that @error = non-zero and @extended = 0xCC... means an invalid PID (unclear what the return value is), and 1 is returned for non-existent processes (but no mention of @extended). The 1/0/0xCC... result seems to occur when the first program exits very quickly (with or without an error). Since the exit value is not available, the script scans the program's output and tries to determine whether it ran successfully. This has gotten complicated and unreliable.

Partial Fix

I've now implemented a much simpler approach that works for most cases:

  1. Modify the monitor program so that it ignores the other program's process (the monitor always gets killed by the script anyway)
  2. Execute the monitor program first using Run, then execute the processing program with RunWait
  3. When RunWait returns, the child process exit value is available, so the script can ignore its output (which isn't available anyway)
  4. If the monitor program is still running, kill it.

Remaining Issue

However, there are still a couple of cases where it's necessary to get both the exit value from the processing program and its output. Since RunWait doesn't capture stdout and stderr for the parent script, it's looking like I'll have to call RunWait and redirect the 2 streams to a temp file and then scan it. Also, to do the redirect, I think I'll have to use @ComSpec to execute the processing program, which adds an undesired layer.

Does anybody have a better (cleaner) way to handle these cases?


When the going gets tough, the tough start coding.

Share this post


Link to post
Share on other sites

i certainly would never implement it in three separate processes. I would call processing functions that used the Progress bar udf and scan output as necessary until done.

Edited by Earthshine

My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites

This is what I do in AutoIt3Wrapper when I understand your question correctly.
It shells the program, captures the output constandly and then gets the return/exit code from the process closed.

These are the lines I use for all programs I shell:

$Pid = Run('"program" /parameter', '', @SW_HIDE, $STDOUT_CHILD + $STDERR_CHILD)
$Handle = _ProcessExitCode($Pid)
$Return_Text = ShowStdOutErr($Pid)
$ExitCode = _ProcessExitCode($Pid, $Handle)
_ProcessCloseHandle($Handle)
StdioClose($Pid)

You ofcourse need to get the UDF/Funcs as well from the source.

Jos

Edited by Jos

SciTE4AutoIt3 Full installer Download page   - Beta files       Read before posting     How to post scriptsource   Forum etiquette  Forum Rules 
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Share this post


Link to post
Share on other sites

I would test that code but can't find the udf's. bunches of process udf but none with those :blink:

Edited by Earthshine

My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites

They are in AutoIt3Wrapper itself as they were written quite some time ago. ;)

SciTE has this great tool Ctrl+j when the carrot is on the Funcname which will jump strait to it. 
Ctrl+Shift+j will jump back.

Jos 


SciTE4AutoIt3 Full installer Download page   - Beta files       Read before posting     How to post scriptsource   Forum etiquette  Forum Rules 
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Share this post


Link to post
Share on other sites

@Jos: Thanks for the suggestion; I'll look into it. It was frustrating to lose the exit code, but the simple fix I outlined takes care of that for the exit-only cases. For the capture+exit cases, your approach may very well do the trick.

@Earthshine: The main reason the monitoring programs are separate is that they're pretty generic and get used in other scenarios as well. For example, the one that tracks the number of output files also gets run in the background from Bash scripts, as does another that tracks the size of an output file.

Note that in some cases, the processing program that's being executed is pretty simple (e.g., using Cygwin's cp command for a large recursive copy). In other cases, the processing is more complex and involves multiprocessing (e.g., transforming thousands of files using up to 2 dozen simultaneous instances (edit: "threads" but not really) over several dozen processors [within a single computer]).

 

Edited by tremolux66
Reworded a portion for clarity.

When the going gets tough, the tough start coding.

Share this post


Link to post
Share on other sites

Never mind - I figured it out.

I extracted the following from AutoIt3Wrapper.au3 into a separate file:

  • __ConsoleWrite()
  • _ProcessCloseHandle()
  • _ProcessExitCode()
  • ShowStdOutErr()

I renamed the functions (inserted a prefix), added/edited comments, etc. and it looks like I'm good to go. Passes syntax-checking; on to building the system and unit-testing.

Thanks again.

Original message:

On 12/18/2017 at 1:34 PM, Jos said:

You of course need to get the UDF/Funcs as well from the source.

@Jos Does this mean I need to extract the functions I want to use (along with any other required code) from AutoIt3Wrapper.au3 into a separate file?

(As opposed to:  #include <...\AutoIt3Wrapper.au3>  ?)

I suspect the answer is "yes", but want to make sure I understand correctly.

Edited by tremolux66
Answered my own question.

When the going gets tough, the tough start coding.

Share this post


Link to post
Share on other sites
6 hours ago, tremolux66 said:

Jos Does this mean I need to extract the functions I want to use (along with any other required code) from AutoIt3Wrapper.au3 into a separate file?

(As opposed to:  #include <...\AutoIt3Wrapper.au3>  ?)

That is what indeed would do. :)

Jos


SciTE4AutoIt3 Full installer Download page   - Beta files       Read before posting     How to post scriptsource   Forum etiquette  Forum Rules 
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Share this post


Link to post
Share on other sites

You can also look in the Help File at the example for _WinAPI_GetExitCodeProcess.  These are almost exactly the same functions as the ones that Jos uses, but are included in the WinAPI libraries, under slightly different names, that is included with AutoIt.  

 

Adam

 

Share this post


Link to post
Share on other sites
8 hours ago, AdamUL said:

You can also look in the Help File at the example for _WinAPI_GetExitCodeProcess.  These are almost exactly the same functions as the ones that Jos uses, but are included in the WinAPI libraries, under slightly different names, that is included with AutoIt.  

 

Adam

 

@AdamUL: Thanks for the pointer. :)

Lazy person that I am, I'll probably continue using the sample code I got from @Jos since I've already incorporated it into my scripts. ;)


When the going gets tough, the tough start coding.

Share this post


Link to post
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By WoodGrain
      Hi All,
      Trying to open windows explorer to a WebDav location and it's not working quite how I want, on the computers it is setup as a "network location" (as opposed to a "mapped drive", and this unfortunately can't be changed), the "Data" WebDav folder sits directly under "This PC" if that's an easier way to get to it. any suggestions as to what I can correct to get the 2nd example to work?
      ; This works, but I'm trying to avoid this as users normally see the URL style in the 2nd example below $folderToOpen = "\\mycompany.sharepoint.com@SSL\DavWWWRoot\Data" Run("Explorer.exe " & $folderToOpen) ; This does not work, it tries to open the WebDav url in the default web browser $folderToOpen = "https://mycompany.sharepoint.com/Data" Run("Explorer.exe " & $folderToOpen) ShellExecute also opens it in the default browser.
      Saw _WinAPI_ShellOpenFolderAndSelectItems but couldn't get the 2nd example to work.
      If I manually open Windows Explorer and paste in https://mycompany.sharepoint.com/Data it loads the WebDav directory without issue.
      If I have to use the pathing from the first example it is fine, just trying to give users a familiar experience.
      Thanks!
    • By nacerbaaziz
      hello autoit team
      is there any wey to check if any process run as admin or no?
      i mean e.g if i want to restart any process, now i have the ability to get the process path and commands line
      what i need is a wey to check if the process was runing as admin or no to restart it with the same state.
      here is the part that am using it to restart the process
      func _processRestart($i_pid, $s_ProcessPath) if not (ProcessExists($i_ProcessPid)) then return SetError(1, 0, -1) local $s_ProcessWorkDir = _WinAPI_GetProcessWorkingDirectory($i_ProcessPid) ProcessClose($i_ProcessPid) ProcessWaitClose($i_ProcessPid) ProcessWait(ShellExecute($i_pid,"", $s_ProcessWorkDir)) ProcessesGetList() return true endFunc thanks in advance
    • By lonardd
      Hi
      I have to run an executable with a parameter preceded by a /, like this:
      c:\myfolder\Tools\AutomaticRun\myexe.EXE /filename=c:\myfolder\Tools\AutomaticRun\myTemplate.xml")
      I tried both this:
      $iReturn = RunWait ("c:\myfolder\Tools\AutomaticRun\myexe.EXE"," /filename=c:\myfolder\Tools\AutomaticRun\myTemplate.xml")
      and using COMSPEC as per some posted suggestions on this forum:
      Run(@comspec & ' /c "c:\myfolder\Tools\AutomaticRun\myexe.EXE" /filename=c:\myfolder\Tools\AutomaticRun\myTemplate.xml')
      They both seem to fail.
      Can you please tell me what I'm doing wrong?
      Thanks
      Dave
       
    • By ohaya
      Hi,
      I am trying to use ConsoleWrite() to output some debug to stdout/console on a Windows command (cmd) window, but it seems like nothing is being output.
      I noted that the help says:
      but what does that mean (the "compiled as a console application" part?
      I have also tried adding
      to the beginning of my .au3 and re-compiling, but when I run the .exe in a command window, nothing is being output?
      How do I get the output from ConsoleWrite() to appear?
      Thanks,
      Jim
    • By AnonymousX
      So I just got a new computer, and instantly went and installed Autoit onto it. I selected run script as default action when clicking on an au3 file, however every time I do this it opens the script in the editor. I can from there run the script no problem.
      I've tried reinstalling and checking the settings by hitting "Ctrl+1" and have confirmed it is set to run, but yet it just continues to open in the editor.
      Any ideas why this is happening or how to solve?
      New system is windows 10, old was windows 7
×
×
  • Create New...