The title says it all. When I run the following code:
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE hFile = CreateFile(TEXT("Foo.txt"), GENERIC_WRITE, FILE_READ_ACCESS | FILE_WRITE_ACCESS,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
SetStdHandle(STD_OUTPUT_HANDLE, hFile);
std::cout << "Hello, ";
printf("world!
");
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "Hello, world!
", 13, NULL, NULL);
SetStdHandle(STD_OUTPUT_HANDLE, hOut);
CloseHandle(hFile);
The result is that Hello, world!
gets written to the console as a result of the calls to cout
and printf
, and Hello, world!
also gets written to the file Foo.txt
as a result of the call to WriteFile
. My assumption is that when everything gets initialized at the very beginning, the HANDLE
returned by GetStdHandle
is cached and reused for both cout
and printf
. That's perfectly reasonable and exactly what I would want as I assume GetStdHandle
requires a call to the operating system (which can be long!). The trouble is that I want to override that behavior and "sync" both cout and printf with the application's standard handles if possible.
Before suggesting any alternatives, let me describe exactly what it is I am trying to do (yes, I know that it is possible to use freopen
for this purpose). What I need to be able to do is to "save" the current standard output handle on a stack-like data structure before I change it so that I can be able to restore the previous output handle. Anything short of that is unacceptable for this situation (i.e. I can't restore to CONOUT$
, etc.). This needs to have the ability to be recursive. I.e. the following should work as you would expect it to:
std::cout << "A1" << std::endl;
StartStdOutRedirection(TEXT("Foo.txt"));
std::cout << "B1" << std::endl;
StartStdOutRedirection(TEXT("Bar.txt"));
std::cout << "C1" << std::endl;
EndStdOutRedirection();
std::cout << "B2" << std::endl;
EndStdOutRedirection();
std::cout << "A2" << std::endl;
This would be excessively easy if there was a way to "re-sync" stdout
as the following code should do the trick:
std::vector<HANDLE> vStdOutHandles;
void StartStdOutRedirection(_In_ LPCTSTR lpFile)
{
vStdOutHandles.push_back(GetStdHandle(STD_OUTPUT_HANDLE));
SetStdHandle(STD_OUTPUT_HANDLE, CreateFile(lpFile, GENERIC_WRITE,
FILE_WRITE_ACCESS | FILE_READ_ACCESS, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL));
}
void EndStdOutRedirection(void)
{
CloseHandle(GetStdHandle(STD_INPUT_HANDLE));
SetStdHandle(STD_OUTPUT_HANDLE, vStdOutHandles.back());
vStdOutHandles.pop_back();
}
The correctness of the above code can be verified by using WriteFile
with a call to GetStdHandle(STD_OUTPUT_HANDLE)
in place of cout
. What I ideally need is an equivalent of freopen
that works on HANDLE
s. That way I could use DuplicateHandle
on the HANDLE
returned by GetStdHandle
and then this MyReopenHandle
function to set the underlying file for that HANDLE
to the file of my liking. I believe that would work as I assume both printf
and cout
have a HANDLE
saved somewhere deep down. I tried to "fake it" by duplicating the standard output handle, closing that handle, and then calling CreateFile
in hopes that it'll give me the same HANDLE
value, but that works sporadically at best. Here's my code for that if you are interested:
std::vector<HANDLE> vStdOutHandles;
bool StartStdOutRedirection(_In_ LPCTSTR lpFile)
{
bool fResult = false;
HANDLE hProc = GetCurrentProcess();
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hOut != INVALID_HANDLE_VALUE)
{
HANDLE hDup;
if (DuplicateHandle(hProc, hOut, hProc, &hDup, 0, FALSE, DUPLICATE_SAME_ACCESS))
{
// Need to close the current handle before we open the new one
CloseHandle(hOut);
HANDLE hFile = CreateFile(lpFile, GENERIC_WRITE, FILE_WRITE_ACCESS | FILE_READ_ACCESS,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
// Should be same HANDLE; else we're screwed...
assert(hFile == hOut);
SetStdHandle(STD_OUTPUT_HANDLE, hFile);
vStdOutHandles.push_back(hDup);
fResult = true;
}
else
{
// Otherwise, reopen the previous output HANDLE on failure
DuplicateHandle(hProc, hDup, hProc, &hFile, 0, FALSE, DUPLICATE_SAME_ACCESS);
assert(hFile == hOut);
CloseHandle(hDup);
}
}
}
return fResult;
}
bool EndStdOutRedirection(void)
{
bool fResult = false;
HANDLE hProc = GetCurrentProcess();
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hOut != INVALID_HANDLE_VALUE && vStdOutHandles.size() != 0)
{
HANDLE hDup;
HANDLE hNext = vStdOutHandles.back();
// Close current handle and re-open previous one
CloseHandle(hOut);
if (DuplicateHandle(hProc, hNext, hProc, &hDup, 0, FALSE, DUPLICATE_SAME_ACCESS))
{
// Again, we're screwed if these are not the same
assert(hOut == hDup);
SetStdHandle(STD_OUTPUT_HANDLE, hDup);
vStdOutHandles.pop_back();
fResult = true;
}
}
return fResult;
}
The above assert fails about half the time (I wasn't really expecting or counting on that to work... I was just interested). That is about as far as I have gotten in terms of this problem. If anyone has any suggestions, please let me know :)
See Question&Answers more detail:
os