communicating with a child process (redirecting STDIN and STDOUT) in Win32 
Author Message
 communicating with a child process (redirecting STDIN and STDOUT) in Win32

Hi Group,

I inherited a DOS executable which requests several parameters from the
user, entered one by one:

prompt: Please enter com port number
user  : 1
prompt: Please enter com port speed
user  : 57600
prompt: Please enter log file name
user  : whatever
prompt: Do you want to... (Y/N)?
user  : Y
...
some processing, progress displayed on the screen
....
Programs stops with message "100% completed".

Now, I would need to run this program automatically several times from a
Perl script depending on some results of this script.

I tried this idea to capture the first prompt from the executable

use strict;
use warnings;
use FileHandle;
use IPC::Open2;
my $got;
my $pid = open2(\*Reader, \*Writer, "< exefile.exe" );
print "$pid\n";
while ($got = <Reader>)
{
    print $got;

Quote:
}

...

It prints the pid (242 in this case) and just hangs.
Replacing the executable with "dir" gives me a nice directory listing as
expected.

I'm aware that Win32 IPC is far from perfect in comparing to *nix (not
that I have much experience in *nix) therefore I'm not sure it's even
doable under Win32, but if someone could give me some hints how to
start, I'd really be grateful.

Thanks and best regards,

Zoltan Kandi, M. Sc.



Sun, 25 Sep 2005 00:04:36 GMT  
 communicating with a child process (redirecting STDIN and STDOUT) in Win32
Quote:

> Hi Group,

> I inherited a DOS executable which requests several parameters from the
> user, entered one by one:

> prompt: Please enter com port number
> user  : 1
> prompt: Please enter com port speed
> user  : 57600
> prompt: Please enter log file name
> user  : whatever
> prompt: Do you want to... (Y/N)?
> user  : Y
> ...
> some processing, progress displayed on the screen
> ....
> Programs stops with message "100% completed".

> Now, I would need to run this program automatically several times from a
> Perl script depending on some results of this script.

> I tried this idea to capture the first prompt from the executable

> use strict;
> use warnings;
> use FileHandle;
> use IPC::Open2;
> my $got;
> my $pid = open2(\*Reader, \*Writer, "exefile.exe" );
> print "$pid\n";
> while ($got = <Reader>)
> {
>    print $got;
> }
> ...

> It prints the pid (242 in this case) and just hangs.
> Replacing the executable with "dir" gives me a nice directory listing as
> expected.

> I'm aware that Win32 IPC is far from perfect in comparing to *nix (not
> that I have much experience in *nix) therefore I'm not sure it's even
> doable under Win32, but if someone could give me some hints how to
> start, I'd really be grateful.

> Thanks and best regards,

> Zoltan Kandi, M. Sc.

Got one step further:

use strict;
use warnings;
use FileHandle;
use IPC::Open2;
my $got;

my $pid = open2(\*Reader, \*Writer, "exefile.exe" );
print $pid;

$|=1;

open(SAVEIN, "<&STDIN");

open(STDIN, "<&Reader");

while ($got = <STDIN>)
{
    print $got;

Quote:
}

close(SAVEIN);
close(STDIN);

will print the first row (out of four) of the first prompt
(and hangs afterwards).

Zoltan



Sun, 25 Sep 2005 00:39:17 GMT  
 communicating with a child process (redirecting STDIN and STDOUT) in Win32

Quote:

> Hi Group,

> I inherited a DOS executable which requests several parameters from the
> user, entered one by one:

> prompt: Please enter com port number
> user  : 1
> prompt: Please enter com port speed
> user  : 57600
> prompt: Please enter log file name
> user  : whatever
> prompt: Do you want to... (Y/N)?
> user  : Y
> ...
> some processing, progress displayed on the screen
> ....
> Programs stops with message "100% completed".

> Now, I would need to run this program automatically several times from
> a Perl script depending on some results of this script.

> I tried this idea to capture the first prompt from the executable

> use strict;
> use warnings;
> use FileHandle;
> use IPC::Open2;
> my $got;
> my $pid = open2(\*Reader, \*Writer, "< exefile.exe" );
> print "$pid\n";
> while ($got = <Reader>)
> {
>     print $got;
> }
> ...

> It prints the pid (242 in this case) and just hangs.

Well, it probably doesn't *just* hang.

