2
attachconsole.cpp - WINAPI AttachConsole
3
Copyright (C) 2009-2011 Pali Rohár <pali.rohar@gmail.com>
5
This program is free software: you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation, either version 2 of the License, or
8
(at your option) any later version.
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
15
You should have received a copy of the GNU General Public License
16
along with this program. If not, see <http://www.gnu.org/licenses/>.
20
#if ( defined(WIN32) || defined(_MSC_VER) ) && ( defined(NO_STDIO_REDIRECT) || ! defined(REDIRECT_OUTPUT) )
31
#ifndef _WIN32_WINNT_WIN2K
32
#define _WIN32_WINNT_WIN2K 0x0500
35
static int fixmode = 0;
37
static HINSTANCE lib_kernel32 = NULL;
38
static HINSTANCE lib_ntdll = NULL;
40
typedef int FAR WINAPI proto_AttachConsole(int);
41
typedef int FAR WINAPI proto_NtQueryObject(HANDLE, int, void *, unsigned long int, unsigned long int *);
43
static proto_AttachConsole *func_AttachConsole = NULL;
44
static proto_NtQueryObject *func_NtQueryObject = NULL;
46
/// Check if HANDLE is attached to console
47
static int WINAPI_CheckIfConsoleHandle(HANDLE handle)
50
wchar_t filename[MAX_PATH];
51
unsigned long int length = 0;
53
// Try to get filename of HANDLE
54
if (func_NtQueryObject) {
55
func_NtQueryObject(handle, 1, filename, MAX_PATH, &length);
58
// Filename start at position 8
67
/// Try to reopen FILE* from WINAPI HANDLE
68
static void WINAPI_ReopenFileFromHandle(HANDLE handle, FILE *file, const char *mode)
74
if (! handle || handle == INVALID_HANDLE_VALUE) {
78
// Get file descriptor from HANDLE
79
fd = _open_osfhandle((intptr_t)handle, O_TEXT);
85
// Get C structure FILE* from file descriptior
86
newfile = _fdopen(fd, mode);
95
// Set new file from HANDLE
98
setvbuf(file, NULL, _IONBF, 0);
100
// If stdout/stderr write 2 empty lines to cmd console
101
if (! fixmode && strcmp(mode, "w") == 0) {
103
fprintf(file, "\n\n");
110
/// Try to set std HANDLE from FILE*
111
static void WINAPI_SetStdHandleFromFile(int type, FILE *file)
123
handle = (HANDLE)_get_osfhandle(fd);
125
if (! handle || handle == INVALID_HANDLE_VALUE) {
129
SetStdHandle(type, handle);
133
/// Try attach console of parent process for std input/output in Windows NT, 2000, XP or new
134
static void WINAPI_AttachConsole(void)
145
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
146
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
148
hasVersion = GetVersionEx(&osvi);
154
version = (osvi.dwMajorVersion << 8) | osvi.dwMinorVersion;
156
// We need Windows 2000 or new
157
if (version < _WIN32_WINNT_WIN2K) {
161
lib_kernel32 = LoadLibrary("kernel32.dll");
163
if (! lib_kernel32) {
167
func_AttachConsole = (proto_AttachConsole *)GetProcAddress(lib_kernel32, "AttachConsole");
169
if (! func_AttachConsole) {
173
lib_ntdll = LoadLibrary("ntdll.dll");
176
func_NtQueryObject = (proto_NtQueryObject *)GetProcAddress(lib_ntdll, "NtQueryObject");
179
// Ignore if HANDLE is not attached console
180
reopen_stdin = WINAPI_CheckIfConsoleHandle(GetStdHandle(STD_INPUT_HANDLE));
181
reopen_stdout = WINAPI_CheckIfConsoleHandle(GetStdHandle(STD_OUTPUT_HANDLE));
182
reopen_stderr = WINAPI_CheckIfConsoleHandle(GetStdHandle(STD_ERROR_HANDLE));
184
attached = func_AttachConsole(-1);
191
WINAPI_ReopenFileFromHandle(GetStdHandle(STD_INPUT_HANDLE), stdin, "r");
193
WINAPI_SetStdHandleFromFile(STD_INPUT_HANDLE, stdin);
197
WINAPI_ReopenFileFromHandle(GetStdHandle(STD_OUTPUT_HANDLE), stdout, "w");
199
WINAPI_SetStdHandleFromFile(STD_OUTPUT_HANDLE, stdout);
203
WINAPI_ReopenFileFromHandle(GetStdHandle(STD_ERROR_HANDLE), stderr, "w");
205
WINAPI_SetStdHandleFromFile(STD_ERROR_HANDLE, stderr);
212
std::ios::sync_with_stdio();
217
/// This section set that WINAPI_AttachConsole() will be called at application startup before main()
219
#pragma section(".CRT$XCU", long, read)
220
__declspec(allocate(".CRT$XCU")) void (*initialize)(void) = WINAPI_AttachConsole;
222
__attribute__((constructor)) static void initialize(void) { WINAPI_AttachConsole(); }