1 | // LAF Base Library |
2 | // Copyright (c) 2021 Igara Studio S.A. |
3 | // Copyright (c) 2001-2016 David Capello |
4 | // |
5 | // This file is released under the terms of the MIT license. |
6 | // Read LICENSE.txt for more information. |
7 | |
8 | #ifdef HAVE_CONFIG_H |
9 | #include "config.h" |
10 | #endif |
11 | |
12 | #include "base/system_console.h" |
13 | |
14 | #ifdef LAF_WINDOWS |
15 | |
16 | // Windows needs some adjustments to the console if the process is |
17 | // linked with /subsystem:windows. These adjustments are not great but |
18 | // are good enough. See system_console.h for more information. |
19 | |
20 | #include <cstdio> |
21 | #include <iostream> |
22 | |
23 | #include <windows.h> |
24 | #include <io.h> |
25 | |
26 | namespace base { |
27 | |
28 | static bool withConsole = false; |
29 | |
30 | SystemConsole::SystemConsole() |
31 | { |
32 | // If some output handle (stdout/stderr) is not attached to a |
33 | // console, we can attach the process to the parent process console. |
34 | bool unknownOut = (::GetFileType(::GetStdHandle(STD_OUTPUT_HANDLE)) == FILE_TYPE_UNKNOWN); |
35 | bool unknownErr = (::GetFileType(::GetStdHandle(STD_ERROR_HANDLE)) == FILE_TYPE_UNKNOWN); |
36 | if (unknownOut || unknownErr) { |
37 | // AttachConsole() can fails if the parent console doesn't have a |
38 | // console, which is the most common, i.e. when the user |
39 | // double-click a shortcut to start the program. |
40 | if (::AttachConsole(ATTACH_PARENT_PROCESS)) { |
41 | // In this case we're attached to the parent process |
42 | // (e.g. cmd.exe) console. |
43 | withConsole = true; |
44 | } |
45 | } |
46 | |
47 | if (withConsole) { |
48 | // Here we redirect stdout/stderr to use the parent console's ones. |
49 | if (unknownOut) std::freopen("CONOUT$" , "w" , stdout); |
50 | if (unknownErr) std::freopen("CONOUT$" , "w" , stderr); |
51 | |
52 | // Synchronize C++'s cout/cerr streams with C's stdout/stderr. |
53 | std::ios::sync_with_stdio(); |
54 | } |
55 | } |
56 | |
57 | SystemConsole::~SystemConsole() |
58 | { |
59 | if (withConsole) { |
60 | ::FreeConsole(); |
61 | withConsole = false; |
62 | } |
63 | } |
64 | |
65 | void SystemConsole::prepareShell() |
66 | { |
67 | if (withConsole) |
68 | ::FreeConsole(); |
69 | |
70 | // In this case, for a better user experience, we create a new |
71 | // console so we can write text in a synchronized way with the |
72 | // console. (The parent console stdin is not reliable for |
73 | // interactive command input in the current state, without doing |
74 | // this the input from the cmd.exe would be executed by cmd.exe and |
75 | // by our app.) |
76 | withConsole = true; |
77 | ::AllocConsole(); |
78 | ::AttachConsole(::GetCurrentProcessId()); |
79 | |
80 | std::freopen("CONIN$" , "r" , stdin); |
81 | std::freopen("CONOUT$" , "w" , stdout); |
82 | std::freopen("CONOUT$" , "w" , stderr); |
83 | std::ios::sync_with_stdio(); |
84 | } |
85 | |
86 | } |
87 | |
88 | #else // On Unix-like systems the console works just fine |
89 | |
90 | namespace base { |
91 | |
92 | SystemConsole::SystemConsole() { } |
93 | SystemConsole::~SystemConsole() { } |
94 | void SystemConsole::prepareShell() { } |
95 | |
96 | } |
97 | |
98 | #endif |
99 | |