Created
November 16, 2012 18:28
-
-
Save azrafe7/4089665 to your computer and use it in GitHub Desktop.
read from process stdout
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Slightly modified code from http://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx | |
// Ma non capisco perché non mi termina dopo aver stampato l'output | |
// E comunque popen continua a non funzionarmi (CodeBlocks with MinGW - gcc 4.7.2) | |
#include <windows.h> | |
#include <tchar.h> | |
#include <stdio.h> | |
//#include <strsafe.h> | |
#define BUFSIZE 4096 | |
// Child output is written to this temp file and then read by this parent process (you may want to delete it when you're finished with it) | |
char *tempFile = "child.out"; | |
// Child process cmd line | |
//TCHAR szCmdline[]=TEXT("c:\\windows\\system32\\getmac.exe"); | |
TCHAR szCmdline[]=TEXT("cmd /c dir"); | |
HANDLE g_hChildStd_IN_Rd = NULL; | |
HANDLE g_hChildStd_IN_Wr = NULL; | |
HANDLE g_hChildStd_OUT_Rd = NULL; | |
HANDLE g_hChildStd_OUT_Wr = NULL; | |
HANDLE g_hInputFile = NULL; | |
void CreateChildProcess(void); | |
void WriteToPipe(void); | |
void ReadFromPipe(void); | |
void ErrorExit(char *); | |
int _tmain(int argc, TCHAR *argv[]) | |
{ | |
SECURITY_ATTRIBUTES saAttr; | |
printf("\n->Start of parent execution.\n"); | |
// Set the bInheritHandle flag so pipe handles are inherited. | |
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); | |
saAttr.bInheritHandle = TRUE; | |
saAttr.lpSecurityDescriptor = NULL; | |
// Create a pipe for the child process's STDOUT. | |
if ( ! CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0) ) | |
ErrorExit("StdoutRd CreatePipe"); | |
// Ensure the read handle to the pipe for STDOUT is not inherited. | |
if ( ! SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0) ) | |
ErrorExit("Stdout SetHandleInformation"); | |
// Create a pipe for the child process's STDIN. | |
/*if (! CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0)) | |
ErrorExit("Stdin CreatePipe");*/ | |
// Ensure the write handle to the pipe for STDIN is not inherited. | |
/*if ( ! SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0) ) | |
ErrorExit("Stdin SetHandleInformation");*/ | |
// Create the child process. | |
CreateChildProcess(); | |
// Get a handle to an input file for the parent. | |
// This example assumes a plain text file and uses string output to verify data flow. | |
g_hInputFile = CreateFile( | |
tempFile, | |
GENERIC_READ, | |
0, | |
NULL, | |
OPEN_ALWAYS, | |
FILE_ATTRIBUTE_READONLY, | |
NULL); | |
if ( g_hInputFile == INVALID_HANDLE_VALUE ) | |
ErrorExit("CreateFile"); | |
// Write to the pipe that is the standard input for a child process. | |
// Data is written to the pipe's buffers, so it is not necessary to wait | |
// until the child process is running before writing data. | |
/*WriteToPipe(); | |
printf( "\n->Contents of %s written to child STDIN pipe.\n", argv[1]);*/ | |
// Read from pipe that is the standard output for child process. | |
printf( "\n->Contents of child process STDOUT: %s \n\n", tempFile); | |
ReadFromPipe(); | |
printf("\n->End of parent execution.\n"); | |
// The remaining open handles are cleaned up when this process terminates. | |
// To avoid resource leaks in a larger application, close handles explicitly. | |
return 0; | |
} | |
void CreateChildProcess() | |
// Create a child process that uses the previously created pipes for STDIN and STDOUT. | |
{ | |
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 STDIN and STDOUT handles for redirection. | |
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) ); | |
siStartInfo.cb = sizeof(STARTUPINFO); | |
siStartInfo.hStdError = g_hChildStd_OUT_Wr; | |
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr; | |
siStartInfo.hStdInput = g_hChildStd_IN_Rd; | |
siStartInfo.dwFlags |= STARTF_USESTDHANDLES; | |
// Create the child process. | |
bSuccess = CreateProcess(NULL, | |
szCmdline, // 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 an error occurs, exit the application. | |
if ( ! bSuccess ) | |
ErrorExit(TEXT("CreateProcess")); | |
else | |
{ | |
// Close handles to the child process and its primary thread. | |
// Some applications might keep these handles to monitor the status | |
// of the child process, for example. | |
CloseHandle(piProcInfo.hProcess); | |
CloseHandle(piProcInfo.hThread); | |
} | |
} | |
void WriteToPipe(void) | |
// Read from a file and write its contents to the pipe for the child's STDIN. | |
// Stop when there is no more data. | |
{ | |
DWORD dwRead, dwWritten; | |
CHAR chBuf[BUFSIZE]; | |
BOOL bSuccess = FALSE; | |
for (;;) | |
{ | |
bSuccess = ReadFile(g_hInputFile, chBuf, BUFSIZE, &dwRead, NULL); | |
if ( ! bSuccess || dwRead == 0 ) break; | |
bSuccess = WriteFile(g_hChildStd_IN_Wr, chBuf, dwRead, &dwWritten, NULL); | |
if ( ! bSuccess ) break; | |
} | |
// Close the pipe handle so the child process stops reading. | |
if ( ! CloseHandle(g_hChildStd_IN_Wr) ) | |
ErrorExit(TEXT("StdInWr CloseHandle")); | |
} | |
void ReadFromPipe(void) | |
// Read output from the child process's pipe for STDOUT | |
// and write to the parent process's pipe for STDOUT. | |
// Stop when there is no more data. | |
{ | |
DWORD dwRead, dwWritten; | |
CHAR chBuf[BUFSIZE]; | |
BOOL bSuccess = FALSE; | |
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE); | |
for (;;) | |
{ | |
bSuccess = ReadFile( g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL); | |
if( ! bSuccess || dwRead == 0 ) break; | |
bSuccess = WriteFile(hParentStdOut, chBuf, | |
dwRead, &dwWritten, NULL); | |
if (! bSuccess ) break; | |
} | |
} | |
void ErrorExit(char *msg) | |
// Format a readable error message, display a message box, | |
// and exit from the application. | |
{ | |
printf("%s\n", msg); | |
exit(1); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Slightly modified code from http://ubuntuforums.org/archive/index.php/t-610271.html | |
// Ancora più interessante e conciso (leggi tutto il thread) | |
#include <windows.h> | |
#include <tchar.h> | |
#include <stdio.h> | |
char * output; | |
char * run_command(LPCTSTR cmd); | |
int _tmain(int argc, TCHAR *argv[]) | |
{ | |
if ((output = run_command("cmd.exe /c dir c:\\"))) | |
{ | |
MessageBox(0, output, "Success", MB_OK); | |
GlobalFree(output); | |
} | |
return 0; | |
} | |
#ifdef __cplusplus | |
extern "C" { | |
#endif | |
// Define OUTPUTBUFSIZE to be as big as the largest output you expect | |
// from the console app, plus one char. For example, if you | |
// expect the app to return 10 chars, define this to be 11. | |
#define OUTPUTBUFSIZE 4096*10 | |
const TCHAR ErrorStr[] = "Error"; | |
const TCHAR NoMem[] = "Out of memory"; | |
const TCHAR NoPipeMsg[] = "Can't open pipe"; | |
const TCHAR NoLaunchMsg[] = "Can't start console app"; | |
const TCHAR NoOutput[] = "Can't read output of console app"; | |
char * run_command(LPCTSTR cmd) | |
{ | |
STARTUPINFO sinfo; | |
PROCESS_INFORMATION pinfo; | |
SECURITY_ATTRIBUTES sattr; | |
HANDLE readfh, writefh; | |
register char *cbuff; | |
// Allocate a buffer to read the app's output | |
if (!(cbuff = (char *)GlobalAlloc(GMEM_FIXED, OUTPUTBUFSIZE))) | |
{ | |
MessageBox(0, &NoMem[0], &ErrorStr[0], MB_OK|MB_ICONEXCLAMATION); | |
return 0; | |
} | |
// Initialize the STARTUPINFO struct | |
ZeroMemory(&sinfo, sizeof(STARTUPINFO)); | |
sinfo.cb = sizeof(STARTUPINFO); | |
sinfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; | |
// Uncomment this if you want to hide the other app's | |
// DOS window while it runs | |
// sinfo.wShowWindow = SW_HIDE; | |
sinfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); | |
sinfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); | |
sinfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); | |
// Initialize security attributes to allow the launched app to | |
// inherit the caller's STDOUT, STDIN, and STDERR | |
sattr.nLength = sizeof(SECURITY_ATTRIBUTES); | |
sattr.lpSecurityDescriptor = 0; | |
sattr.bInheritHandle = TRUE; | |
// Get a pipe from which we read | |
// output from the launched app | |
if (!CreatePipe(&readfh, &sinfo.hStdOutput, &sattr, 0)) | |
{ | |
// Error opening the pipe | |
MessageBox(0, &NoPipeMsg[0], &ErrorStr[0], MB_OK|MB_ICONEXCLAMATION); | |
GlobalFree(cbuff); | |
return 0; | |
} | |
// Launch the app. We should return immediately (while the app is running) | |
if (!CreateProcess(0, cmd, 0, 0, TRUE, 0, 0, 0, &sinfo, &pinfo)) | |
{ | |
MessageBox(0, &NoLaunchMsg[0], &ErrorStr[0], MB_OK|MB_ICONEXCLAMATION); | |
CloseHandle(sinfo.hStdInput); | |
CloseHandle(writefh); | |
CloseHandle(readfh); | |
CloseHandle(sinfo.hStdOutput); | |
GlobalFree(cbuff); | |
return 0; | |
} | |
// Don't need the read access to these pipes | |
CloseHandle(sinfo.hStdInput); | |
CloseHandle(sinfo.hStdOutput); | |
// We haven't yet read app's output | |
sinfo.dwFlags = 0; | |
// Input and/or output still needs to be done? | |
while (readfh) | |
{ | |
// Capture more output of the app? | |
// Read in upto OUTPUTBUFSIZE bytes | |
if (!ReadFile(readfh, cbuff + sinfo.dwFlags, OUTPUTBUFSIZE - sinfo.dwFlags, &pinfo.dwProcessId, 0) || !pinfo.dwProcessId) | |
{ | |
// If we aborted for any reason other than that the | |
// app has closed that pipe, it's an | |
// error. Otherwise, the program has finished its | |
// output apparently | |
if (GetLastError() != ERROR_BROKEN_PIPE && pinfo.dwProcessId) | |
{ | |
// An error reading the pipe | |
MessageBox(0, &NoOutput[0], &ErrorStr[0], MB_OK|MB_ICONEXCLAMATION); | |
GlobalFree(cbuff); | |
cbuff = 0; | |
break; | |
} | |
// Close the pipe | |
CloseHandle(readfh); | |
readfh = 0; | |
} | |
sinfo.dwFlags += pinfo.dwProcessId; | |
} | |
// Close input pipe if it's still open | |
if (writefh) CloseHandle(writefh); | |
// Close output pipe | |
if (readfh) CloseHandle(readfh); | |
// Wait for the app to finish | |
WaitForSingleObject(pinfo.hProcess, INFINITE); | |
// Close process and thread handles | |
CloseHandle(pinfo.hProcess); | |
CloseHandle(pinfo.hThread); | |
// Nul-terminate it | |
if (cbuff) *(cbuff + sinfo.dwFlags) = 0; | |
// Return the output | |
return cbuff; | |
} | |
#ifdef __cplusplus | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
C/C++ - How to read output (STDOUT & STDERR) from an external command on Windows