Skip to content

Instantly share code, notes, and snippets.

@rhoot
Created June 8, 2012 02:27
Show Gist options
  • Save rhoot/2893136 to your computer and use it in GitHub Desktop.
Save rhoot/2893136 to your computer and use it in GitHub Desktop.
Win32 application entry point redirection
/** \file WinMain.cpp
* \author rhoot <https://github.com/rhoot>
*
* \brief Redirects calls from the windows specific WinMain() entry point to a more
* standard main() entry point defined someplace else. In debug builds, also
* allocates a console and redirects stdin, stderr, stdout to that console.
*
* \remark The std* stream redirection is based on RedirectIOToConsole(), as can be found
* at http://dslweb.nwnexus.com/~ast/dload/guicon.htm.
*/
/* This only has to be compiled for WIN32 builds, others always use main() as entry point. */
#ifdef _WIN32
/* Update this bit as you see fit. */
#ifdef _DEBUG
# define ALLOC_CONSOLE
# define CONSOLE_LINES 0x200
#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
/* Only allocates console and redirects streams if this is defined. See above. */
#ifdef ALLOC_CONSOLE
#include <iostream>
#include <io.h>
#include <fcntl.h>
namespace
{
/* Stash away the old std* streams, so we can restore them later. */
FILE oldStdout = *stdout;
FILE oldStdin = *stdin;
FILE oldStderr = *stderr;
/** Redirects a std stream from its default output/input, to the console.
* \param[in] stdHandleId One of STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE.
* \param[in] stream Stream to redirect.
* \param[in] direction "r" for input streams, "w" for output streams. */
void redirectStream(DWORD stdHandleId, FILE* stream, const char* direction)
{
intptr_t stdHandle = reinterpret_cast<intptr_t>(::GetStdHandle(stdHandleId));
int fileHandle = _open_osfhandle(stdHandle, _O_TEXT);
FILE* fp = _fdopen(fileHandle, direction);
*stream = *fp;
setvbuf(stream, NULL, _IONBF, 0);
}
/** Allocates a console for this application, increases the buffer size, and redirects std* streams
* to this console. */
void prepareConsole()
{
::AllocConsole();
// increase the size of the screen buffer, so we can scroll text rather than have it dissappear on us
CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
HANDLE stdOutHandle = ::GetStdHandle(STD_OUTPUT_HANDLE);
::GetConsoleScreenBufferInfo(stdOutHandle, &consoleInfo);
consoleInfo.dwSize.Y = 500;
::SetConsoleScreenBufferSize(stdOutHandle, consoleInfo.dwSize);
// Redirect all the standard streams to the newly allocated console, and finally make sure the
// std::stream classes do as well
redirectStream(STD_OUTPUT_HANDLE, stdout, "w");
redirectStream(STD_ERROR_HANDLE, stderr, "w");
redirectStream(STD_INPUT_HANDLE, stdin, "r");
std::ios::sync_with_stdio();
}
/** Frees the allocated console and restores the std* streams to their default. */
void cleanupConsole()
{
::FreeConsole();
*stdout = oldStdout;
*stdin = oldStdin;
*stderr = oldStderr;
std::ios::sync_with_stdio();
}
}; // anon namespace
#endif // ALLOC_CONSOLE
/* External reference to the main() method to use as entry point. */
extern int main(int argc, char** argv);
/** Application entry point. Redirects the call from this function to the main() function defined
* elsewhere. If ALLOC_CONSOLE is defined, it will allocate a console before the call to main()
* and free it after the call has finished. */
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
#ifdef ALLOC_CONSOLE
prepareConsole();
#endif
int ret = main(__argc, __argv);
#ifdef ALLOC_CONSOLE
cleanupConsole();
#endif
return ret;
}
#endif // _WIN32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment