场景:
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,目前没有更好的办法,有谁知道的留了言.