The exefile has probably done printf("prompt: Please enter com port
number\n"), or the equivilant, at this point.  However, since the stdout
filehandle of exefile is a pipe to your perl program's Reader handle,
instead of being a terminal, it doesn't automatically flush the handle,
and the data doesn't get written to the actual stdout filedescriptor
(aka fileno(stdout)).

So, in effect, the prompt has been *almost,* but not quite written.
Sadly, "almost but not quite," is, from your perl program's point of
view, the same as "not at all."

Quote:
> Replacing the executable with "dir" gives me a nice directory listing
> as expected.

That's because "dir" isn't waiting for user input.

Quote:
> I'm aware that Win32 IPC is far from perfect in comparing to *nix (not
> that I have much experience in *nix) therefore I'm not sure it's even
> doable under Win32, but if someone could give me some hints how to
> start, I'd really be grateful.

Redirect the program's output to a file, and ignore the fact that you
aren't getting prompts; after you've sent all your data, wait for the
program to exit (with waitpid($pid, 0)); then, read in the file.

   open( OUT_FROM_EXEFILE, ">+", "tmpfile.$$.txt" ) or die horribly;
   my $pid = open( ">&OUT_FROM_EXEFILE", *Writer, "exefile.exe" );
   print Writer "1\n57600\nwhatever\nY\n";
   close Writer or die horribly;
   waitpid( $pid, 0 ) or die horribly;
   my $err_code = $?;
   seek OUT_FROM_EXEFILE, 0, 0 or die horribly;
   while( my $got = <OUT_FROM_EXEFILE> ) {
      print $got;
   }
   close OUT_FROM_EXEFILE or die horribly;
   unlink "tmpfile.$$.txt" or die horribly;
   $err_code and die horribly;

Or, write your input data to a file, redirect the program's stdin from
that file, and read from the program's stdout as a pipe.

   open( IN_TO_EXEFILE, "<+", "tmpfile.$$.txt" ) or die horribly;
   print "1\n57600\nwhatever\nY\n";
   seek IN_TO_EXEFILE, 0, 0 or die horribly;
   my $pid = open( *Reader, "<&IN_TO_EXEFILE", "exefile.exe" );
   close IN_TO_EXEFILE or die horribly;
   while( my $got = <Reader> ) {
      print $got;
   }
   close Reader or die horribly;
   unlink "tmpfile.$$.txt" or die horribly;
   waitpid( $pid, 0 ) or die horribly;
   $? and die horribly;

--





Sun, 25 Sep 2005 02:22:02 GMT  
 communicating with a child process (redirecting STDIN and STDOUT) in Win32

[snip non working code]

Quote:

> Well, it probably doesn't *just* hang.

> The exefile has probably done printf("prompt: Please enter com port
> number\n"), or the equivilant, at this point.  However, since the stdout
> filehandle of exefile is a pipe to your perl program's Reader handle,
> instead of being a terminal, it doesn't automatically flush the handle,
> and the data doesn't get written to the actual stdout filedescriptor
> (aka fileno(stdout)).

> So, in effect, the prompt has been *almost,* but not quite written.
> Sadly, "almost but not quite," is, from your perl program's point of
> view, the same as "not at all."

>>Replacing the executable with "dir" gives me a nice directory listing
>>as expected.

> That's because "dir" isn't waiting for user input.

>>I'm aware that Win32 IPC is far from perfect in comparing to *nix (not
>>that I have much experience in *nix) therefore I'm not sure it's even
>>doable under Win32, but if someone could give me some hints how to
>>start, I'd really be grateful.

> Redirect the program's output to a file, and ignore the fact that you
> aren't getting prompts; after you've sent all your data, wait for the
> program to exit (with waitpid($pid, 0)); then, read in the file.

>    open( OUT_FROM_EXEFILE, ">+", "tmpfile.$$.txt" ) or die horribly;
>    my $pid = open( ">&OUT_FROM_EXEFILE", *Writer, "exefile.exe" );
>    print Writer "1\n57600\nwhatever\nY\n";
>    close Writer or die horribly;
>    waitpid( $pid, 0 ) or die horribly;
>    my $err_code = $?;
>    seek OUT_FROM_EXEFILE, 0, 0 or die horribly;
>    while( my $got = <OUT_FROM_EXEFILE> ) {
>       print $got;
>    }
>    close OUT_FROM_EXEFILE or die horribly;
>    unlink "tmpfile.$$.txt" or die horribly;
>    $err_code and die horribly;

