when I use popen to get the output of a command, say dir, it will prompt out a console.
however, can I get the output of a command without the appearance of the console?
I am using Visual C++ and want to make an Library to return the outp开发者_如何转开发ut of some command, say, dir.
Assuming Windows (since this is the only platform where this behavior is endemic):
CreatePipe() to create the pipes necessary to communicate, and CreateProcess to create the child process.
HANDLE StdInHandles[2];
HANDLE StdOutHandles[2];
HANDLE StdErrHandles[2];
CreatePipe(&StdInHandles[0], &StdInHandles[1], NULL, 4096);
CreatePipe(&StdOutHandles[0], &StdOutHandles[1], NULL, 4096);
CreatePipe(&StdErrHandles[0], &StdErrHandles[1], NULL, 4096);
STARTUPINFO si; memset(&si, 0, sizeof(si)); /* zero out */
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = StdInHandles[0]; /* read handle */
si.hStdOutput = StdOutHandles[1]; /* write handle */
si.hStdError = StdErrHandles[1]; /* write handle */
/* fix other stuff in si */
PROCESS_INFORMATION pi;
/* fix stuff in pi */
CreateProcess(AppName, commandline, SECURITY_ATTRIBUTES, SECURITY_ATTRIBUTES, FALSE, CREATE_NO_WINDOW |DETACHED_PROCESS, lpEnvironment, lpCurrentDirectory, &si, &pi);
This should more than get you on your way to doing what you wish to accomplish.
Maybe something like this? This code will return the output but it has to wait for the process to finish.
#include <iostream>
#include <windows.h>
int runCmd(const char* cmd, std::string& outOutput) {
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
HANDLE g_hChildStd_ERR_Rd = NULL;
HANDLE g_hChildStd_ERR_Wr = NULL;
SECURITY_ATTRIBUTES sa;
// Set the bInheritHandle flag so pipe handles are inherited.
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
if (!CreatePipe(&g_hChildStd_ERR_Rd, &g_hChildStd_ERR_Wr, &sa, 0)) { return 1; } // Create a pipe for the child process's STDERR.
if (!SetHandleInformation(g_hChildStd_ERR_Rd, HANDLE_FLAG_INHERIT, 0)) { return 1; } // Ensure the read handle to the pipe for STDERR is not inherited.
if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &sa, 0)) { return 1; } // Create a pipe for the child process's STDOUT.
if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) { return 1; } // Ensure the read handle to the pipe for STDOUT is not inherited
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
bool bSuccess = FALSE;
// Set up members of the PROCESS_INFORMATION structure.
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
// Set up members of the STARTUPINFO structure.
// This structure specifies the STDERR and STDOUT handles for redirection.
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = g_hChildStd_ERR_Wr;
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
// Create the child process.
bSuccess = CreateProcess(
NULL, // program name
(char*)cmd, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
CREATE_NO_WINDOW, // creation flags (this is what hides the window)
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo // receives PROCESS_INFORMATION
);
CloseHandle(g_hChildStd_ERR_Wr);
CloseHandle(g_hChildStd_OUT_Wr);
// read output
#define BUFSIZE 4096
DWORD dwRead;
CHAR chBuf[BUFSIZE];
bool bSuccess2 = FALSE;
for (;;) { // read stdout
bSuccess2 = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
if(!bSuccess2 || dwRead == 0) break;
std::string s(chBuf, dwRead);
outOutput += s;
}
dwRead = 0;
for (;;) { // read stderr
bSuccess2 = ReadFile(g_hChildStd_ERR_Rd, chBuf, BUFSIZE, &dwRead, NULL);
if(!bSuccess2 || dwRead == 0) break;
std::string s(chBuf, dwRead);
outOutput += s;
}
// The remaining open handles are cleaned up when this process terminates.
// To avoid resource leaks in a larger application,
// close handles explicitly.
return 0;
}
int main(int argc, char* argv[]) {
std::string output;
runCmd("cmd /c dir", output);
std::cout << output << std::endl;
return 0;
}
With POSIX it should be something like this:
//Create the pipe.
int lsOutPipe[2];
pipe(lsOutPipe);
//Fork to two processes.
pid_t lsPid=fork();
//Check if I'm the child or parent.
if ( 0 == lsPid )
{//I'm the child.
//Close the read end of the pipe.
close(lsOutPipe[0]);
//Make the pipe be my stdout.
dup2(lsOutPipe[1],STDOUT_FILENO);
//Replace my self with ls (using one of the exec() functions):
exec("ls"....);//This never returns.
} // if
//I'm the parent.
//Close the read side of the pipe.
close(lsOutPipe[1]);
//Read stuff from ls:
char buffer[1024];
int bytesRead;
do
{
bytesRead = read(emacsInPipe[0], buffer, 1024);
// Do something with the read information.
if (bytesRead > 0) printf(buffer, bytesRead);
} while (bytesRead > 0);
You should off course check return values etc...
I needed to solve this for my full screen OpenGL Windows application, but was unable to prevent the console window popping up. Instead, taking back focus after a short delay seems to work well enough to avoid seeing it.
_popen(cmd, "wb");
Sleep(100);
ShowWindow(hWnd, SW_SHOWDEFAULT);
SetForegroundWindow(hWnd);
Update: this apparently doesn't work if the program is launched from Explorer. It is working when launched from Visual Studio.
精彩评论