aboutsummaryrefslogtreecommitdiff
path: root/launcher/Application.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'launcher/Application.cpp')
-rw-r--r--launcher/Application.cpp132
1 files changed, 109 insertions, 23 deletions
diff --git a/launcher/Application.cpp b/launcher/Application.cpp
index aeea90f1..ff6864f5 100644
--- a/launcher/Application.cpp
+++ b/launcher/Application.cpp
@@ -135,13 +135,16 @@
#include "updater/MacSparkleUpdater.h"
#endif
-
#if defined Q_OS_WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
-#include <windows.h>
+#include <fcntl.h>
+#include <io.h>
#include <stdio.h>
+#include <windows.h>
+#include <iostream>
+
#endif
#define STRINGIFY(x) #x
@@ -168,32 +171,115 @@ void appDebugOutput(QtMsgType type, const QMessageLogContext &context, const QSt
fflush(stderr);
}
-}
+} // namespace
+
-Application::Application(int &argc, char **argv) : QApplication(argc, argv)
-{
#if defined Q_OS_WIN32
- // attach the parent console
- if(AttachConsole(ATTACH_PARENT_PROCESS))
- {
- // if attach succeeds, reopen and sync all the i/o
- if(freopen("CON", "w", stdout))
- {
- std::cout.sync_with_stdio();
+
+// taken from https://stackoverflow.com/a/25927081
+// getting a proper output to console with redirection support on windows is apearently hell
+void BindCrtHandlesToStdHandles(bool bindStdIn, bool bindStdOut, bool bindStdErr)
+{
+ // Re-initialize the C runtime "FILE" handles with clean handles bound to "nul". We do this because it has been
+ // observed that the file number of our standard handle file objects can be assigned internally to a value of -2
+ // when not bound to a valid target, which represents some kind of unknown internal invalid state. In this state our
+ // call to "_dup2" fails, as it specifically tests to ensure that the target file number isn't equal to this value
+ // before allowing the operation to continue. We can resolve this issue by first "re-opening" the target files to
+ // use the "nul" device, which will place them into a valid state, after which we can redirect them to our target
+ // using the "_dup2" function.
+ if (bindStdIn) {
+ FILE* dummyFile;
+ freopen_s(&dummyFile, "nul", "r", stdin);
+ }
+ if (bindStdOut) {
+ FILE* dummyFile;
+ freopen_s(&dummyFile, "nul", "w", stdout);
+ }
+ if (bindStdErr) {
+ FILE* dummyFile;
+ freopen_s(&dummyFile, "nul", "w", stderr);
+ }
+
+ // Redirect unbuffered stdin from the current standard input handle
+ if (bindStdIn) {
+ HANDLE stdHandle = GetStdHandle(STD_INPUT_HANDLE);
+ if (stdHandle != INVALID_HANDLE_VALUE) {
+ int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT);
+ if (fileDescriptor != -1) {
+ FILE* file = _fdopen(fileDescriptor, "r");
+ if (file != NULL) {
+ int dup2Result = _dup2(_fileno(file), _fileno(stdin));
+ if (dup2Result == 0) {
+ setvbuf(stdin, NULL, _IONBF, 0);
+ }
+ }
+ }
}
- if(freopen("CON", "w", stderr))
- {
- std::cerr.sync_with_stdio();
+ }
+
+ // Redirect unbuffered stdout to the current standard output handle
+ if (bindStdOut) {
+ HANDLE stdHandle = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (stdHandle != INVALID_HANDLE_VALUE) {
+ int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT);
+ if (fileDescriptor != -1) {
+ FILE* file = _fdopen(fileDescriptor, "w");
+ if (file != NULL) {
+ int dup2Result = _dup2(_fileno(file), _fileno(stdout));
+ if (dup2Result == 0) {
+ setvbuf(stdout, NULL, _IONBF, 0);
+ }
+ }
+ }
}
- if(freopen("CON", "r", stdin))
- {
- std::cin.sync_with_stdio();
+ }
+
+ // Redirect unbuffered stderr to the current standard error handle
+ if (bindStdErr) {
+ HANDLE stdHandle = GetStdHandle(STD_ERROR_HANDLE);
+ if (stdHandle != INVALID_HANDLE_VALUE) {
+ int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT);
+ if (fileDescriptor != -1) {
+ FILE* file = _fdopen(fileDescriptor, "w");
+ if (file != NULL) {
+ int dup2Result = _dup2(_fileno(file), _fileno(stderr));
+ if (dup2Result == 0) {
+ setvbuf(stderr, NULL, _IONBF, 0);
+ }
+ }
+ }
+ }
+ }
+
+ // Clear the error state for each of the C++ standard stream objects. We need to do this, as attempts to access the
+ // standard streams before they refer to a valid target will cause the iostream objects to enter an error state. In
+ // versions of Visual Studio after 2005, this seems to always occur during startup regardless of whether anything
+ // has been read from or written to the targets or not.
+ if (bindStdIn) {
+ std::wcin.clear();
+ std::cin.clear();
+ }
+ if (bindStdOut) {
+ std::wcout.clear();
+ std::cout.clear();
+ }
+ if (bindStdErr) {
+ std::wcerr.clear();
+ std::cerr.clear();
+ }
+}
+#endif
+
+Application::Application(int& argc, char** argv) : QApplication(argc, argv)
+{
+#if defined Q_OS_WIN32
+ // attach the parent console if stdout not already captured
+ auto stdout_type = GetFileType(GetStdHandle(STD_OUTPUT_HANDLE));
+ if (stdout_type == FILE_TYPE_CHAR || stdout_type == FILE_TYPE_UNKNOWN) {
+ if (AttachConsole(ATTACH_PARENT_PROCESS)) {
+ BindCrtHandlesToStdHandles(true, true, true);
+ consoleAttached = true;
}
- auto out = GetStdHandle (STD_OUTPUT_HANDLE);
- DWORD written;
- const char * endline = "\n";
- WriteConsole(out, endline, strlen(endline), &written, NULL);
- consoleAttached = true;
}
#endif
setOrganizationName(BuildConfig.LAUNCHER_NAME);