~amdmi3/stratagus/cxx11-narrowing

« back to all changes in this revision

Viewing changes to src/win32/attachconsole.cpp

  • Committer: Pali Rohár
  • Date: 2015-04-12 09:54:50 UTC
  • Revision ID: pali.rohar@gmail.com-20150412095450-2opu93bilibdmk1l
Add new version of WINAPI code for attaching console

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
    attachconsole.cpp - WINAPI AttachConsole
3
 
    Copyright (C) 2009-2011  Pali Rohár <pali.rohar@gmail.com>
4
 
 
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.
9
 
 
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.
14
 
 
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/>.
17
 
 
18
 
*/
19
 
 
20
 
#if ( defined(WIN32) || defined(_MSC_VER) ) && ( defined(NO_STDIO_REDIRECT) || ! defined(REDIRECT_OUTPUT) )
21
 
 
22
 
#include <windows.h>
23
 
#include <io.h>
24
 
#include <fcntl.h>
25
 
#include <stdio.h>
26
 
 
27
 
#ifdef __cplusplus
28
 
#include <iostream>
29
 
#endif
30
 
 
31
 
#ifndef _WIN32_WINNT_WIN2K
32
 
#define _WIN32_WINNT_WIN2K 0x0500
33
 
#endif
34
 
 
35
 
static int fixmode = 0;
36
 
 
37
 
static HINSTANCE lib_kernel32 = NULL;
38
 
static HINSTANCE lib_ntdll = NULL;
39
 
 
40
 
typedef int FAR WINAPI proto_AttachConsole(int);
41
 
typedef int FAR WINAPI proto_NtQueryObject(HANDLE, int, void *, unsigned long int, unsigned long int *);
42
 
 
43
 
static proto_AttachConsole *func_AttachConsole = NULL;
44
 
static proto_NtQueryObject *func_NtQueryObject = NULL;
45
 
 
46
 
/// Check if HANDLE is attached to console
47
 
static int WINAPI_CheckIfConsoleHandle(HANDLE handle)
48
 
{
49
 
 
50
 
        wchar_t filename[MAX_PATH];
51
 
        unsigned long int length = 0;
52
 
 
53
 
        // Try to get filename of HANDLE
54
 
        if (func_NtQueryObject) {
55
 
                func_NtQueryObject(handle, 1, filename, MAX_PATH, &length);
56
 
        }
57
 
 
58
 
        // Filename start at position 8
59
 
        if (length > 8) {
60
 
                return 0;
61
 
        } else {
62
 
                return 1;
63
 
        }
64
 
 
65
 
}
66
 
 
67
 
/// Try to reopen FILE* from WINAPI HANDLE
68
 
static void WINAPI_ReopenFileFromHandle(HANDLE handle, FILE *file, const char *mode)
69
 
{
70
 
 
71
 
        int fd;
72
 
        FILE *newfile;
73
 
 
74
 
        if (! handle || handle == INVALID_HANDLE_VALUE) {
75
 
                return;
76
 
        }
77
 
 
78
 
        // Get file descriptor from HANDLE
79
 
        fd = _open_osfhandle((intptr_t)handle, O_TEXT);
80
 
 
81
 
        if (fd < 0) {
82
 
                return;
83
 
        }
84
 
 
85
 
        // Get C structure FILE* from file descriptior
86
 
        newfile = _fdopen(fd, mode);
87
 
 
88
 
        if (! newfile) {
89
 
                return;
90
 
        }
91
 
 
92
 
        // Close current file
93
 
        fclose(file);
94
 
 
95
 
        // Set new file from HANDLE
96
 
        *file = *newfile;
97
 
 
98
 
        setvbuf(file, NULL, _IONBF, 0);
99
 
 
100
 
        // If stdout/stderr write 2 empty lines to cmd console
101
 
        if (! fixmode && strcmp(mode, "w") == 0) {
102
 
 
103
 
                fprintf(file, "\n\n");
104
 
                fixmode = 1;
105
 
 
106
 
        }
107
 
 
108
 
}
109
 
 
110
 
/// Try to set std HANDLE from FILE*
111
 
static void WINAPI_SetStdHandleFromFile(int type, FILE *file)
112
 
