在Activestate Perl中重定向stdin / stderr / stdout时写入控制台

时间:2013-02-12 21:26:11

标签: perl winapi console windows-console activestate

我有以下代码要写入Windows命令控制台:

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);

如果用户在调用我的脚本时重定向STDERR,则此代码将失败:

perl myscript.pl 2> foo

如何在不参考其中一个标准句柄的情况下获取连接该进程的Win32控制台的句柄,以便用户所做的重定向无关紧要?

我想要的效果是能够在正常程序输出之后立即在控制台上编写消息,而不管是否以与bash内置time命令类似的方式进行任何重定向。基本上,类似于在Unix中打开和写入/dev/tty

我已经尝试my $console = new Win32::Console()分配一个新的控制台,然后是$console->Display(),但这完全是错误的。

2 个答案:

答案 0 :(得分:3)

在提出这个问题之后,我深入研究了一下,并且能够通过使用令人讨厌的黑客来解决它:

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';

我查看了new()Win32::Console函数的代码,发现它只是创建了一个包含控制台句柄的哈希。如果参数指定stdin / stdout / stderr,它只是检索关联的句柄,否则它会创建一个新的控制台屏幕缓冲区并使用该句柄。

所以我只是手动创建了包含CreateFile返回的控制台句柄的Win32::Console对象。

所以现在perl myscript.pl > nul 2> nul < nul会在命令行正下方的屏幕上写blah blah

如果有人想出一个,我会接受更好的答案。

答案 1 :(得分:0)

根据AllocConsole()文档(C ++文档,但概念相同):

“进程只能与一个控制台关联,因此如果调用进程已经有一个控制台,则AllocConsole函数会失败。进程可以使用FreeConsole函数将自己从当前控制台分离,然后它可以调用AllocConsole来创建一个新的控制台或AttachConsole连接到另一个控制台。“

由于您的控制台已经重定向,因此看起来您无法做任何事情。即使您分离控制台并分配新控制台,新控制台也会继承重定向。在C ++中,您可以使用SetStdHandle() API强制标准句柄指向不同的文件或设备,但我找不到任何Perl等价物。