> Or, write your input data to a file, redirect the program's stdin from
> that file, and read from the program's stdout as a pipe.

>    open( IN_TO_EXEFILE, "<+", "tmpfile.$$.txt" ) or die horribly;
>    print "1\n57600\nwhatever\nY\n";
>    seek IN_TO_EXEFILE, 0, 0 or die horribly;
>    my $pid = open( *Reader, "<&IN_TO_EXEFILE", "exefile.exe" );
>    close IN_TO_EXEFILE or die horribly;
>    while( my $got = <Reader> ) {
>       print $got;
>    }
>    close Reader or die horribly;
>    unlink "tmpfile.$$.txt" or die horribly;
>    waitpid( $pid, 0 ) or die horribly;
>    $? and die horribly;

Hi and thanks for the recommendations.

However, in the real life, it's not as simple as that. The executable -
depending on user input - may return sometimes different prompts.
For example, when asked, the user types in the name of the logfile to be
created. The executable checks for duplicate and if this file already
exists, gives an extra prompt "do you want to overwrite this file" which
the user needs to confirm or cancel.

Therefore I had hoped that I could do something like (pseudocode):

....
open2(*Reader, *Writer, "exefile.exe");
....
while (<Reader>)
{
    last if /enter logfile name:/ig;

Quote:
}

print Writer "$logfilename\n";
while (<Reader>)
{
    print(Writer "Y\n"),last if /overwrite existing logfile?/ig;
    last if /whatever the next prompt is/ig;
Quote:
}

....

etc, a fully flexible dialog more similar to a TCP/IP client-server
communication.

Best regards,

Zoltan



Sun, 25 Sep 2005 19:50:08 GMT  
 communicating with a child process (redirecting STDIN and STDOUT) in Win32

Quote:


[snip]
> > Redirect the program's output to a file, and ignore the fact that you
> > aren't getting prompts; after you've sent all your data, wait for the
> > program to exit (with waitpid($pid, 0)); then, read in the file.
[snip]
> > Or, write your input data to a file, redirect the program's stdin
> > from that file, and read from the program's stdout as a pipe.
[snip]
> Hi and thanks for the recommendations.

> However, in the real life, it's not as simple as that. The executable -
> depending on user input - may return sometimes different prompts.
> For example, when asked, the user types in the name of the logfile to
> be created. The executable checks for duplicate and if this file
> already exists, gives an extra prompt "do you want to overwrite this
> file" which the user needs to confirm or cancel.

I'm not quite sure what to suggest at this point.  If you were doing
this with some form of *nix, then I would reccommend IO::Pty or Expect.
You would use one of those to create a psuedo-terminal; the program,
seeing that it's hooked up to a terminal instead of a pipe or file,
would then disable the block-mode buffering (flush every BUFSIZ bytes),
and switch to line-mode buffering (flush after every newline).

But windows doesn't have psuedo-terminals, AFAIK.

Is there any chance you can alter exefile's source?  If so, then you can
add a couple lines:
   char new_stdout_buffer[BUFSIZ];
   setvbuf(stdout, new_stdout_buffer, _IOLBF, BUFSIZ);
[or something like that]

Or perhaps, read it's source to learn if there's a command-line option
or environment variable which you can set to disable this buffering?

Anyway, unless you discover a perl module for creating psuedo-terminals
on windows, then this is getting way off-topic for clp.modules, since
this has nothing to do with the IPC::Open2 module, and is completely
dependent on the program which you're trying to read from/write to.

--





Mon, 26 Sep 2005 03:19:25 GMT  
 
 [ 7 post ] 

 Relevant Pages 

1. Redirecting stdin and stdout for child

2. Communicating with a child process

3. Can you redirect STDIN/STDOUT on the fly ?

4. synchronistaion of STDIN with redirected STDOUT

5. Redirecting STDIN and STDOUT

6. redirecting stdin and stdout

7. Redirecting STDIN and STDOUT to Internet

8. Redirecting STDIN/STDOUT to socket

9. HELP!! Redirecting STDIN and STDOUT to UDP socket

10. STDIN in child process

11. STDIN handoff to child process

12. tie()ing STDOUT to a file being written to by anothe (child) process

 

 
Powered by phpBB® Forum Software