Вы также можете использовать CreateProcess вместо ShellExecute/ShellExecuteEx. Эта функция включает опцию оболочки cmd.exe, возвращает код выхода и возвращает stdout. (Включения могут быть не идеальными).
Примечания: В моем использовании я знал, что должны быть результаты stdout, но функция PeekedNamePipe не всегда возвращает количество байтов при первой попытке, следовательно, цикл там. Возможно, кто-то может понять это и опубликовать ревизию? Кроме того, может быть создана альтернативная версия, которая возвращает stderr отдельно?
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <Shellapi.h>
/*
Note:
The exitCode for a "Cmd Process" is not the exitCode
for a sub process launched from it! That can be retrieved
via the errorlevel variable in the command line like so:
set errorlevel=&[launch command]&echo.&echo exitCode=%errorlevel%&echo.
The stdOut vector will then contain the exitCode on a seperate line
*/
BOOL executeCommandLine(const CStringW &command,
DWORD &exitCode,
const BOOL asCmdProcess=FALSE,
std::vector<CStringW> *stdOutLines=NULL)
{
// Init return values
BOOL bSuccess = FALSE;
exitCode = 0;
if(stdOutLines) stdOutLines->clear();
// Optionally prepend cmd.exe to command line to execute
CStringW cmdLine((asCmdProcess ? L"cmd.exe /C " : L"") +
command);
// Create a pipe for the redirection of the STDOUT
// of a child process.
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
bSuccess = CreatePipe(&g_hChildStd_OUT_Rd,
&g_hChildStd_OUT_Wr, &saAttr, 0);
if(!bSuccess) return bSuccess;
bSuccess = SetHandleInformation(g_hChildStd_OUT_Rd,
HANDLE_FLAG_INHERIT, 0);
if(!bSuccess) return bSuccess;
// Setup the child process to use the STDOUT redirection
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = g_hChildStd_OUT_Wr;
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
// Execute a synchronous child process & get exit code
bSuccess = CreateProcess(NULL,
cmdLine.GetBuffer(), // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
if(!bSuccess) return bSuccess;
WaitForSingleObject(piProcInfo.hProcess, (DWORD)(-1L));
GetExitCodeProcess(piProcInfo.hProcess, &exitCode);
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
// Return if the caller is not requesting the stdout results
if(!stdOutLines) return TRUE;
// Read the data written to the pipe
DWORD bytesInPipe = 0;
while(bytesInPipe==0){
bSuccess = PeekNamedPipe(g_hChildStd_OUT_Rd, NULL, 0, NULL,
&bytesInPipe, NULL);
if(!bSuccess) return bSuccess;
}
if(bytesInPipe == 0) return TRUE;
DWORD dwRead;
CHAR *pipeContents = new CHAR[ bytesInPipe ];
bSuccess = ReadFile(g_hChildStd_OUT_Rd, pipeContents,
bytesInPipe, &dwRead, NULL);
if(!bSuccess || dwRead == 0) return FALSE;
// Split the data into lines and add them to the return vector
std::stringstream stream(pipeContents);
std::string str;
while(getline(stream, str))
stdOutLines->push_back(CStringW(str.c_str()));
return TRUE;
}
спасибо. Я буду смотреть глубже. он работает :) – buddy123
У вас есть CloseHandle (info.hProcess); после этого? (Это указано здесь: http://www.codingnotebook.com/2012/02/wait-on-process-launched-by.html) – Robin
@Robin Это правильно, спасибо - я внесла поправки в свой ответ, чтобы сделать это явный. –