1+ #include " stdafx.h"
2+ #include < io.h>
3+ #include < fcntl.h>
4+ #include < iostream>
5+ #include < inttypes.h>
6+ #include " LuaMacros.h"
7+
8+ // / https://stackoverflow.com/a/25927081/5578773
9+ static void BindCrtHandlesToStdHandles (bool bindStdIn, bool bindStdOut, bool bindStdErr)
10+ {
11+ // Re-initialize the C runtime "FILE" handles with clean handles bound to "nul". We do this because it has been
12+ // observed that the file number of our standard handle file objects can be assigned internally to a value of -2
13+ // when not bound to a valid target, which represents some kind of unknown internal invalid state. In this state our
14+ // call to "_dup2" fails, as it specifically tests to ensure that the target file number isn't equal to this value
15+ // before allowing the operation to continue. We can resolve this issue by first "re-opening" the target files to
16+ // use the "nul" device, which will place them into a valid state, after which we can redirect them to our target
17+ // using the "_dup2" function.
18+ if (bindStdIn)
19+ {
20+ FILE* dummyFile;
21+ freopen_s (&dummyFile, " nul" , " r" , stdin);
22+ }
23+ if (bindStdOut)
24+ {
25+ FILE* dummyFile;
26+ freopen_s (&dummyFile, " nul" , " w" , stdout);
27+ }
28+ if (bindStdErr)
29+ {
30+ FILE* dummyFile;
31+ freopen_s (&dummyFile, " nul" , " w" , stderr);
32+ }
33+
34+ // Redirect unbuffered stdin from the current standard input handle
35+ if (bindStdIn)
36+ {
37+ HANDLE stdHandle = GetStdHandle (STD_INPUT_HANDLE);
38+ if (stdHandle != INVALID_HANDLE_VALUE)
39+ {
40+ int fileDescriptor = _open_osfhandle ((intptr_t )stdHandle, _O_TEXT);
41+ if (fileDescriptor != -1 )
42+ {
43+ FILE* file = _fdopen (fileDescriptor, " r" );
44+ if (file != NULL )
45+ {
46+ int dup2Result = _dup2 (_fileno (file), _fileno (stdin));
47+ if (dup2Result == 0 )
48+ {
49+ setvbuf (stdin, NULL , _IONBF, 0 );
50+ }
51+ }
52+ }
53+ }
54+ }
55+
56+ // Redirect unbuffered stdout to the current standard output handle
57+ if (bindStdOut)
58+ {
59+ HANDLE stdHandle = GetStdHandle (STD_OUTPUT_HANDLE);
60+ if (stdHandle != INVALID_HANDLE_VALUE)
61+ {
62+ int fileDescriptor = _open_osfhandle ((intptr_t )stdHandle, _O_TEXT);
63+ if (fileDescriptor != -1 )
64+ {
65+ FILE* file = _fdopen (fileDescriptor, " w" );
66+ if (file != NULL )
67+ {
68+ int dup2Result = _dup2 (_fileno (file), _fileno (stdout));
69+ if (dup2Result == 0 )
70+ {
71+ setvbuf (stdout, NULL , _IONBF, 0 );
72+ }
73+ }
74+ }
75+ }
76+ }
77+
78+ // Redirect unbuffered stderr to the current standard error handle
79+ if (bindStdErr)
80+ {
81+ HANDLE stdHandle = GetStdHandle (STD_ERROR_HANDLE);
82+ if (stdHandle != INVALID_HANDLE_VALUE)
83+ {
84+ int fileDescriptor = _open_osfhandle ((intptr_t )stdHandle, _O_TEXT);
85+ if (fileDescriptor != -1 )
86+ {
87+ FILE* file = _fdopen (fileDescriptor, " w" );
88+ if (file != NULL )
89+ {
90+ int dup2Result = _dup2 (_fileno (file), _fileno (stderr));
91+ if (dup2Result == 0 )
92+ {
93+ setvbuf (stderr, NULL , _IONBF, 0 );
94+ }
95+ }
96+ }
97+ }
98+ }
99+
100+ // Clear the error state for each of the C++ standard stream objects. We need to do this, as attempts to access the
101+ // standard streams before they refer to a valid target will cause the iostream objects to enter an error state. In
102+ // versions of Visual Studio after 2005, this seems to always occur during startup regardless of whether anything
103+ // has been read from or written to the targets or not.
104+ if (bindStdIn)
105+ {
106+ std::wcin.clear ();
107+ std::cin.clear ();
108+ }
109+ if (bindStdOut)
110+ {
111+ std::wcout.clear ();
112+ std::cout.clear ();
113+ }
114+ if (bindStdErr)
115+ {
116+ std::wcerr.clear ();
117+ std::cerr.clear ();
118+ }
119+ }
120+
121+ static HWND GetConsoleHwnd (void )
122+ {
123+ #define MY_BUFSIZE 1024 // Buffer size for console window titles.
124+ HWND hwndFound; // This is what is returned to the caller.
125+ wchar_t pszNewWindowTitle[MY_BUFSIZE]; // Contains fabricated
126+ // WindowTitle.
127+ wchar_t pszOldWindowTitle[MY_BUFSIZE]; // Contains original
128+ // WindowTitle.
129+
130+ // Fetch current window title.
131+
132+ GetConsoleTitle (pszOldWindowTitle, MY_BUFSIZE);
133+
134+ // Format a "unique" NewWindowTitle.
135+
136+ wsprintf (pszNewWindowTitle, L" %" PRIu64 L" /%d" , GetTickCount64 (), GetCurrentProcessId ());
137+
138+ // Change current window title.
139+
140+ SetConsoleTitle (pszNewWindowTitle);
141+
142+ // Ensure window title has been updated.
143+
144+ Sleep (40 );
145+
146+ // Look for NewWindowTitle.
147+
148+ hwndFound = FindWindow (NULL , pszNewWindowTitle);
149+
150+ // Restore original window title.
151+
152+ SetConsoleTitle (pszOldWindowTitle);
153+
154+ return (hwndFound);
155+ }
156+
157+ void init_console_window () {
158+ AllocConsole ();
159+ SetConsoleTitle (L" LuaMacros debug console" );
160+ LuaMacros::consoleWindow = GetConsoleHwnd ();
161+ BindCrtHandlesToStdHandles (true , true , true );
162+ #if !_DEBUG
163+ ShowWindow (LuaMacros::consoleWindow, SW_HIDE);
164+ #endif
165+ }
0 commit comments