Создание дочернего процесса с переназначенным вводом и выводом
Пример в этом разделе демонстрирует, как создать дочерний процесс из консольного процесса. Он также демонстрирует методику использования неименованных программных каналов, чтобы переназначить стандартные дескрипторы ввода и вывода дочернего процесса.
Функция
CreatePipe использует структуру SECURITY_ATTRIBUTES, чтобы создать наследуемые дескрипторы для чтения и записи в концах двух каналов. Конец чтения в одном из каналов служит как стандартный ввод данных для дочернего процесса, и конец записи в другом канале является стандартным выводом для дочернего процесса. Эти дескрипторы каналов устанавливаются в функции SetStdHandle, которая делает их стандартными дескрипторами, унаследованными дочерним процессом. После того, как дочерний процесс создан, SetStdHandle используется снова, чтобы восстановить стандартные исходные дескрипторы для родительского процесса.Родительский процесс использует другие концы каналов, чтобы записать введенные данные и прочитать вывод данных дочернего процесса. Дескрипторы этих концов канала также наследуемы. Однако дескриптор не должен быть унаследован. Перед созданием дочернего процесса, родительский процесс должен использовать
DuplicateHandle, чтобы создать дубликат определяемой программой глобальной переменной hChildStdinWr, которая не может быть унаследована. Тогда он использует CloseHandle, чтобы закрыть наследуемый дескриптор. Для получения дополнительной информации, см. главу Каналы.Нижеследующее - родительский процесс.
#include <stdio.h> #include <windows.h> #define BUFSIZE 4096 HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup, hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup, hInputFile, hSaveStdin, hSaveStdout; BOOL CreateChildProcess(VOID); VOID WriteToPipe(VOID); VOID ReadFromPipe(VOID); VOID ErrorExit(LPTSTR); VOID ErrMsg(LPTSTR, BOOL); DWORD main(int argc, char *argv[]) {
// Установим флажок bInheritHandle, так как дескрипторы канала наследуются.
// Шаги для переназначения STDOUT дочернего процесса // 1.Сохраним текущий STDOUT, который позже восстановим. // 2. Создадим анонимный канал, который будет STDOUT дочернего процесса. // 3. Установим STDOUT родительского процесса, который будет, // дескриптором записи канала наследуемым дочерним процессом. // 4. Создадим ненаследуемый дубликат дескриптора чтения и закроем // наследуемый дескриптор чтения. // Сохраним дескриптор текущего STDOUT.
// Создадим канал для STDOUT дочернего процесса.
// Установим дескриптор записи канала, который будет STDOUT.
// Создадим ненаследуемый дескриптор чтения и закроем наследуемый дескриптор чтения.
// Шаги для переназначения STDIN дочернего процесса: // 1.Сохраним текущий STDIN, который позже восстановим. // 2. Создадим анонимный канал, который будет STDIN дочернего процесса. // 3. Установим STDIN родительского процесса, который будет дескриптором // чтения канала, так чтобы он наследовался дочерним процессом. // 4. Создадим ненаследуемый дубликат дескриптора записи закроем // наследуемый дескриптор записи. // Сохраним дескриптор текущего STDIN.
// Создадим канал для STDIN дочернего процесса.
// Установим дескриптор чтения для канала, который будет STDIN.
// Продублируем дескриптор записи для канала, так что он не был унаследован.
// Теперь создадим дочерний процесс.
// После создания процесса, восстановим сохраненные STDIN и STDOUT.
// Получим дескриптор для входного файла родителя.
// Запишем в канал, который является стандартным вводом данных для дочернего // процесса.
// Прочитаем из канала, который является стандартным выводом для дочернего // процесса.
} BOOL CreateChildProcess() {
// Установим член структуры PROCESS_INFORMATION. ( &piProcInfo, sizeof(PROCESS_INFORMATION) );ZeroMemory // Установим член структуры STARTUPINFO.
// Создадим дочерний процесс.
} VOID WriteToPipe(VOID) {
// Чтение из файла и запись его контекста в канал.
// Закрываем дескриптор канала, так чтобы дочерний процесс остановил чтение.
DWORD dwRead, dwWritten; CHAR chBuf[BUFSIZE]; HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); // Закрываем конец записи канала перед чтением из конца чтения канала. if (!CloseHandle(hChildStdoutWr)) ErrorExit("Closing handle failed"); // Читаем выводимую информацию дочерним процессом, и записываем в STDOUT // родителя.
} VOID ErrorExit (LPTSTR lpszMessage) { fprintf(stderr, "%s\n", lpszMessage); ExitProcess(0); } // Код для дочернего процесса. #include <windows.h> #define BUFSIZE 4096 VOID main(VOID) {
// Читаем из стандартного ввода данных.
// Записываем в стандартный вывод данных
} |