Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling

Open a second DOS window

by bart (Canon)
on Oct 08, 2003 at 15:05 UTC ( #297621=perlquestion: print w/replies, xml ) Need Help??

bart has asked for the wisdom of the Perl Monks concerning the following question:

I'd like to use the standard DOS box, that perl displays when running a perl script on my Windows box, for my normal output, and I'd like to add another DOS box, for my STDERR, for info/error messages, without interfering with my normal output.

I didn't find anything on CPAN, the docs of Win32::Console say:

A process cannot be associated with more than one console, so this method will fail if there is already an allocated console.

Perhaps somebody here has done this before? If so, can you share your recipe?

Replies are listed 'Best First'.
Re: Open a second DOS window
by Thelonius (Priest) on Oct 08, 2003 at 18:29 UTC
    There probably isn't a way to do it with one process. However, you can use one process to display whatever is sent through a socket (or named pipe ...) and just connect STDERR to the socket. E.g. here's the program to show the output:
    #!perl -w # usage: port use IO::Socket; use strict; $| = 1; $SIG{CHLD} = 'IGNORE'; my $localport = shift; my $socklisten = IO::Socket::INET->new(LocalPort => $localport, Listen => 2, Reuse => 1, Proto => 'tcp') or die "Cannot open sock on $localport: $!\n"; while (my $readport = $socklisten->accept) { print "Accepted new connection at ", scalar(localtime), "\n"; print while <$readport>; print "Connection closed at ", scalar(localtime), "\n"; }
    You can start that program independently or you could have the main program start it as below (in which case you would want to take out the outer while loop (replace while with if)):
    #!perl -w use IO::Socket; use strict; my $errsocket = "1999"; system("start 1999"); sleep(5); *STDERR = IO::Socket::INET->new( Proto => "tcp", PeerAddr => "localhost:$errsocket", Timeout => 30, ) or die "cannot create socketremote: $!\n"; warn "This is a test"; print STDERR "testing\n"; sleep(10);
    Note that there's an awkward sleep() here to wait an undetermined time for the listener to start. This race condition could be fixed, but it might be simpler to just run the showerr program independently first.
      Here's a better version of my program above, combined into one program and with the race condition fixed:
      #!perl -w use Socket; use IO::Socket; use Getopt::Std; use strict; $| = 1; my %opts; getopts("e:", \%opts); if ($opts{e}) { showerrs($opts{e}); } my $socklisten = IO::Socket::INET->new(LocalPort => 0, Listen => 2, Reuse => 1, Proto => 'tcp') or die "Cannot open socket: $!\n"; my ($port, $myaddr) = sockaddr_in(getsockname($socklisten)); print "port = $port\n"; # Here we start the error process system("start perl $0 -e $port\n"); # should put alarm() timeout around this section if (my $readport = $socklisten->accept) { print "reading from port\n"; chomp(my $portback = <$readport>); print "Connecting to $portback\n"; close($readport); *STDERR = IO::Socket::INET->new( Proto => "tcp", PeerAddr => "localhost:$portback", Timeout => 30, ) or die "cannot create socketremote: $!\n"; } close($socklisten); # warn "this is a test"; sleep(3); print "program exiting\n"; die "I died!!!\n"; sub showerrs { my $port1 = shift; my $socklisten = IO::Socket::INET->new(LocalPort => 0, Listen => 2, Reuse => 1, Proto => 'tcp') or die "Cannot open socket: $!\n"; my ($port, $myaddr) = sockaddr_in(getsockname($socklisten)); my $out = IO::Socket::INET->new( Proto => "tcp", PeerAddr => "localhost:$port1", Timeout => 30, ) or die "cannot create socketremote: $!\n"; print $out "$port\n"; close($out); if (my $readport = $socklisten->accept) { print while <$readport>; } print "Program terminated\n"; # Unless your DOS box is already configured to wait: print "Press Enter to exit ..."; $_ = <>; exit(0); }
Re: Open a second DOS window
by benn (Vicar) on Oct 08, 2003 at 18:36 UTC
    I don't think this is possible. You could maybe try redirecting STDERR to a file, and typeing it from another console window though, using something like...
    perl 2>stderr.txt
    ...though this only works on later Windows versions - 2000 upwards, I believe. For earlier versions, you could try one of the various DOS redirect utilities available.

    HTH, Ben.

Re: Open a second DOS window
by castaway (Parson) on Oct 08, 2003 at 18:41 UTC
    I've not tried it at all, but seeing as the docs for AllocConsole (Win API) also claim to only be able to create one Console per process, I'm guessing you'll have to start a second process somehow. Using fork maybe? And then there's the fun of communicating between the two..

    Personally I prefer log files for that.. less hassle :)


      Hi, why dont you use perl:TK - follow the link The question there was how to create a tail fkt with Tk. Solution is very straight forward. If you like the 2nd dos box because of the copy/past capability some widgets like Text will do the same job. Dont start to hassle with socket programming - if you do that properly you will end with a log-server .... Cheers Hartwig PS. Can you explain in more detail why there is a need for a 2nd dos-box?
