Что происходит с stdin при вызове _popen?

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

saa
Сообщения: 6
Зарегистрирован: 19 окт 2004, 16:51
Откуда: Петербург

Добрый день.
Имеется консольное приложение (плагин для FAR).
Требуется в процессе чтения потока, созданного _popen, перехватывать нажатие ESC. Если вместо pipe читать, например, файл, то ReadConsoleInput отлично работает. Стоит только вызвать _popen, как события клавиатуры уходят мимо...
Eugie
Сообщения: 708
Зарегистрирован: 17 фев 2004, 23:59
Откуда: SPb

Вообще-то, функция станд.библиотеки (CRT) _popen создает канал и перенаправляет в него вывод команды, указанной в качестве параметра. Читать/писать из/в него надо с помощью CTR-функций типа fgetc, fgets/fputc, fputs. При чем здесь ReadConsoleInput?
saa
Сообщения: 6
Зарегистрирован: 19 окт 2004, 16:51
Откуда: Петербург

Возможно, я недостаточно понятно описал проблему. Запускается плагин из FAR, который инициирует процесс на удаленной машине и читает ее stdout. Но процесс может затянуться, поэтому хотелось бы иметь возможность прервать его. ReadConsoleInput нужен, чтобы определить, был ли нажат ESC. Если вместо открытия потока читать, например, большой файл, возможность диагностировать ESC есть. При использовании _popen() - нет.
Eugie
Сообщения: 708
Зарегистрирован: 17 фев 2004, 23:59
Откуда: SPb

Все равно непонятно :( Еще раз повторяю: _popen() асинхронно запускает копию командного процессора, выполняет в ней консольную программу локально и позволяет перенаправить ее ввод-вывод в возвращаемый поток (буферизованный файл). Поскольку возвращается FILE*, для доступа к нему надо использовать стандартные функции чтения-записи типа fgets()/fputs(). WinAPI-функция ReadConsoleInput() и иже с ней предоставляют альтернативный вар-т для того же самого, но обладают большей функциональностью. Но она требует, чтобы и поток был создан с помощью API-шной функции типа CreatePipe(), ведь первый параметр ReadConsoleInput() - хэндл буфера ввода.

Короче, приведите фрагмент кода - посмотрим.
saa
Сообщения: 6
Зарегистрирован: 19 окт 2004, 16:51
Откуда: Петербург

Код: Выделить всё

// -------------------------------------------------------------------------
static bool CheckForEsc( HANDLE hStdin )
{
  DWORD cNumRead;
  INPUT_RECORD irInBuf[128]; 
  int i = 0;

  GetNumberOfConsoleInputEvents( hStdin, &cNumRead );
  if( !cNumRead ) return false;

  if ( !ReadConsoleInput( 
          hStdin,      // input buffer handle 
          irInBuf,     // buffer to read into 
          1,           // size of read buffer 
          &cNumRead)) // number of records read 
  {
    return false;
  }

  if( cNumRead == 0 ) return false; 

  for( i = 0; i < cNumRead; i++ ) {
    if( irInBuf[i].EventType == KEY_EVENT && 
        irInBuf[i].Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE ) return true;
  }
  return false;
}
// -------------------------------------------------------------------------
static void Do( void )
{
  HANDLE hStdin = GetStdHandle( STD_INPUT_HANDLE );
  char buf[256];
  FILE *pf = _popen( "rsh server \"ls -l\"", "rt" );
  while( !feof( pf )) {
    // проверим, не нажал ли пользователь ESC
    if( CheckForEsc( hStdin )) return;
    if( fgets( buf, 255, pf ) != NULL ) {
      // что - то делаем
    }
  }
}
// -------------------------------------------------------------------------
Если вместо _popen использвать, например, fopen, то все работает.
Eugie
Сообщения: 708
Зарегистрирован: 17 фев 2004, 23:59
Откуда: SPb

Понятно. Команда rsh перенаправляет STDIN на удаленный хост, поэтому после ее запуска через _popen() бессмысленно читать локальный STDIN (через hStdin). А с fopen(), естественно, работает: она ведь не подменяет стандартный вход, и Вы просто читаете что есть с локальной консоли. Попробуйте такой финт ушами: задайте вместо удаленного localhost - если я прав, в этом случае должно работать.
saa
Сообщения: 6
Зарегистрирован: 19 окт 2004, 16:51
Откуда: Петербург

Попробовал с localhost - эффект тот же. Но даже если предположить, что такой вариант работоспособен - он мне, к сожалению, не подходит.
Но вот ведь что интересно - все, что вводится с клавиатуры в процессе чтения потока, отображается на консоли, а перехватить не получается.
Eugie
Сообщения: 708
Зарегистрирован: 17 фев 2004, 23:59
Откуда: SPb

Тады не знаю... А rsh -то работает реально? Читаете что-нибудь с remotehost?
saa
Сообщения: 6
Зарегистрирован: 19 окт 2004, 16:51
Откуда: Петербург

да, с удаленного хоста читаю все без проблем. да ладно, и так получилось нормально. можно и без ESC обойтись :)
Eugie
Сообщения: 708
Зарегистрирован: 17 фев 2004, 23:59
Откуда: SPb

Если все-таки захотите использовать ESC, можно еще поставить хук на консольное окно и ловить WM_KEYDOWN. Но это уже вариант на любителя :)

PS Если что, смогу ответить после 16.00
Ответить