2

I have the following code to write to the Windows command console:

use Win32::Console;
my $console = new Win32::Console(Win32::Console::STD_ERROR_HANDLE());
my $defaultAttribute = $console->Attr();
my $defaultFG = ($defaultAttribute & 0x0F);
my $defaultBG = ($defaultAttribute & 0xF0);
$console->Attr($defaultBG | $Win32::Console::FG_LIGHTGREEN);
$console->Write("blah blah");
$console->Attr($defaultAttribute);

This code fails if the user redirects STDERR when invoking my script:

perl myscript.pl 2> foo

How can I obtain a handle to the Win32 console the process is attached to without reference to one of the standard handles so that it doesn't matter what redirections the user makes?

The effect I want is to be able to write a message on the console immediately following normal program output regardless of any redirection in a similar way to the bash builtin time command. Essentially, similar to opening and writing to /dev/tty in Unix.

I've tried my $console = new Win32::Console() to allocate a new console followed by $console->Display() but this does completely the wrong thing.

Adrian Pronk
  • 13,486
  • 7
  • 36
  • 60
  • There usually **is** a good reason to say 2>blubb. I hate it when programs demand attention when I told them to be silent. – Ingo Feb 12 '13 at 22:12
  • @Ingo: Fair point but I'm not going to modify the requirements for a program I write for myself to suit you. :-) – Adrian Pronk Feb 12 '13 at 22:18
  • You made my day! You mean, just in case you accidentaly type 2>NUL .... – Ingo Feb 12 '13 at 22:30
  • @Ingo: No. My command is like bash's `time` and I want to use it like: `cd this && mytime mvn ... >> ..\x 2>&1 && cd ..\that && mytime mvn ... >> ..\x 2>&1` with compile output in x and timings on screen. Plus it fills in what seemed to me to be a gap between what Win32::Console allows and what is possible with the Windows API. – Adrian Pronk Feb 12 '13 at 22:57

2 Answers2

3

After asking this question, I delved a bit deeper and was able to solve it by using a nasty hack:

use Win32API::File qw(createFile);
use Win32::Console;

my $handle = createFile('CONOUT$', 'rwke') or die "conout\$: $^E\n";
# my $console = new Win32::Console($handle) or die "new console: $^E\n";
my $console = bless {handle => $handle}, 'Win32::Console';

I looked at the code for the new() function inside Win32::Console and saw that it just creates a hash containing the handle to a console. If the parameter specifies stdin/stdout/stderr, it just retrieves the associated handle otherwise it creates a new console screen buffer and uses the handle for that.

So I just manually created the Win32::Console object containing a handle to the console returned by CreateFile.

So now perl myscript.pl > nul 2> nul < nul will write blah blah on the screen immediately below the command line.

I'll accept a better answer if someone comes up with one.

Adrian Pronk
  • 13,486
  • 7
  • 36
  • 60
0

According to the AllocConsole() docs (C++ docs, but the concepts are the same):

"A process can be associated with only one console, so the AllocConsole function fails if the calling process already has a console. A process can use the FreeConsole function to detach itself from its current console, then it can call AllocConsole to create a new console or AttachConsole to attach to another console."

Since your console is already redirected it doesn't look like there's anything you can do about it; even if you detach the console and allocate a new one, the new console inherits the redirection. In C++ you would use the SetStdHandle() API to force the standard handles to point to a different file or device, but I can't find any Perl equivalent of that.

HerrJoebob
  • 2,264
  • 16
  • 25
  • Redirecting the standard handles does not free the console. `CreateFile('conout$')` will retrieve the handle to the allocated console but there's no direct way of using this in Perl's Win32::Console module. – Adrian Pronk Feb 12 '13 at 22:05
  • Failing to see where I said that redirecting would free the console... In any case your comment about having no direct way to change it was my point. Also I would expect CreateFile on conout$ to also get you a handle to the redirected output. – HerrJoebob Feb 12 '13 at 22:10