printf to both console window and file? - c++

I have a lot of C++ programs that compile with Visual Studio 2005. They're mostly small server modules that run in console windows. Anyway, the problem I'm running into is that text can only be displayed to either the console window or a log file but not both. Each program has a command line option to specify the log file. Here is the function that I call to redirect stdout and stderr to a file.
void consoleobj::setstdouterr(const stringobj& printstr)
{
#if !defined(_WIN32_WCE)
freopen(printstr.c_str(),"w",stdout);
#ifdef _MSC_VER
::SetStdHandle(STD_ERROR_HANDLE,GetStdHandle(STD_OUTPUT_HANDLE));
#endif
#endif
// make log msgs flush to log file(cout does this(on \n?), printf doesn't)
//now if both redir to same log file, msgs should be in right order
setvbuf(stdout, NULL, _IONBF, 0); //no buffering
setvbuf(stderr, NULL, _IONBF, 0); //no buffering
}//end method setstdouterr
Is there any way to set things up so stdout and stderr are written to both the console window and an optional log file simultaneously? I've seen code that redirects cout or a wrapper function, but our print statements all use printf and I'd prefer using a function similar to the one in our consoleobj library to set this up if possible. Thanks!

Instead of implement this functionality in your code.
You can use the well known utility tee in Unix.
There is a Windows version of it called wtee.exe.
C:\> programm | wtee log.txt

Related

WinAPI - How to redirect all stdout of a program and external DLLs to the Win32 standard output handle?

I want to be able to redirect all standard output of a Windows application to the Win32 standard output handle, instead of using a console handle.
For context, the Emacs Win32 FAQ says this:
Programs that explicitly use a handle to the console (CON or CON:) instead of stdin and stdout cannot be used as subprocesses to Emacs, and they will also not work in shell-mode [...] There is no convenient way for either Emacs or any shell used in shell-mode to redirect the input and output of such processes from the console to input and output pipes. The only workaround is to use a different implementation of the program that does not use the console directly.
(https://www.gnu.org/software/emacs/manual/html_node/efaq-w32/Subprocess-hang.html)
I'm experiencing the issue the FAQ describes: when started from Emacs, the program will run but none of its output is displayed in Emacs' shell window until the program exits, as if stdout was buffered and didn't flush while it was running. The same program will output stdout in real-time as expected if run from cmd.exe or ConEmu.
What I want to accomplish is making all the output of the program appear in an Emacs shell so I can jump to a compiler error location as soon as it's printed. I'm willing to rewrite the source of the program to accomplish this. I want to know what "different implementation" details are necessary to accomplish this by using "stdin and stdout" instead of "a handle to the console".
From what I understand:
There are multiple kinds of I/O in Windows, including the C runtime (printf, etc.) and the Win32 layer (ReadFile, etc.).
I'm assuming "stdin and stdout" refer to STD_INPUT_HANDLE and STD_OUTPUT_HANDLE which can be modified by SetStdHandle().
External DLLs loaded by a program will inherit the C runtime stdin and stdout pipes, but this happens on program initialization, before any calls to SetStdHandle() are called, so there is something else you have to do to redirect their output.
I've tried using this code:
#include <windows.h>
#include <cstdlib>
int main()
{
HANDLE hStdout = CreateFile(L"CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE hStdin = CreateFile(L"CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
SetStdHandle(STD_OUTPUT_HANDLE, hStdout);
SetStdHandle(STD_ERROR_HANDLE, hStdout);
SetStdHandle(STD_INPUT_HANDLE, hStdin);
std::cout << "Hello, world." << std::endl;
printf("Hello, world.\n");
std::cin.get();
return 0;
}
This has the desired effect, but only on usages of printf and std::cout within the same binary as the redirection code. My program loads an external DLL that uses printf and none of its output is redirected.
Also, I don't want to use AllocConsole() or similar since that opens a separate window, which does not integrate with the parent process (Emacs). What I want is to redirect all stdout so it shows up within the same terminal/console that is running the program instead of a different window (if that makes sense). Since I don't use AllocConsole(), then code like _open_osfhandle((long)hStdout, O_WRONLY|O_TEXT) always returns -1 for some reason, so it seems like I can't use dup2() as described here.
See also:
Redirecting stdout in win32 does not redirect stdout
Can't send buffer to gnuplot under Windows
I used the code example I provided above, then called setvbuf(stdout, NULL, _IONBF, 4096) to set non-buffered output and got the desired result.

Decide an application to be of console/windows subsystem at run time

I have an MFC application that generates some reports and shows the same in the GUI.
I have a requirement of running it as a console application, when passed with certain commandline argument.
In the console mode it will generate the reports/errors in standard output/error and I should be able to redirect the same to any file.
For Ex.
C:/temp MyApp.exe --console > report.txt should run my exe in console mode and redirect all the output to a text file.
But if I run it without any console argument, it should be like a default MFC application.
To achieve my requirement, so far I have done is, changed the Linker > System > Subsytem from Windows to Console and added WinMainCRTStartup at
Linker > Advanced > Entry Point
So now my app works fine when I run it with --console parameter from console/batch files.
But when I run it directly, it still opens a cmd window (of course because it is now a console application). However, I am using FreeConsole() method to get rid of it but it still flashes for a brief second.
So I am just curious if there is a way to get rid of it completely, either by deciding the application's subsytem at run time or any other trick?
Any suggestion will be appreciated.
I'd suggest to keep your GUI application with the windows subsystem.
At the very beginning, when parsing command line, instead of creating the GUI windows (MFC inistialisation), you could create a console or attach with AttachConsole()
As a proof of concept, here how it could look like (for example in CxxxApp::InitInstance()):
... // init code but before the the CMainFrame is created
if(...) { // suppose you want to go to the console
if (! AttachConsole(ATTACH_PARENT_PROCESS)) // try to hijack existing console of command line
AllocConsole(); // or create your own.
DWORD nw,nr; // demo with windows native console i/o
char buff[32];
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), L"Who are you ? ", 14, &nw, NULL);
ReadConsoleA(GetStdHandle(STD_INPUT_HANDLE), buff, sizeof(buff), &nr, NULL);
WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), "Hello ", 6, &nw, NULL);
WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), buff, nr, &nw, NULL);
ReadConsoleA(GetStdHandle(STD_INPUT_HANDLE), buff, 1, &nr, NULL);
...
}
If you want to use C++ cin/cout, additional work is however needed. This other SO question addresses for example the redirecting of cout.

