Створення дочірнього процесу з перепризначеним введенням і виведенням

Створення дочірнього процесу з перепризначеним введенням і виведенням

Приклад в цьому розділі демонструє, як створити дочірній процес з консольного процесу. Він також демонструє методику використання різних неназваних програмних каналів, щоб перепризначити стандартні дескриптори введення і виведення дочірнього процесу.

Функція CreatePipe використовує структуру SECURITY_ATTRIBUTES. щоб створити успадковані дескриптори для читання і запису в кінцях двох каналів. Кінець читання в одному з каналів служить як стандартний ввід даних для дочірнього процесу, і кінець запису в іншому каналі є стандартним висновком для дочірнього процесу. Ці дескриптори каналів встановлюються в функції SetStdHandle. яка робить їх стандартними дескрипторами, успадкованими дочірнім процесом. Після того, як дочірній процес створений, SetStdHandle використовується знову, щоб відновити стандартні вихідні дескриптори для батьківського процесу.

Батьківський процес використовує інші кінці каналів, щоб записати введені дані і прочитати висновок даних дочірнього процесу. Дескриптори цих кінців каналу також успадковане. Однак дескриптор не повинен бути успадкований. Перед створенням дочірнього процесу, батьківський процес повинен використовувати DuplicateHandle. щоб створити дублікат обумовленою програмою глобальної змінної hChildStdinWr. яка не може бути успадкована. Тоді він використовує CloseHandle. щоб закрити успадковані дескриптор. Для отримання додаткової інформації, див. Розділ Канали.

Наведена - батьківський процес.

#defineBUFSIZE 4096

HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,

hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,

hInputFile, hSaveStdin, hSaveStdout;

BOOLCreateChildProcess (VOID);

VOIDReadFromPipe (VOID);

// Встановимо прапорець bInheritHandle, так як дескриптори каналу успадковуються.

saAttr.nLength = sizeof (SECURITY_ATTRIBUTES);

// Кроки для перепризначення STDOUT дочірнього процесу

// 1.Сохранім поточний STDOUT, який пізніше відновимо.

// 2. Створимо анонімний канал, який буде STDOUT дочірнього процесу.

// 3. Встановимо STDOUT батьківського процесу, який буде,

// дескриптором записи каналу спадкоємною дочірнім процесом.

// 4. Створимо неуспадковане дублікат дескриптора читання і закриємо

// успадковані дескриптор читання.

// Збережемо дескриптор поточного STDOUT.

hSaveStdout = GetStdHandle (STD_OUTPUT_HANDLE);

// Створимо канал для STDOUT дочірнього процесу.

if (! CreatePipe (hChildStdoutRd, hChildStdoutWr, saAttr, 0))

ErrorExit ( "Stdout pipe creation failed \ n");

// Встановимо дескриптор запису каналу, який буде STDOUT.

if (! SetStdHandle (STD_OUTPUT_HANDLE. hChildStdoutWr))

ErrorExit ( "Redirecting STDOUT failed");

// Створимо неуспадковане дескриптор читання і закриємо успадковані дескриптор читання.

fSuccess = DuplicateHandle (GetCurrentProcess (), hChildStdoutRd,

GetCurrentProcess (), hChildStdoutRdDup. 0,

ErrorExit ( "DuplicateHandle failed");

// Кроки для перепризначення STDIN дочірнього процесу:

// 1.Сохранім поточний STDIN, який пізніше відновимо.

// 2. Створимо анонімний канал, який буде STDIN дочірнього процесу.

// 3. Встановимо STDIN батьківського процесу, який буде дескриптором

// читання каналу, так щоб він дістався у спадок дочірнім процесом.

// 4. Створимо неуспадковане дублікат дескриптора записи закриємо

// успадковані дескриптор запису.

// Збережемо дескриптор поточного STDIN.

hSaveStdin = GetStdHandle (STD_INPUT_HANDLE);

// Створимо канал для STDIN дочірнього процесу.

if (! CreatePipe ( hChildStdinRd, hChildStdinWr, saAttr, 0))

ErrorExit ( "Stdin pipe creation failed \ n");

// Встановимо дескриптор читання для каналу, який буде STDIN.

if (! SetStdHandle (STD_INPUT_HANDLE. hChildStdinRd))

ErrorExit ( "Redirecting Stdin failed");

// Продублюємо дескриптор записи для каналу, так що він не був успадкований.

fSuccess = DuplicateHandle (GetCurrentProcess (), hChildStdinWr,

GetCurrentProcess (), hChildStdinWrDup, 0,

FALSE, // не успадковується

ErrorExit ( "DuplicateHandle failed");

// Тепер створимо дочірній процес.

ErrorExit ( "Create process failed");

// Після створення процесу, відновимо збережені STDIN і STDOUT.

if (! SetStdHandle (STD_INPUT_HANDLE. hSaveStdin))

ErrorExit ( "Re-redirecting Stdin failed \ n");

if (! SetStdHandle (STD_OUTPUT_HANDLE. hSaveStdout))

ErrorExit ( "Re-redirecting Stdout failed \ n");

// Отримаємо дескриптор для вхідного файлу батька.

hInputFile = CreateFile (argv [1], GENERIC_READ. 0, NULL,

OPEN_EXISTING. FILE_ATTRIBUTE_READONLY. NULL);

if (hInputFile == INVALID_HANDLE_VALUE)

ErrorExit ( "no input file \ n");

// Запишемо в канал, який є стандартним введенням даних для дочірнього

// Прочитаємо з каналу, який є стандартним висновком для дочірнього