-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathExeFileWin32.cpp
More file actions
284 lines (248 loc) · 7 KB
/
ExeFileWin32.cpp
File metadata and controls
284 lines (248 loc) · 7 KB
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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
// Copyright © 2026 CCP ehf.
#include "StdAfx.h"
#ifdef _WIN32
#include "ExeFile.h"
#include <CcpCrash.h>
#include <fcntl.h>
#include <Shlobj.h>
#include <VersionHelpers.h>
namespace
{
DWORD g_mainThreadId;
bool g_quit = false;
//Note, we might want to change this to produce always english
//messages...
std::string FmtError(DWORD err = 0)
{
DWORD olderr = GetLastError();
if (!err)
err = olderr;
LPVOID lpMsgBuf;
DWORD ok = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL );
if (!ok && GetLastError() == ERROR_RESOURCE_LANG_NOT_FOUND)
{
//try again using default language
ok = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
0,
(LPTSTR) &lpMsgBuf,
0,
NULL );
}
if (!ok)
{
SetLastError(olderr);
return "";
}
std::string r((LPTSTR)lpMsgBuf);
LocalFree( lpMsgBuf );
SetLastError(olderr);
return r;
}
void myInvalidParameterHandler(const wchar_t* expression,
const wchar_t* function,
const wchar_t* file,
unsigned int line,
uintptr_t pReserved)
{
CCP_LOGERR( "ExeFile CRT invalid parameter handler: %s:%d in %s",
file?(const char*)CW2A(file):"<none>", line, function?(const char*)CW2A(function):"<none>");
CCP_LOGERR( "Expression: %s", expression?(const char*)CW2A(expression):"<none>");
}
void __cdecl PureCallHandler()
{
CcpCrashOnPurpose();
// Crash the process instead of showing the default MS "pure virtual call" dialog
volatile int* crashPointer = nullptr;
*crashPointer = 42;
}
BOOL WINAPI OnConsoleCtrl(DWORD type)
{
// let's quit no matter the type
g_quit = true;
PostThreadMessage(g_mainThreadId, WM_QUIT, 0, 0);
return TRUE;
}
}
//--------------------------------------------------------------------
// ShowConsoleWindow
// ExeFile is a WindowsApplication. But we sometimes want a console,
// and in particular, we want to run the servers as regular console
// applications. This function attemts to emulate the services
// normally provided by the system when starting a "console" app.
// When CreateProcess starts a non-console application, it doesn't
// heed the CREATE_NEW_CONSOLE flag.
// And DETACHED_PROCESS doesn't prevent the process from attaching
// to the parent process... Therefore, to emulate a console app,
// one has to be reasonable.
//--------------------------------------------------------------------
void ShowConsoleWindow(ConsoleMode mode)
{
if( mode == console_mode_off )
{
// Completely bypassing any mucking around with IO handles.
// This tended to break Mac Remote Debugging.
return;
}
//first, look at those std handles that we want to keep. Allocating
//or attaching to a console will trample these handles that we were given
//by CreateProcess. C stdio has already been initialized to use these
//handles.
DWORD hKeys[] = {STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE};
HANDLE keep[3];
for( int i = 0; i<3; i++ )
{
//We detect those file redirection handles by our ability to set
//their inheritance flags. Console handles can't do that.
//(cmd.exe will pass on _its_ stdio handles, even if they are to
//a console, and they won't work for us).
HANDLE h = GetStdHandle(hKeys[i]);
if (h && SetHandleInformation(h, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
{
keep[i] = h;
}
else
{
keep[i] = 0;
}
}
//Now, Attach to or Create a console, depending on our mode.
BOOL console;
switch (mode)
{
case console_mode_off:
console = FALSE;
break;
case console_mode_inherit:
{
//dynamic loading of AttachConsole, which is supported only on XP and later
console = FALSE;
HMODULE h = GetModuleHandle("kernel32");
if( h )
{
typedef BOOL (__stdcall *at)(DWORD);
at ft = (at)GetProcAddress(h, "AttachConsole");
if( ft )
{
console = (*ft)(-1);
}
}
break;
}
case console_mode_create:
console = AllocConsole();
break;
}
if( console )
{
//if we want to keep any handles, reinstate those handles now,
//else, reopen stdio to the new handles from console alloc/attach
//(Maybe we should close those handles that we trample but lets
//not worry about that)
if( mode == console_mode_inherit )
{
for( int i = 0; i<3; ++i )
{
if( keep[i] )
{
SetStdHandle( hKeys[i], keep[i] );
}
}
}
//reopen stdio for those handles that we didn't want to keep from before
FILE *si, *so, *se;
if( mode == console_mode_create || !keep[0] )
{
freopen_s(&si, "CONIN$", "r", stdin);
}
if( mode == console_mode_create || !keep[1] )
{
freopen_s(&so, "CONOUT$", "w", stdout);
}
if( mode == console_mode_create || !keep[2] )
{
freopen_s(&se, "CONOUT$", "w", stderr);
}
}
if( mode != console_mode_off )
{
//We are pretending to be a console app
// Set the output channel of the CRT error handler to stderr
// This will prevent abort() and assert() from putting up a
// dialogue box. (default for win app is a dialog box)
_set_error_mode(_OUT_TO_STDERR);
// Change abort behaviour to not invoke DRWatson for a dump when
// abort() is called. Turn off the _CALL_REPORTFAULT flag.
_set_abort_behavior(0, _CALL_REPORTFAULT);
}
}
void PreStartupTest()
{
SetConsoleCtrlHandler( OnConsoleCtrl, TRUE );
if(!IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE))
{
MessageBox( NULL,
"SSE2 support is needed to run this game.\nClick \'OK\' to continue but the game will probably shut down.",
"SSE2 needed",
MB_ICONEXCLAMATION | MB_OK );
}
}
void SetProcessAffinity( int affinity )
{
int mask = affinity;
HANDLE me = GetCurrentProcess();
HMODULE kernel32 = LoadLibrary( "kernel32" );
typedef WINBASEAPI BOOL WINAPI maskfn( IN HANDLE process, IN DWORD_PTR mask );
maskfn* proc = (maskfn*)GetProcAddress( kernel32, "SetProcessAffinityMask" );
if( me && kernel32 && proc && proc( me, mask ) )
{
CCP_LOG( "Process affinity mask is %d", mask );
}
else
{
CCP_LOGERR(
"Cannot set affinity mask, mask=%d, me=%p, kernel32=%p, proc=%p, err=%d:\"%s\"",
mask, me, kernel32, proc, GetLastError(), FmtError().c_str()
);
}
if( kernel32 )
{
FreeLibrary( kernel32 );
}
}
bool IsSupportedOSVersion()
{
return IsWindows10OrGreater();
}
int APIENTRY WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
{
//NOTE! This is only local to Exefile as long as we don't use DLL RCT
_set_invalid_parameter_handler(myInvalidParameterHandler);
_set_purecall_handler( &PureCallHandler );
g_mainThreadId = GetCurrentThreadId();
CommandLine commandLine = ParseCommandLine();
int retcode = Main( commandLine, IsSupportedOSVersion() );
// If the game was launched from Media Center, find the window and restore
// (possibly the game wasn't launched from MCE even though it's running, in
// that case it's restored anyway)
HWND hwndMCE = FindWindow( _T("eHome Render Window"), NULL );
if( hwndMCE )
{
ShowWindow( hwndMCE, SW_RESTORE );
}
return retcode;
}
#endif