我有以下代码要写入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()
,但这完全是错误的。
答案 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等价物。