Тема:, Програми та розповсюдженний програм, C / C + +, статті

Про те, як створити дочірній процес і передати управління його потоком
вводу-виводу батьківського процесу за рахунок переадресації StdIn / StdOut.

Вступ:


У цій статті пояснюється, як запустити дочірнє консольний додаток
і переадресувати його стандартне введення / виведення з використанням неіменовані
пайпов.

Неіменовані пайпи використовуються для передачі даних тільки в одному
напрямку (тільки читання або тільки запис). Навіщо це може знадобитися? Для
того, щоб запустити яку-небудь зовнішню утиліту і управляти її поведінкою з
своєї програми. Наприклад, це може бути Телнет-сервер, який запускає DOS
Shell і все, що виводиться в Шеллі, передає через сокети на віддалений хост.

Для початку ми поговоримо про самих пайпах. Пайп в Windows – це просто один з
методів комунікації між процесами. У SDK дається таке визначення для
пайпов: “пайп – це комунікаційний шлюз з двома кінцями; певний процес через
дескриптор (handle) на одному кінці пайпа може передавати дані іншому
процесу, що знаходиться на іншому кінці пайпа. ”

В даному випадку ми використовуємо неіменовані пайпи (“anonymous” pipes), тобто
односпрямовані пайпи, які “передають дані між батьківським і дочірнім
процесами або між двома дочірніми процесами одного і того ж батьківського
процесу. ”

Образно кажучи, пайп – це “труба”, за якою між двома процесами
перетікають дані.

Для створення пайпа ми будемо використовувати функцію CreatePipe, яка поверне
нам два дескриптора: дескриптор для запису і дескриптор для читання.

Зверніть увагу, що нам доведеться створити два пайпа: один для stdin і
другий для stdout.

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

Крім того, ми будемо перевіряти, введено чи що-небудь у нашому додатку, та
все, що введено, будемо посилати в “записуваний кінець” пайпа stdin.

Исходник:

 //———— Приклад використання CreateProcess і Anonymous Pipes ——

// childspawn.cpp
/ / Додаток запускає shell і перехоплює його введення / виведення

//———————use freely—————————————

#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <string.h>
#pragma hdrstop
#include <condefs.h>

# Define bzero (a) memset (a, 0, sizeof (a)) / / для скорочення писанини

bool IsWinNT () / / перевірка запуску під NT
{
OSVERSIONINFO osv;
osv.dwOSVersionInfoSize = sizeof(osv);
GetVersionEx(&osv);
return (osv.dwPlatformId == VER_PLATFORM_WIN32_NT);
}

void ErrorMessage (char * str) / / виведення докладної інформації про помилку
{

LPVOID msg;

FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
GetLastError(),
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), / / ​​мова за замовчуванням
(LPTSTR) &msg,
0,
NULL
);

printf("%s: %s
",str,msg);
LocalFree(msg);

}

//———————————————————————-

void main()

{

char buf [1024]; / ​​/ буфер введення / виводу

STARTUPINFO si;
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd; / / структура security для пайпов
PROCESS_INFORMATION pi;

HANDLE newstdin, newstdout, read_stdout, write_stdin; / / дескриптори
/ / Пайпов

if (IsWinNT ()) / / ініціалізація security для Windows NT
{
InitializeSecurityDescriptor(&sd,SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, true, NULL, false);
sa.lpSecurityDescriptor = &sd;
}

else sa.lpSecurityDescriptor = NULL;

sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = true; / / дозволяємо спадкування дескрипторів

if (! CreatePipe (& newstdin, & write_stdin, & sa, 0)) / / створюємо пайп
/ / Для stdin
{
ErrorMessage("CreatePipe");
getch();
return;
}

if (! CreatePipe (& read_stdout, & newstdout, & sa, 0)) / / створюємо пайп
/ / Для stdout
{
ErrorMessage("CreatePipe");
getch();
CloseHandle(newstdin);
CloseHandle(write_stdin);
return;
}

GetStartupInfo (& si); / / створюємо startupinfo для
/ / Дочірнього процесу

/*

Параметр dwFlags повідомляє функції CreateProcess
як саме треба створити процес.

STARTF_USESTDHANDLES управляє полями hStd *.
STARTF_USESHOWWINDOW управляє полем wShowWindow.

*/

si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
si.hStdOutput = newstdout;
si.hStdError = newstdout; / / підміняємо дескриптори для
si.hStdInput = newstdin; / / дочірнього процесу

char app_spawn [] = “d: winntsystem32cmd.exe”; / / це просто
/ / Приклад,
/ / Замініть на те,
/ / Що вам потрібно

/ / Створюємо дочірній процес

if (!CreateProcess(app_spawn,NULL,NULL,NULL,TRUE,CREATE_NEW_CONSOLE,
NULL,NULL,&si,&pi))
{
ErrorMessage("CreateProcess");
getch();
CloseHandle(newstdin);
CloseHandle(newstdout);
CloseHandle(read_stdout);
CloseHandle(write_stdin);
return;
}

unsigned long exit = 0; / / код завершення процесу
unsigned long bread; / / к-ть прочитаних байт
unsigned long avail; / / к-сть доступних байт

bzero(buf);

for (;;) / / основний цикл програми
{
GetExitCodeProcess (pi.hProcess, & exit); / / поки дочірній процес
/ / Не закрито
if (exit != STILL_ACTIVE)
break;

PeekNamedPipe(read_stdout,buf,1023,&bread,&avail,NULL);

/ / Перевіряємо, чи є дані для читання в stdout

if (bread != 0)
{
bzero(buf);
if (avail > 1023)
{
while (bread >= 1023)
{
ReadFile (read_stdout, buf, 1023, & bread, NULL); / / читаємо з
/ / Пайпа stdout
printf("%s",buf);
bzero(buf);
}
}

else {
ReadFile(read_stdout,buf,1023,&bread,NULL);
printf("%s",buf);
}
}

if (kbhit ()) / / перевіряємо, введено чи що-небудь з клавіатури
{
bzero(buf);
*buf = (char)getche();

//printf("%c",*buf);

WriteFile (write_stdin, buf, 1, & bread, NULL); / / відправляємо це
/ / В stdin

if (*buf == ”
“) {
*buf = ”
“;
printf("%c",*buf);
WriteFile (write_stdin, buf, 1, & bread, NULL); / / формірум кінець
/ / Рядки, якщо потрібно

}
}
}

CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
CloseHandle (newstdin); / / невелика прибирання за собою
CloseHandle(newstdout);
CloseHandle(read_stdout);
CloseHandle(write_stdin);
}

//—————————-EOF———————————–

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*