Я хочу создать консольное приложение Windows, которое запустит дочерний процесс с командной строкой cmd
с командной строкой и отобразит результат, созданный дочерним процессом.
Вывод дочернего процесса должен быть прочитан родительским процессом, поэтому мне нужно подключить stdout
дочернего процесса к stdin
родительского процесса. Затем родительский процесс будет читать из своего stdin
вывод из дочернего процесса, который ребенок записывает на его stdout
. Родительский процесс отобразит дочерний вывод в родительский stdout
.
В дочернем процессе будет выполняться команда dir
Windows с командной оболочкой cmd
.
Моя текущая версия не отображает вывод команды dir
. Родительский процесс не отображает никакого вывода, кроме выхода из system("pause");
,
Мой основной процесс:
int main(int argc,char* argv[])
{
HANDLE hStdInRead;
HANDLE hStdInWrite;
HANDLE hStdOutRead;
HANDLE hStdOutWrite;
HANDLE hStdErrWrite;
if(!CreatePipe(&hStdInRead,&hStdInWrite,NULL,0))
return 0;
if(!CreatePipe(&hStdOutRead,&hStdOutWrite,NULL,0))
return 0;
if (!DuplicateHandle(GetCurrentProcess(), hStdOutWrite, GetCurrentProcess(), &hStdErrWrite, 0, TRUE, DUPLICATE_SAME_ACCESS))
{
return 0;
}
STARTUPINFO si;
ZeroMemory(&si,sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.wShowWindow = SW_SHOW;
si.dwFlags =STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
si.hStdOutput = hStdOutWrite;
si.hStdError = hStdErrWrite;
si.hStdInput = hStdInRead;
PROCESS_INFORMATION pi;
ZeroMemory(&pi,sizeof(PROCESS_INFORMATION));
LPSTR cmd = new char[256*sizeof(char)];
strcpy_s(cmd,256,"C:\\Windows\\cmd.exe /c dir");
if(CreateProcess(NULL,cmd,NULL,NULL,true,0,NULL,NULL,&si,&pi))
{
std::cout<<"OK"<<std::endl;
CloseHandle(hStdOutWrite);
CloseHandle(hStdInRead);
char ReadBuff[4096];
DWORD ReadNum ;
ZeroMemory(&ReadBuff,4096);
while(ReadFile(hStdOutRead,ReadBuff,4096,&ReadNum,NULL))
{
std::cout<<ReadBuff<<std::endl;
}
WaitForSingleObject(pi.hProcess,INFINITE);
}
system("pause");
return 0;
}
В коде есть несколько ошибок, здесь работает очищенный пример.
Сделанные изменения: объединить набор труб в один массив и создать перечисления для обозначения того, что имеет какую-то цель, делает его намного яснее, чем называть что-то "StdOutRead" и "StdOutWrite".
Создала структуру SECURITY_ATTRIBUTES, чтобы мы могли настроить каналы для наследования и добавили код, чтобы предотвратить половину родительских сторон наследуемых труб.
Удалил флаг STARTF_USESTDHANDLES из процесса.
Указал каталог для процесса для выполнения DIR.
Убедитесь, что мы закрываем все ручки, которые мы не используем, как только процесс запускается в родительском.
Наконец, я заставил его слить файл io в куски и добавить нулевой ограничитель в конец успешного буфера, чтобы он мог корректно выводить.
#define WINDOWS_LEAN_AND_MEAN
#include <Windows.h>
#include <tchar.h>
#include <iostream>
#include <thread>
#include <cassert>
enum { ParentRead, ParentWrite, ChildWrite, ChildRead, NumPipeTypes };
int main(int /*argc*/, char* /*argv*/[])
{
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = nullptr;
HANDLE pipes[NumPipeTypes];
if (!CreatePipe(&pipes[ParentWrite], &pipes[ChildRead], &sa, 0))
return 0;
if (!CreatePipe(&pipes[ParentRead], &pipes[ChildWrite], &sa, 0))
return 0;
// make sure the handles the parent will use aren't inherited.
SetHandleInformation(pipes[ParentRead], HANDLE_FLAG_INHERIT, 0);
SetHandleInformation(pipes[ParentWrite], HANDLE_FLAG_INHERIT, 0);
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.wShowWindow = SW_SHOW;
si.dwFlags = STARTF_USESHOWWINDOW;
si.hStdOutput = pipes[ChildWrite];
si.hStdError = pipes[ChildWrite];
si.hStdInput = pipes[ChildRead];
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
TCHAR cmd[] = _T("C:\\Windows\\System32\\cmd.exe /c dir c:\\");
if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
return 0;
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(pipes[ChildRead]);
CloseHandle(pipes[ChildWrite]);
CloseHandle(pipes[ParentWrite]);
char ReadBuff[4096 + 1];
DWORD ReadNum;
for (;;) {
auto success = ReadFile(pipes[ParentRead], ReadBuff, sizeof(ReadBuff) - 1, &ReadNum, NULL);
if (!success || !ReadNum)
break;
ReadBuff[ReadNum] = 0;
std::cout << ReadBuff;
}
//system("pause"); use Ctrl+F5 or Debug >> Start Without debugging instead.
return 0;
}