23
23
#include < version.h>
24
24
#include < memory>
25
25
#include < algorithm>
26
+ #include < cassert>
27
+
28
+ #if __cplusplus >= 201703L
29
+ #define MAYBE_UNUSED [[maybe_unused]]
30
+ #else
31
+ #define MAYBE_UNUSED
32
+ #endif
26
33
27
34
namespace {
28
- // Constants
35
+ // Error codes enum for better maintainability
36
+ enum ErrorCode : int {
37
+ ERROR_NULL_INSTANCE = -1 ,
38
+ ERROR_NULL_INSTALL_MANAGER = -2 ,
39
+ ERROR_LAUNCH_EXCEPTION = -3 ,
40
+ ERROR_INSTALL_CONTINUE = -4
41
+ };
42
+
43
+ // Command line constants
29
44
constexpr size_t MAX_CMD_LINE_LENGTH = 4096 ;
30
- constexpr int ERROR_NULL_INSTANCE = -1 ;
31
- constexpr int ERROR_NULL_INSTALL_MANAGER = -2 ;
32
- constexpr int ERROR_LAUNCH_EXCEPTION = -3 ;
33
- constexpr int ERROR_INSTALL_CONTINUE = -4 ;
34
45
35
46
// Report log IDs
36
47
constexpr int LOG_ID_END = 1044 ;
37
48
constexpr int LOG_ID_CONTINUE_EXCEPTION = 1045 ;
38
49
constexpr int LOG_ID_LAUNCH_EXCEPTION = 1046 ;
50
+
51
+ // Compile-time checks
52
+ static_assert (MAX_CMD_LINE_LENGTH > 0 , " Command line buffer size must be positive" );
53
+ static_assert (MAX_CMD_LINE_LENGTH <= 65536 , " Command line buffer size seems unreasonably large" );
54
+ static_assert (sizeof (DWORD) >= sizeof (int ), " DWORD must be at least as large as int" );
39
55
40
56
class Utf8FileHooksGuard {
57
+ private:
58
+ bool m_released = false ;
59
+
41
60
public:
42
- Utf8FileHooksGuard () { AddUtf8FileHooks (); }
43
- ~Utf8FileHooksGuard () { RemoveUtf8FileHooks (); }
61
+ Utf8FileHooksGuard () {
62
+ AddUtf8FileHooks ();
63
+ }
64
+
65
+ ~Utf8FileHooksGuard () noexcept {
66
+ if (!m_released) {
67
+ RemoveUtf8FileHooks ();
68
+ }
69
+ }
70
+
71
+ // Called when we want to keep hooks active (early return with error)
72
+ void release () noexcept {
73
+ m_released = true ;
74
+ }
75
+
76
+ // Called when we want to remove hooks early (on GetInstallManager failure)
77
+ void removeNow () noexcept {
78
+ if (!m_released) {
79
+ RemoveUtf8FileHooks ();
80
+ m_released = true ;
81
+ }
82
+ }
44
83
45
84
// Disable copy and move
46
85
Utf8FileHooksGuard (const Utf8FileHooksGuard&) = delete ;
@@ -49,8 +88,17 @@ namespace {
49
88
Utf8FileHooksGuard& operator =(Utf8FileHooksGuard&&) = delete ;
50
89
};
51
90
52
- inline void SafeCopyCommandLine (LPSTR lpCmdLine, char * safeCmdLine, size_t bufferSize) {
53
- if (!lpCmdLine || !safeCmdLine || bufferSize == 0 ) {
91
+ inline void SafeCopyCommandLine (LPSTR lpCmdLine, char * safeCmdLine, size_t bufferSize) noexcept {
92
+ // Preconditions (only in debug builds)
93
+ assert (safeCmdLine != nullptr && " Destination buffer must not be null" );
94
+ assert (bufferSize > 0 && " Buffer size must be positive" );
95
+
96
+ if (!safeCmdLine || bufferSize == 0 ) {
97
+ return ;
98
+ }
99
+
100
+ // If source is null, destination remains zero-initialized
101
+ if (!lpCmdLine) {
54
102
return ;
55
103
}
56
104
@@ -61,7 +109,6 @@ namespace {
61
109
safeCmdLine[cmdLineLen] = ' \0 ' ;
62
110
}
63
111
64
-
65
112
inline DWORD GetSafeProcessId () noexcept {
66
113
try {
67
114
return GetCurrentProcessId ();
@@ -71,67 +118,28 @@ namespace {
71
118
}
72
119
}
73
120
74
- bool PerformInitialization (const char * safeCmdLine) {
121
+ CInstallManager* PerformEarlyInitialization (const char * safeCmdLine) {
75
122
auto * pInstallManager = GetInstallManager ();
76
123
if (!pInstallManager) {
77
- return false ;
124
+ return nullptr ;
78
125
}
79
126
80
- // Configure install manager
127
+ // Let install manager figure out what MTASA path to use
81
128
pInstallManager->SetMTASAPathSource (safeCmdLine);
82
129
83
- // Initialize logging
130
+ // Start logging.....now
84
131
BeginEventLog ();
85
132
86
- // Start localization (non-critical, continue on failure)
133
+ // Start localization if possible
87
134
InitLocalization (false );
88
135
89
- // Handle installer commands
136
+ // Handle commands from the installer
90
137
HandleSpecialLaunchOptions ();
91
138
92
- // Ensure single instance
139
+ // Check MTA is launched only once
93
140
HandleDuplicateLaunching ();
94
141
95
- // Clear any pending operations
96
- ClearPendingBrowseToSolution ();
97
-
98
- // Validate GTA installation
99
- ValidateGTAPath ();
100
-
101
- return true ;
102
- }
103
-
104
- void PerformPreLaunchSetup (HINSTANCE hInstance) {
105
- // Ensure localization is fully initialized
106
- InitLocalization (true );
107
-
108
- // Initialize monitoring systems
109
- PreLaunchWatchDogs ();
110
-
111
- // Handle custom configurations
112
- HandleCustomStartMessage ();
113
-
114
- #if !defined(MTA_DEBUG) && MTASA_VERSION_TYPE != VERSION_TYPE_CUSTOM
115
- ForbodenProgramsMessage ();
116
- #endif
117
-
118
- // Maintenance operations
119
- CycleEventLog ();
120
- BsodDetectionPreLaunch ();
121
- MaybeShowCopySettingsDialog ();
122
-
123
- // Check for conflicts
124
- HandleIfGTAIsAlreadyRunning ();
125
-
126
- // Maybe warn user if no anti-virus running
127
- CheckAntiVirusStatus ();
128
-
129
- // Show splash screen
130
- ShowSplash (hInstance);
131
-
132
- // Verify integrity
133
- CheckDataFiles ();
134
- CheckLibVersions ();
142
+ return pInstallManager;
135
143
}
136
144
137
145
SString ContinueUpdateProcedure (CInstallManager* pInstallManager) {
@@ -148,13 +156,14 @@ namespace {
148
156
}
149
157
}
150
158
159
+ // Launch the game with exception handling
151
160
int LaunchGameSafely (const SString& strCmdLine) {
152
161
try {
153
162
return LaunchGame (strCmdLine);
154
163
}
155
164
catch (...) {
156
165
AddReportLog (LOG_ID_LAUNCH_EXCEPTION, " Exception in LaunchGame()" );
157
- return ERROR_LAUNCH_EXCEPTION;
166
+ return static_cast < int >( ERROR_LAUNCH_EXCEPTION) ;
158
167
}
159
168
}
160
169
}
@@ -171,64 +180,106 @@ namespace {
171
180
// (Which may then call it again as admin)
172
181
//
173
182
// /////////////////////////////////////////////////////////////
174
- MTAEXPORT int DoWinMain (HINSTANCE hLauncherInstance, HINSTANCE hPrevInstance,
175
- LPSTR lpCmdLine, int nCmdShow)
183
+ MTAEXPORT int DoWinMain (HINSTANCE hLauncherInstance, MAYBE_UNUSED HINSTANCE hPrevInstance,
184
+ LPSTR lpCmdLine, MAYBE_UNUSED int nCmdShow)
176
185
{
177
- // Validate critical parameters
186
+ // Silence unused parameter warnings for older compilers
187
+ #if __cplusplus < 201703L
188
+ (void )hPrevInstance;
189
+ (void )nCmdShow;
190
+ #endif
191
+
192
+ // Check for null parameters before use
178
193
if (!hLauncherInstance) {
179
- return ERROR_NULL_INSTANCE;
194
+ return static_cast < int >( ERROR_NULL_INSTANCE) ;
180
195
}
181
196
197
+ char safeCmdLine[MAX_CMD_LINE_LENGTH] = {0 };
198
+ SafeCopyCommandLine (lpCmdLine, safeCmdLine, sizeof (safeCmdLine));
199
+
182
200
// RAII guard for UTF8 file hooks
183
201
Utf8FileHooksGuard utf8Guard;
184
202
185
- // Run debug tests if in debug mode
186
203
#if defined(MTA_DEBUG)
187
204
SharedUtil_Tests ();
188
205
#endif
189
206
190
- // Prepare safe command line buffer
191
- char safeCmdLine[MAX_CMD_LINE_LENGTH] = {0 };
192
- SafeCopyCommandLine (lpCmdLine, safeCmdLine, sizeof (safeCmdLine));
193
-
194
207
//
195
- // Initialization Phase
208
+ // Init
196
209
//
197
- if (!PerformInitialization (safeCmdLine)) {
198
- return ERROR_NULL_INSTALL_MANAGER;
210
+
211
+ auto * pInstallManager = PerformEarlyInitialization (safeCmdLine);
212
+ if (!pInstallManager) {
213
+ // Remove hooks when install manager fails
214
+ utf8Guard.removeNow ();
215
+ return static_cast <int >(ERROR_NULL_INSTALL_MANAGER);
199
216
}
200
217
201
- // Show initial splash screen
202
- ShowSplash (hLauncherInstance);
218
+ HINSTANCE hInstanceToUse = hLauncherInstance;
219
+
220
+ // Show logo
221
+ ShowSplash (hInstanceToUse);
203
222
204
- //
205
- // Update Phase
206
- //
207
- auto * pInstallManager = GetInstallManager ();
208
- const SString strCmdLine = ContinueUpdateProcedure (pInstallManager);
223
+ // Other init stuff
224
+ ClearPendingBrowseToSolution ();
209
225
210
- //
211
- // Pre-Launch Phase
212
- //
213
- PerformPreLaunchSetup (hLauncherInstance);
226
+ // Find GTA path to use
227
+ ValidateGTAPath ();
228
+
229
+
230
+ // Continue any update procedure
231
+ SString strCmdLine = ContinueUpdateProcedure (pInstallManager);
232
+
233
+ // Ensure localization is started
234
+ InitLocalization (true );
235
+
236
+ // Setup/test various counters and flags for monitoring problems
237
+ PreLaunchWatchDogs ();
238
+
239
+ // Stuff
240
+ HandleCustomStartMessage ();
241
+
242
+ #if !defined(MTA_DEBUG) && MTASA_VERSION_TYPE != VERSION_TYPE_CUSTOM
243
+ ForbodenProgramsMessage ();
244
+ #endif
245
+
246
+ CycleEventLog ();
247
+ BsodDetectionPreLaunch ();
248
+ MaybeShowCopySettingsDialog ();
249
+
250
+ // Make sure GTA is not running
251
+ HandleIfGTAIsAlreadyRunning ();
252
+
253
+ // Maybe warn user if no anti-virus running
254
+ CheckAntiVirusStatus ();
255
+
256
+ // Ensure logo is showing
257
+ ShowSplash (hInstanceToUse);
258
+
259
+ // Check MTA files look good
260
+ CheckDataFiles ();
261
+ CheckLibVersions ();
262
+
263
+ // Go for launch
264
+ // Initialize return code with safe default
265
+ int iReturnCode = 0 ;
266
+ iReturnCode = LaunchGameSafely (strCmdLine);
214
267
215
- //
216
- // Launch Phase
217
- //
218
- const int iReturnCode = LaunchGameSafely (strCmdLine);
219
-
220
- // Post-launch monitoring
221
268
PostRunWatchDogs (iReturnCode);
222
269
223
270
//
224
- // Cleanup Phase
271
+ // Quit
225
272
//
273
+
226
274
HandleOnQuitCommand ();
275
+
276
+ // Maybe show help if trouble was encountered
227
277
ProcessPendingBrowseToSolution ();
228
278
229
- // Log termination details
230
- const DWORD currentPid = GetSafeProcessId ();
231
- AddReportLog (LOG_ID_END, SString (" * End (0x%X)* pid:%d" , iReturnCode, currentPid));
279
+ // Get current process ID for logging
280
+ DWORD currentPid = GetSafeProcessId ();
232
281
282
+ AddReportLog (LOG_ID_END, SString (" * End (0x%X)* pid:%d" , iReturnCode, currentPid));
283
+
233
284
return iReturnCode;
234
- }
285
+ }
0 commit comments