| « Поставить закладку » « Сделать стартовой » | |||
|
|||
|
Статьи:: C/С++ :: C++ Builder :: Использование anonymous pipes для перехвата StdIn/StdOut дочернего процесса.
Использование anonymous pipes для перехвата StdIn/StdOut дочернего процесса.
Автор: Borland Developer Support Staff
Перевод: Валерий Вотинцев Тема:О том, как создать дочерний процесс и передать управление его потоком ввода-вывода родительскому процессу за счет переадресации 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: %sn",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:\winnt\system32\cmd.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 == 'r') {
*buf = 'n';
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-----------------------------------
Рубрика: C++ Builder
Вышел MySQL 5.1.30, первый стабильный рели....
После публикации 29 тестовых версий анонсирован первый стабильный релиз MySQL 5.1, пригодный для промышленной эксплуатации и обеспечивающий увеличение производительности для "тяжелых" SQL запросов, по сравнению с MySQL 5.0, примерно на 15-20%. Главные новшества появившиеся в MySQL 5.1:
Подробнее... |
Рубрика: MySQL
| Добавлено: 28.11.2008
Тестирование параллельных программ.
Тестирование параллельного программного обеспечения представляет собой более сложную задачу по сравнению с тестированием последовательной программы. Программист должен знать о подводных камнях при тестировании параллельного кода, имеющихся методологиях и инструментарии.
Подробнее... |
Рубрика: Тестирование
| Добавлено: 28.11.2008
Архитектура AMD64 (EM64T).
Аннотация. В статье кратко рассматривается архитектура AMD64 компании AMD и ее реализация EM64T компании Intel. Описаны особенности архитектуры, ее возможности, достоинства и недостатки.
Подробнее... |
Рубрика: Архитектура AMD
| Добавлено: 27.11.2008
Остальные статьи: |
Цитата дня (все,добавить):
|
Realcoding.NET
© 2003-2008 |
Контакты |
Реклама на сайте
|