The Russian Electronic Developer Magazine | |
Русский электронный журнал разработчика | |
Идея проста: стандартные потоки ввода/вывода stdin, stdout, stderr перенаправляются на pipes, т.е. чтобы записать данные на stdin или stdout, достаточно записать или считать данные соответствующего pipe. Далее запускается внешняя программа. Теперь мы можем записать в один pipe информацию, которая попадает на stdin порожденной программе. Из другого pipe считываем информацию, которую порожденная программа выдает на stdout и stderr.
Основной принцип понятен, остальное можно найти в комментариях в тексте программы.
// // Тестовый пример как можно вызвать внешнюю программу, // затем передать ей на stdin данные и получить stdout, stderr // этой программы. // // Компиляция с помощью Watcom C/C++: // wcl386 dupstd.cpp // #define INCL_DOSQUEUES #define INCL_DOSFILEMGR #define INCL_DOSNMPIPES #define INCL_DOSERRORS #include <os2.h> #include <stdlib.h> #include <stdio.h> #include <string.h> // Хандлы стандартных потоков ввода/вывода #define STD_IN 0 #define STD_OUT 1 #define STD_ERR 2 // Размер буфера для pipes #define PIPESIZE 4096 // Хандлы для pipes HPIPE PipeReadHandle1, PipeWriteHandle1, PipeReadHandle2, PipeWriteHandle2; // В этих переменных мы сохраним хандлы (сдублированные) стандартных потоков. // !!! Инициализация в -1 необходима (см. описание функции DosDupHandle), // чтобы хандлы стандартных потоков отобразить на новые хандлы, которые // потом понадобятся для восстановления стандартных хандлов обратно. // Т.е. если эти хандлы не восстановить, Ваша программа останется // "глухой" и "слепой", например для стандартной фунцкии printf(). HFILE SavedInputHandle =-1, SavedOutputHandle =-1, SavedErrorsHandle =-1; // Буфер для ввода/вывода в pipes CHAR buf[PIPESIZE]; // // Собственно процедура, которая выполняет перенаправление // и запускает внешнюю программу из буфера progName. // void runService(const CHAR *progName) { // Хандлы стандартных потоков HFILE NewHandleStdIn = STD_IN, NewHandleStdOut = STD_OUT, NewHandleStdErr = STD_ERR; // Создаем копии стандартных потоков // Здесь главный момент в том, что стандартные потоки // получают новые нестандартные хандлы, (их, собственно, // можно использовать для вывода данных на stdout в // родительской программе, см. ниже) DosDupHandle(NewHandleStdIn, &SavedInputHandle); DosDupHandle(NewHandleStdOut, &SavedOutputHandle); DosDupHandle(NewHandleStdErr, &SavedErrorsHandle); // Создаем pipes для связи в внешней программой. // В данном примере можно использовать только один pipe, // но я использую два, не принципиально. DosCreatePipe(&PipeReadHandle1, &PipeWriteHandle1, PIPESIZE); DosCreatePipe(&PipeReadHandle2, &PipeWriteHandle2, PIPESIZE); // PipeReadHandle1 - будет дублироваться на stdin внешней // программы, т.е. записывая любые данные в PipeWriteHandle1, // мы передаем эти данные на stdin внешней программы DosDupHandle(PipeReadHandle1, &NewHandleStdIn); // PipeWriteHandle1 - будет дублироваться на stdout внешней // программы, т.е. все записанные на stdout данные, // можно прочитать через PipeReadHandle2 DosDupHandle(PipeWriteHandle2, &NewHandleStdOut); // stderr и stdout для прстоты выводятся на один хандл (впрочем // никто не мешает создать еще pipe и воспользоваться им) DosDupHandle(NewHandleStdOut, &NewHandleStdErr); // В буфер записываем команды, передаваемые на stdin cmd.exe // (либо Вашей внешней программы). Здесь это команда dir, // с последующей командой exit, для выхода из cmd.exe strcpy(buf,"dir\nexit\n"); // Записываем данные буфера на PipeWriteHandle1, // т.е. на stdin внешней программы! ULONG btWrited; DosWrite(PipeWriteHandle1,buf,strlen(buf),&btWrited); // Этот текст чисто в тестовых целях выводим на stdout // нашей программы (родительской) CHAR *test = "Это выводится на экран родительской программы\n\r"; DosWrite(SavedOutputHandle,test,strlen(test),&btWrited); // Перенаправление сделано, можно вывести данные на экран вызываемой // программы. printf("Эта строка выводится на экран в запускаемую программу, на stdout\n"); // Здесь я использую system для вызова внешней программы только // для простоты описания примера, Вы, возможно, будете использовать // другие функции (например DosExecPgm) system(progName); // ! Мы вызвали внешнюю программы, заранее записав в буфер ввода // ! команды dir и exit, т.е. внешняя программа (cmd.exe) выполнит // ! команду dir, выведет в pipe информацию, затем завершится, // ! выполнив команду exit. Выведенная в pipe информация готова // ! для считывания. Что мы сейчас и сделаем. // Читаем данные, выведенные на stdout командой dir ULONG btReaded; DosRead(PipeReadHandle2,buf,PIPESIZE-1,&btReaded); if(btReaded>0) buf[btReaded] = 0; // Сброс буферов ввода/вывода DosResetBuffer(STD_IN); DosResetBuffer(STD_OUT); DosResetBuffer(STD_ERR); // Теперь восстанавливаем стандартные stdin, stdout, stderr // которые мы сохранили в начале процедуры DosDupHandle(SavedInputHandle, &NewHandleStdIn); DosDupHandle(SavedOutputHandle, &NewHandleStdOut); DosDupHandle(SavedErrorsHandle, &NewHandleStdErr); // Закрываем пайпы, они больше не нужны DosClose(PipeReadHandle1); DosClose(PipeWriteHandle1); DosClose(PipeWriteHandle2); DosClose(PipeReadHandle2); // Выводим на stdout информацию, которую мы получили из // внешней программы. printf("Эти данные мы считали из pipe:\n%s\n",buf); } void main() { runService("cmd.exe"); }
Vladimir Kiselev KiSoft, 1999
Интересные ссылки:
Свежая информация право закон на сайте.
Комментариев к странице: 0 | Добавить комментарий
Редактор: Дмитрий Бан
Оформление: Евгений Кулешов