/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2014 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #include "xenia/base/main.h" #include #include #include #include // Autogenerated by `xb premake`. #include "build/version.h" #include "xenia/base/logging.h" #include "xenia/base/platform_win.h" #include "xenia/base/string.h" #include namespace xe { bool has_console_attached_ = true; bool has_console_attached() { return has_console_attached_; } void AttachConsole() { bool has_console = ::AttachConsole(ATTACH_PARENT_PROCESS) == TRUE; if (!has_console) { // We weren't launched from a console, so just return. // We could alloc our own console, but meh: // has_console = AllocConsole() == TRUE; has_console_attached_ = false; return; } has_console_attached_ = true; auto std_handle = (intptr_t)GetStdHandle(STD_OUTPUT_HANDLE); auto con_handle = _open_osfhandle(std_handle, _O_TEXT); auto fp = _fdopen(con_handle, "w"); *stdout = *fp; setvbuf(stdout, nullptr, _IONBF, 0); std_handle = (intptr_t)GetStdHandle(STD_ERROR_HANDLE); con_handle = _open_osfhandle(std_handle, _O_TEXT); fp = _fdopen(con_handle, "w"); *stderr = *fp; setvbuf(stderr, nullptr, _IONBF, 0); } static void RequestHighPerformance() { #if XE_PLATFORM_WIN32 NTSTATUS(*NtQueryTimerResolution) (OUT PULONG MinimumResolution, OUT PULONG MaximumResolution, OUT PULONG CurrentResolution); NTSTATUS(*NtSetTimerResolution) (IN ULONG DesiredResolution, IN BOOLEAN SetResolution, OUT PULONG CurrentResolution); NtQueryTimerResolution = (decltype(NtQueryTimerResolution))GetProcAddress( GetModuleHandle(L"ntdll.dll"), "NtQueryTimerResolution"); NtSetTimerResolution = (decltype(NtSetTimerResolution))GetProcAddress( GetModuleHandle(L"ntdll.dll"), "NtSetTimerResolution"); if (!NtQueryTimerResolution || !NtSetTimerResolution) { return; } ULONG minimum_resolution, maximum_resolution, current_resolution; NtQueryTimerResolution(&minimum_resolution, &maximum_resolution, ¤t_resolution); NtSetTimerResolution(minimum_resolution, TRUE, ¤t_resolution); #endif } int Main() { auto entry_info = xe::GetEntryInfo(); // Request high performance timing. RequestHighPerformance(); // Convert command line to an argv-like format so we can share code/use // gflags. auto command_line = GetCommandLineW(); int argc; wchar_t** argv = CommandLineToArgvW(command_line, &argc); if (!argv) { return 1; } google::SetUsageMessage(std::string("usage: ") + xe::to_string(entry_info.usage)); google::SetVersionString("1.0"); // Convert all args to narrow, as gflags doesn't support wchar. int argca = argc; char** argva = reinterpret_cast(alloca(sizeof(char*) * argca)); for (int n = 0; n < argca; n++) { size_t len = std::wcstombs(nullptr, argv[n], 0); argva[n] = reinterpret_cast(alloca(sizeof(char) * (len + 1))); std::wcstombs(argva[n], argv[n], len + 1); } // Parse flags; this may delete some of them. google::ParseCommandLineFlags(&argc, &argva, true); // Widen all remaining flags and convert to usable strings. std::vector args; for (int n = 0; n < argc; n++) { size_t len = std::mbstowcs(nullptr, argva[n], 0); auto argvw = reinterpret_cast(alloca(sizeof(wchar_t) * (len + 1))); std::mbstowcs(argvw, argva[n], len + 1); args.push_back(std::wstring(argvw)); } // Setup COM on the main thread. // NOTE: this may fail if COM has already been initialized - that's OK. CoInitializeEx(nullptr, COINIT_MULTITHREADED); // Initialize logging. Needs parsed FLAGS. xe::InitializeLogging(entry_info.name); // Print version info. XELOGI("Build: %s / %s on %s", XE_BUILD_BRANCH, XE_BUILD_COMMIT, XE_BUILD_DATE); // Call app-provided entry point. int result = entry_info.entry_point(args); xe::ShutdownLogging(); google::ShutDownCommandLineFlags(); LocalFree(argv); return result; } } // namespace xe // Used in console mode apps; automatically picked based on subsystem. int main(int argc_ignored, char** argv_ignored) { return xe::Main(); } // Used in windowed apps; automatically picked based on subsystem. int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR command_line, int) { // Attach a console so we can write output to stdout. If the user hasn't // redirected output themselves it'll pop up a window. xe::AttachConsole(); // Run normal entry point. return xe::Main(); } #if defined _M_IX86 #pragma comment( \ linker, \ "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") // NOLINT(whitespace/line_length) #elif defined _M_IA64 #pragma comment( \ linker, \ "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"") // NOLINT(whitespace/line_length) #elif defined _M_X64 #pragma comment( \ linker, \ "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") // NOLINT(whitespace/line_length) #else #pragma comment( \ linker, \ "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") // NOLINT(whitespace/line_length) #endif