#include #include #include #include #include #include #include "Display.h" void print_help() { std::cout << "UpdateDisplay" << std::endl << "=============" << std::endl << std::endl << "Usage: UpdateDisplay.exe " << std::endl << std::endl << "By default the program will refresh display settings." << std::endl << std::endl << "Possible options:" << std::endl << std::endl << "--rotate" << "\t - Rotates Display" << std::endl << "\t0" << "\t - Landscape" << std::endl << "\t90" << "\t - Prtrait" << std::endl << "\t180" << "\t - Flippd Landscape" << std::endl << "\t270" << "\t - Flippd Prtrait" << std::endl << std::endl; } void main(int argc, char** argv) { if (argc == 1) return print_help(); Display dis; char** arg = argv; arg++; for (int i = 1; i < argc; i++, arg++) { std::string a(*arg); if (a == "--help") print_help(); else if (a == "--rotate") { i++; arg++; if (i == argc) throw std::exception("Argumment to --rotate not specified"); a = std::string(*arg); if (a == "0") dis.rotate(Display::Rotation::ROTATE_0); else if (a == "90") dis.rotate(Display::Rotation::ROTATE_90); else if (a == "180") dis.rotate(Display::Rotation::ROTATE_180); else if (a == "270") dis.rotate(Display::Rotation::ROTATE_270); else throw std::exception(("Unknown rotation: "+a).c_str()); } } dis.apply(); } // Taken from https://stackoverflow.com/a/74999569 static void get_command_line_args(int* argc, char*** argv) { // Get the command line arguments as wchar_t strings wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), argc); if (!wargv) { *argc = 0; *argv = NULL; return; } // Count the number of bytes necessary to store the UTF-8 versions of those strings int n = 0; for (int i = 0; i < *argc; i++) n += WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, NULL, 0, NULL, NULL) + 1; // Allocate the argv[] array + all the UTF-8 strings *argv = (char**)malloc((*argc + 1) * sizeof(char*) + n); if (!*argv) { *argc = 0; return; } // Convert all wargv[] --> argv[] char* arg = (char*)&((*argv)[*argc + 1]); for (int i = 0; i < *argc; i++) { (*argv)[i] = arg; arg += WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, arg, n, NULL, NULL) + 1; } (*argv)[*argc] = NULL; } // Source - https://stackoverflow.com/a // Posted by Roger Sanders, modified by community. See post 'Timeline' for change history // Retrieved 2025-12-13, License - CC BY-SA 3.0 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); } } } } } // 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); } } } } } // 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(); } } int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, PSTR cmdline, int cmdshow) { if (AttachConsole(ATTACH_PARENT_PROCESS)) BindCrtHandlesToStdHandles(true, true, true); int argc = 0; char** argv = nullptr; try { get_command_line_args(&argc, &argv); main(argc, argv); if (argv) free(argv); return EXIT_SUCCESS; } catch (std::exception& ex) { if (argv) free(argv); MessageBoxA(nullptr, ex.what(), "UpdateDisplay error", MB_ICONERROR); return EXIT_FAILURE; } }