// Display the character read on the screen.
==> if (!WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),lpBuffer,
nBytesRead,&nCharsWritten,NULL))
Redirecting console output.
My program executes a console application (using CreateProcess).
I'd like to capture the output (stdout, stderr) of the spawned application.
It seems like most of the stuff google comes up with, reference to this article.
But I can't even get the sample code to work!
Running the compiled code, provided in the article, never reaches the line:
I've tried to execute several different programs, including command lines like "command.com /c dir *.* c:\*.* /s" etc. No luck!
Anyone know the correct way to do it?
Quote:Original post by eqThen what's the last line it does reach? Have you tried debugging the application?
Running the compiled code, provided in the article, never reaches the line:
We really need more information to be able to help you.
Unix makes this way too easy..
Of course I've debugged, it simply doesn't read anything, always returns ERROR_BROKEN_PIPE.
After reading some more articles, the following method only works if the executed command flushes the buffers every now and then (which isn't the case with ANY dos commands or ANY of the other programs I've tested with).
This makes it pretty useless. A workaround seems to always spawn a special program, that in turn spawns the desired program!?
Anyone got something better up and going?
if (!ReadFile(hPipeRead,lpBuffer,sizeof(lpBuffer), &nBytesRead,NULL) || !nBytesRead) { if (GetLastError() == ERROR_BROKEN_PIPE)====> break; // pipe done - normal exit path. else DisplayError("ReadFile"); // Something bad happened. }
After reading some more articles, the following method only works if the executed command flushes the buffers every now and then (which isn't the case with ANY dos commands or ANY of the other programs I've tested with).
This makes it pretty useless. A workaround seems to always spawn a special program, that in turn spawns the desired program!?
Anyone got something better up and going?
Partially sorted, it turns out that the flush isn't needed if you have a console.
So test if your app is a console app (or you might hardcode this).
If it's not a console app use AllocConsole to create a console, hide this console. The use CreateProcess with CREATE_NEW_PROCESS_GROUP instead CREATE_NEW_CONSOLE.
Now all output is redirected as it should.
When we're done executing a command, the console needs to be freed (FreeConsole).
The problem is that the console isn't terminated as expected (disable the ShowWindow(console, SW_HIDE) or look at the active processes in the task manager).
I tried doing a DestroyWindow on the console window but that doesn't seem to work.
How can I terminate a running application (given the HWND)?
So test if your app is a console app (or you might hardcode this).
If it's not a console app use AllocConsole to create a console, hide this console. The use CreateProcess with CREATE_NEW_PROCESS_GROUP instead CREATE_NEW_CONSOLE.
// Do first thing in main() HANDLE hConsole = GetStdHandle(STD_ERROR_HANDLE); HWND consoleWindow = null; if ((hConsole == null) || (hConsole == INVALID_HANDLE_VALUE)){ HWND (WINAPI* getConsoleWindow)() = (HWND (WINAPI*)())GetProcAddress(GetModuleHandle("kernel32.dll"), "GetConsoleWindow"); LockWindowUpdate(GetDesktopWindow()); // sometimes it prevents flashing if (AllocConsole() == FALSE) DisplayError("Alloc console!"); if (getConsoleWindow){ consoleWindow = getConsoleWindow(); }else { const char temp[] = "ThisIsMyConsoleNameMustBeUnique"; SetConsoleTitle(temp); Sleep(40); consoleWindow = FindWindow(NULL, temp); } if (!consoleWindow) DisplayError("Couldn't find console window!"); ShowWindow(console, SW_HIDE); LockWindowUpdate(NULL); }
Now all output is redirected as it should.
When we're done executing a command, the console needs to be freed (FreeConsole).
The problem is that the console isn't terminated as expected (disable the ShowWindow(console, SW_HIDE) or look at the active processes in the task manager).
I tried doing a DestroyWindow on the console window but that doesn't seem to work.
How can I terminate a running application (given the HWND)?
As trimmed from the MSDN docs:
#include <windows.h>#include <iostream>using std::cout;using std::endl;bool CreateChildProcess(LPSTR cmd_line);void ReadFromHandle(const HANDLE &hReadHandle);int main(void) { // Be nice and save the original handle to stdout, since we will be altering where it is directed at HANDLE hStdOutOriginal = GetStdHandle(STD_OUTPUT_HANDLE); // stdout will be redirected from the console to this end of the pipe HANDLE hWriteEnd; // this is the handle we use to read back whatever was written to the pipe HANDLE hReadEnd; // Set the bInheritHandle flag to TRUE, // so that the child process inherits the parent's stdio handle (**This is the key**) SECURITY_ATTRIBUTES saAttr; saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; // 1. Create a pipe (nothing special) if(!CreatePipe(&hReadEnd, &hWriteEnd, &saAttr, 0)) { cout << "CreatePipe failed." << endl; return 0; } //2. Redirect parent's stdout from the console to the "write" end of the pipe (nothing special) if(!SetStdHandle(STD_OUTPUT_HANDLE, hWriteEnd)) { cout << "stdout redirection failed." << endl; return 0; } // 3. Create the child process (nothing special, except...) // Because saAttr.bInheritHandle is TRUE, the child process will inherit the parent's stdout, // which happens to be currently redirected to the "write" end of the pipe if(!CreateChildProcess("rsine")) { cout << "Process creation failed." << endl; return 0; } // 4. Close the "write" end of the pipe, since the child process is now finished // If this is not done, the parent process will wait indefinitely for more data to come down the pipe if(!CloseHandle(hWriteEnd)) { cout << "Pipe write end closure failed." << endl; return 0; } // 5. Print out whatever's been stuffed into the "write" end of the pipe cout << "This is what I found in the pipe:" << endl; cout << "@*******************************@" << endl; ReadFromHandle(hReadEnd); cout << "@*******************************@"; // 6. Clean up if(!CloseHandle(hReadEnd)) { cout << "Pipe read end closure failed." << endl; return 0; } // 7. More clean up :) SetStdHandle(STD_OUTPUT_HANDLE, hStdOutOriginal); return 0; } bool CreateChildProcess(LPSTR cmd_line){ // Absolutely nothing fancy goes on in this function... PROCESS_INFORMATION piProcInfo; ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); STARTUPINFO siStartInfo; ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); siStartInfo.cb = sizeof(STARTUPINFO); // Create the child process, nothing special if(!CreateProcess(NULL, cmd_line, NULL, NULL, FALSE, 0, NULL, NULL, &siStartInfo, &piProcInfo)) { return false; } // The process started and finished successfully CloseHandle(piProcInfo.hProcess); CloseHandle(piProcInfo.hThread); return true;}void ReadFromHandle(const HANDLE &hReadHandle){ // Nothing really fancy goes on in this function... // the hReadHandle could be for a file, a pipe, a printer port, whatever, etc.#define BUFSIZE 4096 DWORD dwRead; CHAR chBuf[BUFSIZE]; // Read output from handle, and write to cout (in upper case) for (;;) { if(!ReadFile(hReadHandle, chBuf, BUFSIZE, &dwRead, NULL) || dwRead == 0) break; for(DWORD i = 0; i < dwRead; i++) cout << chBuf; } }
Yes I've seen that aswell, this has the same problem as the others.
In order to capture output a console needs to be present.
Creating that console is simple (AllocConsole).
Problem is to get rid of the console once you don't need it anymore.
In order to capture output a console needs to be present.
Creating that console is simple (AllocConsole).
Problem is to get rid of the console once you don't need it anymore.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement