我想创建一个Windows控制台应用程序,它将使用命令行启动运行cmd
命令shell的子进程,并显示子进程创建的输出。
子进程的输出将由父进程读取,因此我需要将子进程的stdout
连接到父进程的stdin
。然后,父进程将从其stdin
读取子进程的输出,该进程正在将子进程写入其stdout
。父进程将子输出显示给父进程stdout
。
子进程将使用dir
命令shell运行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;
}
答案 0 :(得分:3)
您的代码有几个问题,这是一个有效的清理示例。
所做的更改:将管道集合成一个数组并创建枚举以表示具有什么目的,使其比调用“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;
}