2

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 コンソールへのハンドルを取得するにはどうすればよいですか?

time私が望む効果は、bash 組み込みコマンドと同様の方法で、リダイレクトに関係なく、通常のプログラム出力の直後にコンソールにメッセージを書き込めるようにすることです。/dev/tty基本的に、Unix で開いて書き込むのと同じです。

my $console = new Win32::Console()新しいコンソールを割り当てようとしました$console->Display()が、これは完全に間違っています。

4

2 に答える 2

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 を指定する場合、関連付けられたハンドルを取得するだけです。それ以外の場合は、新しいコンソール画面バッファを作成し、そのハンドルを使用します。

Win32::Consoleそのため、CreateFile によって返されるコンソールへのハンドルを含むオブジェクトを手動で作成しました。

それでは、コマンドラインのすぐ下の画面にperl myscript.pl > nul 2> nul < nul書き込みます。blah blah

誰かが思いついた場合は、より良い答えを受け入れます。

于 2013-02-12T22:16:07.023 に答える
0

AllocConsole()ドキュメントによると(C++ ドキュメントですが、概念は同じです):

「プロセスは 1 つのコンソールにのみ関連付けることができるため、呼び出しプロセスに既にコンソールがある場合、AllocConsole 関数は失敗します。プロセスは FreeConsole 関数を使用して現在のコンソールから切り離し、AllocConsole を呼び出して新しいコンソールを作成できます。または AttachConsole を別のコンソールに接続します。」

コンソールは既にリダイレクトされているため、それに対してできることは何もないようです。コンソールを切り離して新しいコンソールを割り当てても、新しいコンソールはリダイレクトを継承します。C++ では、SetStdHandle() API を使用して、標準ハンドルが別のファイルまたはデバイスを指すように強制しますが、それに相当する Perl は見つかりません。

于 2013-02-12T21:55:30.063 に答える