场景:
1. 有一些外部工具命令需要通过程序调用,比如启动服务器或者使用网络命令获取输出。
2. 使用了匿名管道CreatePipe获取子进程输出.
参考:
1. MSDN的主题《Creating a Child Process with Redirected Input and Output》。
2. 《Windows核心编程》进程章节.
代码:
#include "test_shellrun.h"
#include <stdlib.h>
#include <stdint.h>
#include <iostream>
#include <Windows.h>
using namespace std;
bool ExecuteCommandNoWait(const wchar_t* command)
{
STARTUPINFOW startupInfo = {sizeof(STARTUPINFOW)};
GetStartupInfoW(&startupInfo);
startupInfo.dwFlags=0;
startupInfo.wShowWindow=SW_HIDE;
bool ret = true;
PROCESS_INFORMATION info;
wchar_t* wlpcmd = wcsdup(command);
if (CreateProcessW(NULL , wlpcmd , NULL , NULL , TRUE , CREATE_NO_WINDOW, NULL
, NULL , &startupInfo, &info))
{
CloseHandle(info.hProcess);
CloseHandle(info.hThread);
}else
{
ret = false;
}
free(wlpcmd);
return ret;
}
std::string ExecuteCommandAndWait(const wchar_t* command,uint32_t wait_millisecond)
{
SECURITY_ATTRIBUTES sa;
HANDLE hChildStdoutRd,hChildStdoutWr;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
std::string buf;
if (!CreatePipe(&hChildStdoutRd,&hChildStdoutWr,&sa,0))
{
return buf;
}
if (!SetHandleInformation(hChildStdoutRd, HANDLE_FLAG_INHERIT, 0))
{
CloseHandle(hChildStdoutWr);
CloseHandle(hChildStdoutRd);
return buf;
}
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &pi, sizeof(PROCESS_INFORMATION) );
ZeroMemory( &si, sizeof(STARTUPINFO) );
si.cb = sizeof(STARTUPINFO);
si.hStdError = hChildStdoutWr;
si.hStdOutput = hChildStdoutWr;
si.dwFlags |= STARTF_USESTDHANDLES;
wchar_t* wlpcmd = wcsdup(command);
//CREATE_UNICODE_ENVIRONMENT
if (!CreateProcessW(NULL, wlpcmd,NULL,NULL,TRUE,0 ,NULL,NULL,&si,&pi))
{
CloseHandle(hChildStdoutWr);
CloseHandle(hChildStdoutRd);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
free(wlpcmd);
return buf;
}
WaitForSingleObject(pi.hProcess,wait_millisecond);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(hChildStdoutWr);
char buffer[1024] = {0};
DWORD bytesRead;
BOOL ret = false;
while (true)
{
ret = ReadFile(hChildStdoutRd,buffer,1024,&bytesRead,NULL);
if (!ret || bytesRead == 0)
{
break;
}
buf.append(buffer,bytesRead);
}
CloseHandle(hChildStdoutRd);
free(wlpcmd);
return buf;
}
调用:
ExecuteCommandNoWait(L"notepad.exe");
std::string output = ExecuteCommandAndWait(L"ping www.baidu.com",-1);
cout << "output: " << output << endl;
注意:ReadFile在读取孙子进程的输出时,就是子进程又创建了子进程,会卡住,这个问题暂时用一个线程定时器调用:
CancelIoEx
关闭ReadFile,目前没有更好的办法,有谁知道的留了言.