Re: Open a second DOS window
by vek (Prior) on Oct 09, 2003 at 15:03 UTC

    I agree with some of the other suggestions that logging to a file is probably a better way to go. Redirecting STDERR would be a good start, then as you progress further and want to log all kinds of things (as I'm sure you will in time) try Log::Log4perl. I've started using it instead of our home grown logging system and I like it a lot. Of course it might be total overkill for what you're attempting here though :-)

    -- vek --
Re: Open a second DOS window (a working possibility)
by bart (Canon) on Oct 09, 2003 at 22:35 UTC
    Playing around with all the options I have, I tried launching a second copy of perl, using the open HANDLE, "| program" syntax. Just piping to perl makes its own output appear in the same console as that of the parent program, but by adding "start" to the chain, it works as I'd like! It opens a second console window, that prints the messages it gets (after tweaking them a little , just to show it does something), and that stays open as long as the first program runs. It has successfully been tested on Win98.

    One problem I see is with the console window title bars. The second console gets a nice title "perl", but the original program gets a pretty ugly title, consisting of the whole command line bar the pipe symbol, of the program it just started. It actually appears on the wrong console window. Oh well.

    Now it's just a matter of building a tiny module that does whatever needs to be done. In the meantime, you can play with this:

    #!perl -wl open FOO, qq[| start "$^X" -lne ] . q["print qq['$_' OK]"]; my $stdout = select FOO; $| = 1; select $stdout; print FOO for qw(one two three); sleep 10; print "Finished";

    Update (24 hours later): Oh, damn. Though it works well on Win98, today I've had a chance to try and run it on XP, and it doesn't work there, at all. Perhaps it's a difference between the start executables on both platforms, or else, between the command line interpreters — command.exe vs. cmd.exe.

    I'll have to try and use BrowserUK's version, using Windows::Console and avoiding start completely. It works on Win98, and hopefully, it'll work on XP, too. And onb anything in between.

      Try this

      #! perl -plw use strict; use Win32::Console; BEGIN{ my $c=new Win32::Console( STD_ERROR_HANDLE ); $c->Free(); $c->Alloc(); } END{ print 'Paused'; 1 while sleep 1; }

      Name that as and then do

      perl -e"open F, '| perl' or die $!; print F 'Hello world', $ +_, $/ for 1 .. 100"

      You'll need to use ^Break to end the progam.

      Examine what is said, not who speaks.
      "Efficiency is intelligent laziness." -David Dunham
      "Think for yourself!" - Abigail

Re: Open a second DOS window
by jonadab (Parson) on Oct 09, 2003 at 19:37 UTC

    It is possible to accomplish what you want, but not straightforwardly. The problem is that DOS does not have any such concept as STDERR, at least not in anything like the Unix sense of that term.

    Traditionally, DOS software does not print error messages to the console unless they are fatal and the program is bailing back out to the prompt immediately, in which case there was (think DOS here, not a command box window on Windows, which is intended as a compatibility measure only) no point whatsoever in being able to redirect that output, since it would typically be one sentence long and the user would be getting a prompt. (Remember that DOS was not intended to be Unix, to run on university computers where people were developing software and doing research; it was intended to sell to businesses for things like spreadsheets.) For more verbose error messages in the DOS world, you either explain it onscreen in a fashion that is integrated with the rest of your app (think: text-based dialog box) or else you write it to a log file. For these hysterical raisins, DOS did not have a redirectable STDERR, which leads to your current problem. All C libraries for DOS and for Windows face this issue: do we want to support compiling Unix software that assumes it can just write willy nilly to STDERR, and if so how? The usual approach is to make STDERR synonymous with the console, which is IMO absolutely the wrong way to do it. (What the C libraries probably should have done, back in the eighties, is point it to C:\STDERR.LOG, but it's far too late for that now. What C libraries IMO should be fixed to do now is show these messages in a window available by clicking an icon in the system tray -- but nobody listens to me.) What just about all C libraries do, as I said, is map it to the non-redirectable console. (The console is not by its nature intended to be redirectable; it is not in any sense a stream. The BIOS calls that most C libraries use for writing to it can just as well be used to draw text-based pulldown menus and dialog boxes; they support absolute positioning and that sort of jazz, rather more like ncurses than STDERR on Unix.) As a result, the C library's standard error stream is largely useless on DOS -- and also on Win32 by extension. My advice is, don't use it, in Perl or any other language, if your code needs to support Windows.

    However, Windows 95 and later come with some facilities like multitasking that will allow you to fake it, particularly since in Perl it is possible to close off STDERR and open it pointing to something else (something _other_ than the C library's concept of STDERR), such as a pipe or log file. This is what you should do.

    $;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}} split//,".rekcah lreP rehtona tsuJ";$\=$ ;->();print$/

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://297621]
Approved by sgifford
Front-paged by davido
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (5)
As of 2020-07-05 12:26 GMT
Find Nodes?
    Voting Booth?

    No recent polls found