{
113
 
 
114
 
        int fd;
115
 
        HANDLE handle;
116
 
 
117
 
        fd = _fileno(file);
118
 
 
119
 
        if (fd < 0) {
120
 
                return;
121
 
        }
122
 
 
123
 
        handle = (HANDLE)_get_osfhandle(fd);
124
 
 
125
 
        if (! handle || handle == INVALID_HANDLE_VALUE) {
126
 
                return;
127
 
        }
128
 
 
129
 
        SetStdHandle(type, handle);
130
 
 
131
 
}
132
 
 
133
 
/// Try attach console of parent process for std input/output in Windows NT, 2000, XP or new
134
 
static void WINAPI_AttachConsole(void)
135
 
{
136
 
 
137
 
        OSVERSIONINFO osvi;
138
 
        int hasVersion;
139
 
        int version;
140
 
        int attached;
141
 
        int reopen_stdin;
142
 
        int reopen_stdout;
143
 
        int reopen_stderr;
144
 
 
145
 
        ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
146
 
        osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
147
 
 
148
 
        hasVersion = GetVersionEx(&osvi);
149
 
 
150
 
        if (! hasVersion) {
151
 
                return;
152
 
        }
153
 
 
154
 
        version = (osvi.dwMajorVersion << 8) | osvi.dwMinorVersion;
155
 
 
156
 
        // We need Windows 2000 or new
157
 
        if (version < _WIN32_WINNT_WIN2K) {
158
 
                return;
159
 
        }
160
 
 
161
 
        lib_kernel32 = LoadLibrary("kernel32.dll");
162
 
 
163
 
        if (! lib_kernel32) {
164
 
                return;
165
 
        }
166
 
 
167
 
        func_AttachConsole = (proto_AttachConsole *)GetProcAddress(lib_kernel32, "AttachConsole");
168
 
 
169
 
        if (! func_AttachConsole) {
170
 
                return;
171
 
        }
172
 
 
173
 
        lib_ntdll = LoadLibrary("ntdll.dll");
174
 
 
175
 
        if (lib_ntdll) {
176
 
                func_NtQueryObject = (proto_NtQueryObject *)GetProcAddress(lib_ntdll, "NtQueryObject");
177
 
        }
178
 
 
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));
183
 
 
184
 
        attached = func_AttachConsole(-1);
185
 
 
186
 
        if (! attached) {
187
 
                return;
188
 
        }
189
 
 
190
 
        if (reopen_stdin) {
191
 
                WINAPI_ReopenFileFromHandle(GetStdHandle(STD_INPUT_HANDLE), stdin, "r");
192
 
        } else {
193
 
                WINAPI_SetStdHandleFromFile(STD_INPUT_HANDLE, stdin);
194
 
        }
195
 
 
196
 
        if (reopen_stdout) {
197
 
                WINAPI_ReopenFileFromHandle(GetStdHandle(STD_OUTPUT_HANDLE), stdout, "w");
198
 
        } else {
199
 
                WINAPI_SetStdHandleFromFile(STD_OUTPUT_HANDLE, stdout);
200
 
        }
201
 
 
202
 
        if (reopen_stderr) {
203
 
                WINAPI_ReopenFileFromHandle(GetStdHandle(STD_ERROR_HANDLE), stderr, "w");
204
 
        } else {
205
 
                WINAPI_SetStdHandleFromFile(STD_ERROR_HANDLE, stderr);
206
 
        }
207
 
 
208
 
#ifdef __cplusplus
209
 
        std::cin.clear();
210
 
        std::cout.clear();
211
 
        std::cerr.clear();
212
 
        std::ios::sync_with_stdio();
213
 
#endif
214
 
 
215
 
}
216
 
 
217
 
/// This section set that WINAPI_AttachConsole() will be called at application startup before main()
218
 
#ifdef _MSC_VER
219
 
#pragma section(".CRT$XCU", long, read)
220
 
__declspec(allocate(".CRT$XCU")) void (*initialize)(void) = WINAPI_AttachConsole;
221
 
#else
222
 
__attribute__((constructor)) static void initialize(void) { WINAPI_AttachConsole(); }
223
 
#endif
224
 
 
225
 
#endif