Страница 1 из 2

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

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

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

Добавлено: 19 окт 2004, 20:49
saa
Возможно, я недостаточно понятно описал проблему. Запускается плагин из FAR, который инициирует процесс на удаленной машине и читает ее stdout. Но процесс может затянуться, поэтому хотелось бы иметь возможность прервать его. ReadConsoleInput нужен, чтобы определить, был ли нажат ESC. Если вместо открытия потока читать, например, большой файл, возможность диагностировать ESC есть. При использовании _popen() - нет.

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

Короче, приведите фрагмент кода - посмотрим.

Добавлено: 20 окт 2004, 16:57
saa

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

// -------------------------------------------------------------------------
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, то все работает.

Добавлено: 21 окт 2004, 01:20
Eugie
Понятно. Команда rsh перенаправляет STDIN на удаленный хост, поэтому после ее запуска через _popen() бессмысленно читать локальный STDIN (через hStdin). А с fopen(), естественно, работает: она ведь не подменяет стандартный вход, и Вы просто читаете что есть с локальной консоли. Попробуйте такой финт ушами: задайте вместо удаленного localhost - если я прав, в этом случае должно работать.

Добавлено: 21 окт 2004, 09:55
saa
Попробовал с localhost - эффект тот же. Но даже если предположить, что такой вариант работоспособен - он мне, к сожалению, не подходит.
Но вот ведь что интересно - все, что вводится с клавиатуры в процессе чтения потока, отображается на консоли, а перехватить не получается.

Добавлено: 21 окт 2004, 17:27
Eugie
Тады не знаю... А rsh -то работает реально? Читаете что-нибудь с remotehost?

Добавлено: 22 окт 2004, 09:25
saa
да, с удаленного хоста читаю все без проблем. да ладно, и так получилось нормально. можно и без ESC обойтись :)

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

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