I'm working on a library which needs to be able to repeatedly redirect
stdout to a file and back to the console again.
To do this I'm using something to the effect of the code below, which is
shown to work on W2003/XP/2008R1 but breaks on W7 / W2008R2:
//----------------------------------------------------------------------
// IORedirection.cpp
//
#include "windows.h"
#include "stdafx.h"
#include "stdarg.h"
#include <iostream>
void cdecl dbg(char *format, ... ) {
va_list args;
FILE *fp;
char buffer[ 4095 + 1 ];
static bool bFirstTime = false; // TRUE;
if ((fp = fopen("c:\\axdebug\\dbg.txt", bFirstTime ? "wt" : "at"))
== NULL) {
bFirstTime = false;
return;
}
bFirstTime = false;
va_start( args, format );
vsprintf( buffer, format, args );
va_end( args );
fprintf( fp, buffer );
fclose( fp );
}
#define AXCDBG(s) dbg s
long assign_file_handles(char *pszStdOutFile, char *pszStdErrFile) {
AXCDBG(( ">> %s(%s, %s)\n", __FUNCTION__, pszStdOutFile,
pszStdErrFile ));
if( freopen( pszStdOutFile, "w+" ,stdout ) == NULL ) {
AXCDBG(( "<< assign_file_handles, error on reopen stdout\n" ));
return -992L;
}
if( freopen( pszStdErrFile, "w+" ,stderr ) == NULL ) {
AXCDBG(( "<< assign_file_handles, error on reopen stderr\n" ));
return -993L;
}
AXCDBG(( "<< %s success\n", __FUNCTION__ ));
return 0L;
}
int _tmain(int argc, _TCHAR* argv[]) {
assign_file_handles("stdout.txt", "stderr.txt");
std::cout << "1. Writing to standard output" << std::endl;
std::cerr << "1. Writing to standard error" << std::endl;
assign_file_handles("CONOUT$", "CONOUT$");
std::cout << "2. Writing to standard output" << std::endl;
std::cerr << "2. Writing to standard error" << std::endl;
assign_file_handles("stdout.txt", "stderr.txt");
std::cout << "3. Writing to standard output" << std::endl;
std::cerr << "3. Writing to standard error" << std::endl;
assign_file_handles("CONOUT$", "CONOUT$");
std::cout << "4. Writing to standard output" << std::endl;
std::cerr << "4. Writing to standard error" << std::endl;
std::cout << "Done !" << std::endl;
return 0;
}
//---------------------------------------------------------------------------
This function produces the following debug output on W7 / 2008:
>> assign_file_handles( stdout.txt, stderr.txt )
<< assign_file_handles success
>> assign_file_handles( CONOUT$, CONOUT$ )
<< assign_file_handles success
>> assign_file_handles( stdout.txt, stderr.txt )
<< assign_file_handles success
>> assign_file_handles( CONOUT$, CONOUT$ )
<< assign_file_handles, error on reopen stdout
Does anyone know why the second reopen on CONOUT$ fails ?
Kind regards,
Sirp Potijk
Sorry to reply to my own posting but I've found a solution:
//---------------------------------------------------------------------------
// IORedirection.cpp
//
#include "windows.h"
#include "stdafx.h"
#include "stdarg.h"
#include "io.h"
#include "fcntl.h"
#include <iostream>
void cdecl dbg(char *format, ... ) {
va_list args;
FILE *fp;
char buffer[ 4095 + 1 ];
static bool bFirstTime = false; // TRUE;
if ((fp = fopen("c:\\axdebug\\dbg.txt", bFirstTime ? "wt" : "at"))
== NULL) {
bFirstTime = false;
return;
}
bFirstTime = false;
va_start( args, format );
vsprintf( buffer, format, args );
va_end( args );
fprintf( fp, buffer );
fclose( fp );
}
#define AXCDBG(s) dbg s
HANDLE origouthandle = INVALID_HANDLE_VALUE;
HANDLE origerrhandle = INVALID_HANDLE_VALUE;
HANDLE outhandle = INVALID_HANDLE_VALUE;
HANDLE errhandle = INVALID_HANDLE_VALUE;
bool assignstdouterr(HANDLE outhdle, HANDLE errhdle) {
if (!SetStdHandle(STD_OUTPUT_HANDLE, outhdle) ||
!SetStdHandle(STD_ERROR_HANDLE, errhdle)) {
AXCDBG( ( "<< %s, error on setting stdhandles: %d\n",
__FUNCTION__, GetLastError()) );
return false;
}
int out = _open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE),
_O_TEXT);
int err = _open_osfhandle((long)GetStdHandle(STD_ERROR_HANDLE),
_O_TEXT);
if ((out == -1) || (err == -1)) {
AXCDBG( ( "<< %s, error in _open_osfhandle for %s, errorcode: %d\n",
__FUNCTION__, (out == -1) ? "stdout" : "stderr", GetLastError()) );
return false;
}
stdout->_file = out;
stderr->_file = err;
return true;
}
int _tmain(int argc, _TCHAR* argv[]) {
origouthandle = GetStdHandle(STD_OUTPUT_HANDLE);
origerrhandle = GetStdHandle(STD_ERROR_HANDLE);
outhandle = CreateFile(_T("stdout.txt"),
GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
errhandle = CreateFile(_T("stderr.txt"),
GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if ((outhandle == INVALID_HANDLE_VALUE) ||
(errhandle == INVALID_HANDLE_VALUE)) {
AXCDBG( ( "<< %s, error on opening %s, errorcode: %d\n",
__FUNCTION__,
(outhandle == INVALID_HANDLE_VALUE) ? "stdout" : "stderr",
GetLastError()) );
return false;
}
assignstdouterr(outhandle, errhandle);
std::cout << "1. Writing to standard output" << std::endl;
std::cerr << "1. Writing to standard error" << std::endl;
CloseHandle(outhandle);
CloseHandle(errhandle);
assignstdouterr(origouthandle, origerrhandle);
std::cout << "2. Writing to standard output" << std::endl;
std::cerr << "2. Writing to standard error" << std::endl;
outhandle = CreateFile(_T("stdout.txt"),
GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
errhandle = CreateFile(_T("stderr.txt"),
GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if ((outhandle == INVALID_HANDLE_VALUE) ||
(errhandle == INVALID_HANDLE_VALUE)) {
AXCDBG( ( "<< %s, error on opening %s, errorcode: %d\n", __FUNCTION__,
(outhandle == INVALID_HANDLE_VALUE) ? "stdout" : "stderr",
GetLastError()) );
return false;
}
assignstdouterr(outhandle, errhandle);
std::cout << "3. Writing to standard output" << std::endl;
std::cerr << "3. Writing to standard error" << std::endl;
assignstdouterr(origouthandle, origerrhandle);
std::cout << "4. Writing to standard output" << std::endl;
std::cerr << "4. Writing to standard error" << std::endl;
std::cout << "Done !" << std::endl;
return 0;
}
//---------------------------------------------------------------------------
I'm sorry to see that my first code doesn't work anymore since I think
it was simpler.
Thanks to anyone who has looked into this.
Kind regards,
Sirp Potijk