Запись в консоль при перенаправлении stdin/stderr/stdout в Activestate Perl

У меня есть следующий код для записи в командную консоль 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. По сути, аналогично открытию и записи в /dev/tty в Unix.

Я пробовал my $console = new Win32::Console() выделить новую консоль, за которой следует $console->Display(), но это совершенно неправильно.


person Adrian Pronk    schedule 12.02.2013    source источник
comment
Обычно есть веская причина сказать 2›blubb. Я ненавижу, когда программы требуют внимания, когда я говорю им молчать.   -  person Ingo    schedule 13.02.2013
comment
@Ingo: Справедливое замечание, но я не собираюсь изменять требования к программе, которую пишу для себя, чтобы она подходила вам. :-)   -  person Adrian Pronk    schedule 13.02.2013
comment
Вы сделали мой день! Вы имеете в виду, на всякий случай, если вы случайно наберете 2›NUL ....   -  person Ingo    schedule 13.02.2013
comment
@Ingo: Нет. Моя команда похожа на time в bash, и я хочу использовать ее как: cd this && mytime mvn ... >> ..\x 2>&1 && cd ..\that && mytime mvn ... >> ..\x 2>&1 с выводом компиляции в x и таймингами на экране. Кроме того, он заполняет то, что мне показалось пробелом между тем, что позволяет Win32::Console, и тем, что возможно с Windows API.   -  person Adrian Pronk    schedule 13.02.2013


Ответы (2)


Задав этот вопрос, я копнул немного глубже и смог решить его, используя неприятный хак:

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 на экране сразу под командной строкой.

Я приму лучший ответ, если кто-то придумает его.

person Adrian Pronk    schedule 12.02.2013

Согласно AllocConsole() docs (документы C++, но концепции те же):

«Процесс может быть связан только с одной консолью, поэтому функция AllocConsole дает сбой, если у вызывающего процесса уже есть консоль. Процесс может использовать функцию FreeConsole, чтобы отсоединиться от своей текущей консоли, а затем он может вызвать AllocConsole для создания новой консоли. или AttachConsole для подключения к другой консоли».

Поскольку ваша консоль уже перенаправлена, похоже, вы ничего не можете с этим поделать; даже если вы отсоедините консоль и выделите новую, новая консоль унаследует перенаправление. В C++ вы должны использовать SetStdHandle () API, чтобы стандартные дескрипторы указывали на другой файл или устройство, но я не могу найти эквивалента Perl для этого.

person HerrJoebob    schedule 12.02.2013
comment
Перенаправление стандартных дескрипторов не освобождает консоль. CreateFile('conout$') получит дескриптор выделенной консоли, но нет прямого способа использовать это в модуле Perl Win32::Console. - person Adrian Pronk; 13.02.2013
comment
Не увидев, где я сказал, что перенаправление освободит консоль ... В любом случае, ваш комментарий о том, что нет прямого способа изменить это, был моей точкой зрения. Также я ожидаю, что CreateFile на conout$ также даст вам дескриптор перенаправленного вывода. - person HerrJoebob; 13.02.2013