/
main_win.cc
179 lines (145 loc) · 6.08 KB
/
main_win.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/**
******************************************************************************
* 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 <fcntl.h>
#include <gflags/gflags.h>
#include <io.h>
#include <cstdlib>
// 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 <bcrypt.h>
DEFINE_bool(win32_high_freq, true,
"Requests high performance from the NT kernel");
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(maximum_resolution, TRUE, ¤t_resolution);
#endif
}
int Main() {
auto entry_info = xe::GetEntryInfo();
// 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<char**>(alloca(sizeof(char*) * argca));
for (int n = 0; n < argca; n++) {
size_t len = std::wcstombs(nullptr, argv[n], 0);
argva[n] = reinterpret_cast<char*>(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<std::wstring> args;
for (int n = 0; n < argc; n++) {
size_t len = std::mbstowcs(nullptr, argva[n], 0);
auto argvw =
reinterpret_cast<wchar_t*>(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);
// Request high performance timing.
if (FLAGS_win32_high_freq) {
RequestHighPerformance();
}
// 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