Bạn cũng có thể sử dụng CreateProcess thay vì ShellExecute/ShellExecuteEx. Hàm này bao gồm tùy chọn trình bao bọc cmd.exe, trả lại mã thoát và trả về giá trị xuất chuẩn. (Bao gồm có thể không hoàn hảo).
Lưu ý: Trong sử dụng của tôi, tôi biết rằng có phải có kết quả xuất sắc, nhưng hàm PeekedNamePipe không phải lúc nào cũng trả về số byte trong lần thử đầu tiên, do đó vòng lặp đó. Có lẽ, ai đó có thể hình dung điều này và đăng một bản sửa đổi? Ngoài ra, có lẽ một phiên bản thay thế nên được sản xuất mà trả về stderr riêng biệt?
#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;
}
cảm ơn. Tôi sẽ nhìn sâu hơn ở đó. nó hoạt động :) – buddy123
Bạn có phải CloseHandle (info.hProcess); sau đó? (Điều này được chỉ ra ở đây: http://www.codingnotebook.com/2012/02/wait-on-process-launched-by.html) – Robin
@Robin Đó là chính xác, cảm ơn - Tôi đã sửa đổi câu trả lời của tôi cho phù hợp để làm cho nó rõ ràng. –