2323#include < version.h>
2424#include < memory>
2525#include < algorithm>
26+ #include < cassert>
27+
28+ #if __cplusplus >= 201703L
29+ #define MAYBE_UNUSED [[maybe_unused]]
30+ #else
31+ #define MAYBE_UNUSED
32+ #endif
2633
2734namespace {
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
2944 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 ;
3445
3546 // Report log IDs
3647 constexpr int LOG_ID_END = 1044 ;
3748 constexpr int LOG_ID_CONTINUE_EXCEPTION = 1045 ;
3849 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" );
3955
4056 class Utf8FileHooksGuard {
57+ private:
58+ bool m_released = false ;
59+
4160 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+ }
4483
4584 // Disable copy and move
4685 Utf8FileHooksGuard (const Utf8FileHooksGuard&) = delete ;
@@ -49,8 +88,17 @@ namespace {
4988 Utf8FileHooksGuard& operator =(Utf8FileHooksGuard&&) = delete ;
5089 };
5190
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) {
54102 return ;
55103 }
56104
@@ -61,7 +109,6 @@ namespace {
61109 safeCmdLine[cmdLineLen] = ' \0 ' ;
62110 }
63111
64-
65112 inline DWORD GetSafeProcessId () noexcept {
66113 try {
67114 return GetCurrentProcessId ();
@@ -71,67 +118,28 @@ namespace {
71118 }
72119 }
73120
74- bool PerformInitialization (const char * safeCmdLine) {
121+ CInstallManager* PerformEarlyInitialization (const char * safeCmdLine) {
75122 auto * pInstallManager = GetInstallManager ();
76123 if (!pInstallManager) {
77- return false ;
124+ return nullptr ;
78125 }
79126
80- // Configure install manager
127+ // Let install manager figure out what MTASA path to use
81128 pInstallManager->SetMTASAPathSource (safeCmdLine);
82129
83- // Initialize logging
130+ // Start logging.....now
84131 BeginEventLog ();
85132
86- // Start localization (non-critical, continue on failure)
133+ // Start localization if possible
87134 InitLocalization (false );
88135
89- // Handle installer commands
136+ // Handle commands from the installer
90137 HandleSpecialLaunchOptions ();
91138
92- // Ensure single instance
139+ // Check MTA is launched only once
93140 HandleDuplicateLaunching ();
94141
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;
135143 }
136144
137145 SString ContinueUpdateProcedure (CInstallManager* pInstallManager) {
@@ -148,13 +156,14 @@ namespace {
148156 }
149157 }
150158
159+ // Launch the game with exception handling
151160 int LaunchGameSafely (const SString& strCmdLine) {
152161 try {
153162 return LaunchGame (strCmdLine);
154163 }
155164 catch (...) {
156165 AddReportLog (LOG_ID_LAUNCH_EXCEPTION, " Exception in LaunchGame()" );
157- return ERROR_LAUNCH_EXCEPTION;
166+ return static_cast < int >( ERROR_LAUNCH_EXCEPTION) ;
158167 }
159168 }
160169}
@@ -171,64 +180,106 @@ namespace {
171180// (Which may then call it again as admin)
172181//
173182// /////////////////////////////////////////////////////////////
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)
176185{
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
178193 if (!hLauncherInstance) {
179- return ERROR_NULL_INSTANCE;
194+ return static_cast < int >( ERROR_NULL_INSTANCE) ;
180195 }
181196
197+ char safeCmdLine[MAX_CMD_LINE_LENGTH] = {0 };
198+ SafeCopyCommandLine (lpCmdLine, safeCmdLine, sizeof (safeCmdLine));
199+
182200 // RAII guard for UTF8 file hooks
183201 Utf8FileHooksGuard utf8Guard;
184202
185- // Run debug tests if in debug mode
186203 #if defined(MTA_DEBUG)
187204 SharedUtil_Tests ();
188205 #endif
189206
190- // Prepare safe command line buffer
191- char safeCmdLine[MAX_CMD_LINE_LENGTH] = {0 };
192- SafeCopyCommandLine (lpCmdLine, safeCmdLine, sizeof (safeCmdLine));
193-
194207 //
195- // Initialization Phase
208+ // Init
196209 //
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);
199216 }
200217
201- // Show initial splash screen
202- ShowSplash (hLauncherInstance);
218+ HINSTANCE hInstanceToUse = hLauncherInstance;
219+
220+ // Show logo
221+ ShowSplash (hInstanceToUse);
203222
204- //
205- // Update Phase
206- //
207- auto * pInstallManager = GetInstallManager ();
208- const SString strCmdLine = ContinueUpdateProcedure (pInstallManager);
223+ // Other init stuff
224+ ClearPendingBrowseToSolution ();
209225
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);
214267
215- //
216- // Launch Phase
217- //
218- const int iReturnCode = LaunchGameSafely (strCmdLine);
219-
220- // Post-launch monitoring
221268 PostRunWatchDogs (iReturnCode);
222269
223270 //
224- // Cleanup Phase
271+ // Quit
225272 //
273+
226274 HandleOnQuitCommand ();
275+
276+ // Maybe show help if trouble was encountered
227277 ProcessPendingBrowseToSolution ();
228278
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 ();
232281
282+ AddReportLog (LOG_ID_END, SString (" * End (0x%X)* pid:%d" , iReturnCode, currentPid));
283+
233284 return iReturnCode;
234- }
285+ }
0 commit comments