Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

I/O Redirection fails on W7 / W2008R2

1 view
Skip to first unread message

Sirp Potijk

unread,
Dec 23, 2009, 4:20:15 AM12/23/09
to
Hello,

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

Sirp Potijk

unread,
Dec 23, 2009, 6:32:52 AM12/23/09
to

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

0 new messages