246 lines
7.4 KiB
C++
246 lines
7.4 KiB
C++
#include <Windows.h>
|
|
#include <io.h>
|
|
#include <fcntl.h>
|
|
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <exception>
|
|
|
|
|
|
#include "Display.h"
|
|
|
|
|
|
void print_help()
|
|
{
|
|
std::cout
|
|
<< "UpdateDisplay" << std::endl
|
|
<< "=============" << std::endl
|
|
<< std::endl
|
|
<< "Usage: UpdateDisplay.exe <options...>" << 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;
|
|
}
|
|
} |