How to listen to stderr in C/C++ for sending to callback?

How do I passively listen to stderr and obtain it as string for sending to callback? I have seen posts on reading stderr but I want to listen to it rather than actively reading it.
Background:
I have a cross-platform piece that uses 3rd party library (libcurl) which will output verbose info into stderr. This cross-platform piece is to be used by more than 1 non-cross-platform applications.
I would like to log these info, which I can do by providing FILE* to libcurl. But instead of doing that, I want to see if I can capture (passively listen to) the output in stderr as string, and send back to the calling main application via callback. This has the benefit of 1. main app can keep a single log using whatever logging tool it wants. 2. it will keep this piece cross-platform.
Doing this in a single process is a little tricky, but you can probably do it.
1: Using freopen() you can redirect your stderr to a named file. You can simultaneously open that file for reading on another handle. You might also need to call setvbuf() on stderr to turn off buffering on output to stderr so that you will be able to read it right away from the 2nd handle. Since it is being written to a file you can read it at anytime - when it is convenient. The unix function "select" is what you need if you want to be notified when the file changes. (see also fileno()).
2: More tricky would be to setup stderr as the write end of a pipe. Should be doable using dup3(), though this isn't exactly cross-platform (to non-unixy OS's). It would also require that a 2nd thread be reading from the pipe to prevent the writer from being blocked if they write very much.
Like:
FILE *stream = freopen("stderr.out", "w", stderr); // Added missing pointer
setvbuf(stream, 0, _IONBF, 0); // No Buffering
FILE *input = fopen("stderr.out", "r");
fprintf(stderr, "Output to stderr dude\n");
//fflush(stderr); // You can explicitly flush instead of setting no buffering.
char buffer[1024];
while (fgets(buffer, 512, input))
{
printf(">>>%s\n", buffer);
}

C++ separate command line window?

So I have a GUI program and for some reason it does not let me debug using printf().
When I use printf(), it does not go to the Visual Studio debugger for some reason.
Anyways, I wanted to make my own separate window that opens up when the GUI opens up,
and basically be able to feed information into that console and talk to it.
For example:
void talk(std::string info){
//Add the value of info to the next line in the console
}
Anyone know how to do this?
Basically create a command line and talk to it so I can see output:
CommandLine c;
c.talk("hey!");
You can create a console using AllocConsole to create a console, then write to that explicitly (there are a few methods, GetStdHandle and file write will work). You can also use OutputDebugString to write to the VS output window.
void makeConsole()
{
AllocConsole();
console = GetStdHandle(STD_OUTPUT_HANDLE);
}
void talk(std::string info)
{
WriteFile(console, info.c_str(), info.length()); // To console
OutputDebugString(info.c_str()); // To output window
}
(pseudo-code, functions may not be quite right)
Edit:
If you're writing to the console only through your talk function, this will work fine. If you're using printf/cout throughout your code, you definitely want to use Ben's method (much simpler to use repeatedly).
#peachykeen has half the solution. If you want to make printf and cout work, try this:
AllocConsole();
freopen("CONOUT$", "w", stdout);

launch app, capture stdout and stderr in c++

How do I launch an app and capture the output via stdout and maybe stderr?
I am writing an automated build system and I need to capture the output to analyze. I'd like to update the svn repo and grab the revision number so I can move the files in autobuild/revNumber/ if successful. I also would like to build using make and upload the compile text to my server for everyone to see the warnings and errors on a failed build.
I can't find the system() function, but I found the CreateProcess() function on MSDN. I am able to launch what I need but I have no idea how to capture the stderr and stdout. I notice the process launches separately unless I set a breakpoint and keep my app exiting which it then will keep all the text in my app console window. I would also want to wait until all processes are finished and then scan the data it produced to do any additional operations I need. How do I do any of this?
In real shells (meaning, not sea shells - I mean, not in C Shell or its derivatives), then:
program arg1 arg2 >/tmp/log.file 2>&1
This runs program with the given arguments, and redirects the stdout to /tmp/log.file; the notation (hieroglyph) '2>&1' at the end sends stderr (file descriptor 2) to the same place that stdout (file descriptor 1) is going. Note that the sequence of operations is important; if you reverse them, then standard error will go to where standard output was going, and then standard output (but not standard error) will be redirected to the file.
The choice of file name shown is abysmal for numerous reasons - you should allow the user to choose the directory, and probably should include the process ID or time stamp in the file name.
LOG=${TMPDIR:-/tmp}/log.$$.$(date +%Y%m%d-%H%M%S)
program arg1 arg2 >$LOG 2>&1
In C++, you can use the system() function (inherited from C) to run processes. If you need to know the file name in the C++ program (plausible), then generate the name in the program (strftime() is your friend) and create the command string with that file name.
(Strictly, you also need getenv() to get $TMPDIR, and the POSIX function getpid() to get the process ID, and then you can simulate the two-line shell script (though the PID used would be of the C++ program, not the launched shell).
You could instead use the POSIX popen() function; you'd have to include the '2>&1' notation in the command string that you create to send the standard error of the command to the same place as standard output goes, but you would not need a temporary file:
FILE *pp = popen("program arg1 arg2 2>&1", "r");
You can then read off the file stream. I'm not sure whether there's a clean way to map a C file stream into a C++ istream; there probably is.
You need to fill up the STARTUP_INFO structure, which has hStdInput, hStdOutput and hStdError. Remember to inherit handles when you CreateProcess.
/* Assume you open a file handle or pipe called myoutput */
STARTUP_INFO si_startinfo;
ZeroMemory(&si_startinfo, sizeof(STARTUP_INFO));
si_startinfo.cb = sizeof(STARTUP_INFO);
si_startinfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
si_startinfo.hStdOutput = myoutput;
si_startinfo.hStdError = myoutput;
si_startifno.dwFlags != STARTF_USEHANDLES;
PROCESS_INFORMATION pi_procinfo;
ZeroMemory(&pi_procinfo, sizeof(PROCESS_INFORMATION);
CreateProcess(NULL, cmdline, NULL, NULL, true, 0, NULL, pathname, &si_startinfo, &pi_procinfo);
I have not shown the error handling aspects, which you will need to do. The 5th argument is set to true to inherit the handles. Others have explained how to create pipes so I won't repeat it here.
Microsoft's CRTs and the MSDN library do include the system function and the _popen function.