Skip to content

Commit b08948f

Browse files
committed
Allow multiple instances of MTA/GTA
1 parent 64fd352 commit b08948f

File tree

7 files changed

+43
-250
lines changed

7 files changed

+43
-250
lines changed

Client/core/CCore.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -834,12 +834,27 @@ void CCore::ApplyHooks()
834834

835835
// Create our hooks.
836836
m_pDirectInputHookManager->ApplyHook();
837-
// m_pDirect3DHookManager->ApplyHook ( );
838837
m_pSetCursorPosHook->ApplyHook();
839838

840839
// Remove useless DirectPlay dependency (dpnhpast.dll) @ 0x745701
841840
// We have to patch here as multiplayer_sa and game_sa are loaded too late
842841
DetourLibraryFunction("kernel32.dll", "LoadLibraryA", Win32LoadLibraryA, SkipDirectPlay_LoadLibraryA);
842+
843+
// Disable code that disallows multiple instances of GTA:SA
844+
// Disable `if (IsAppAlreadyRunning())` in WinMain
845+
{
846+
DWORD oldProtect;
847+
VirtualProtect(reinterpret_cast<void*>(0x74872D), 9, PAGE_READWRITE, &oldProtect);
848+
memcpy(reinterpret_cast<void*>(0x74872D), "\x90\x90\x90\x90\x90\x90\x90\x90\x90", 9);
849+
VirtualProtect(reinterpret_cast<void*>(0x74872D), 9, oldProtect, &oldProtect);
850+
}
851+
// Create an unnamed semaphore in CdStreamInitThread.
852+
{
853+
DWORD oldProtect;
854+
VirtualProtect(reinterpret_cast<void*>(0x406945), 5, PAGE_READWRITE, &oldProtect);
855+
memcpy(reinterpret_cast<void*>(0x406945), "\x6A\x00\x90\x90\x90", 5);
856+
VirtualProtect(reinterpret_cast<void*>(0x406945), 5, oldProtect, &oldProtect);
857+
}
843858
}
844859

845860
bool UsingAltD3DSetup()

Client/loader/CInstallManager.cpp

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -361,17 +361,14 @@ SString CInstallManager::_ChangeToAdmin()
361361
NULL, SString(_("MTA:SA needs Administrator access for the following task:\n\n '%s'\n\nPlease confirm in the next window."), *m_strAdminReason),
362362
"Multi Theft Auto: San Andreas", MB_OK | MB_ICONINFORMATION | MB_TOPMOST);
363363
SetIsBlockingUserProcess();
364-
ReleaseSingleInstanceMutex();
365364
if (ShellExecuteBlocking("runas", GetLauncherPathFilename(), GetSequencerSnapshot()))
366365
{
367366
// Will return here once admin process has finished
368-
CreateSingleInstanceMutex();
369367
UpdateSettingsForReportLog();
370368
RestoreSequencerFromSnapshot(ReceiveStringFromAdminProcess());
371369
ClearIsBlockingUserProcess();
372370
return "ok"; // This will appear as the result for _ChangeFromAdmin
373371
}
374-
CreateSingleInstanceMutex();
375372
ClearIsBlockingUserProcess();
376373
MessageBoxUTF8(NULL, SString(_("MTA:SA could not complete the following task:\n\n '%s'\n"), *m_strAdminReason),
377374
"Multi Theft Auto: San Andreas" + _E("CL01"), MB_OK | MB_ICONWARNING | MB_TOPMOST);
@@ -478,10 +475,9 @@ SString CInstallManager::_MaybeSwitchToTempExe()
478475
// If a new "Multi Theft Auto.exe" exists, let that complete the install
479476
if (m_pSequencer->GetVariable(INSTALL_LOCATION) == "far")
480477
{
481-
ReleaseSingleInstanceMutex();
482478
if (ShellExecuteNonBlocking("open", GetLauncherPathFilename(), GetSequencerSnapshot()))
483479
ExitProcess(0); // All done here
484-
CreateSingleInstanceMutex();
480+
485481
return "fail";
486482
}
487483
return "ok";
@@ -501,10 +497,9 @@ SString CInstallManager::_SwitchBackFromTempExe()
501497
{
502498
m_pSequencer->SetVariable(INSTALL_LOCATION, "near");
503499

504-
ReleaseSingleInstanceMutex();
505500
if (ShellExecuteNonBlocking("open", GetLauncherPathFilename(), GetSequencerSnapshot()))
506501
ExitProcess(0); // All done here
507-
CreateSingleInstanceMutex();
502+
508503
return "fail";
509504
}
510505
return "ok";
@@ -584,9 +579,6 @@ SString CInstallManager::_PrepareLaunchLocation()
584579
{
585580
const bool isAdmin = IsUserAdmin();
586581

587-
// Ensure GTA exe is not running
588-
TerminateGTAIfRunning();
589-
590582
const fs::path gtaDir = GetGameBaseDirectory();
591583
const fs::path mtaDir = GetMTARootDirectory() / "MTA";
592584
const fs::path launchDir = GetGameLaunchDirectory();
@@ -718,9 +710,6 @@ SString CInstallManager::_ProcessGtaPatchCheck()
718710
//////////////////////////////////////////////////////////
719711
SString CInstallManager::_ProcessGtaDllCheck()
720712
{
721-
// Ensure GTA exe is not running
722-
TerminateGTAIfRunning();
723-
724713
struct DependencyHash
725714
{
726715
const char* fileName;

Client/loader/Main.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,6 @@ MTAEXPORT int DoWinMain(HINSTANCE hLauncherInstance, HINSTANCE hPrevInstance, LP
9393
BsodDetectionPreLaunch();
9494
MaybeShowCopySettingsDialog();
9595

96-
// Make sure GTA is not running
97-
HandleIfGTAIsAlreadyRunning();
98-
9996
// Maybe warn user if no anti-virus running
10097
CheckAntiVirusStatus();
10198

Client/loader/MainFunctions.cpp

Lines changed: 25 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -200,81 +200,38 @@ void HandleSpecialLaunchOptions()
200200
//////////////////////////////////////////////////////////
201201
void HandleDuplicateLaunching()
202202
{
203-
LPSTR lpCmdLine = GetCommandLine();
203+
LPWSTR szCommandLine = GetCommandLineW();
204204

205-
int iRecheckTimeLimit = 2000;
206-
while (!CreateSingleInstanceMutex())
207-
{
208-
if (strcmp(lpCmdLine, "") != 0)
209-
{
210-
HWND hwMTAWindow = FindWindow(NULL, "MTA: San Andreas");
205+
if (!szCommandLine[0])
206+
return;
207+
208+
HWND gameWindow = FindWindowA(nullptr, "MTA: San Andreas");
211209
#ifdef MTA_DEBUG
212-
if (hwMTAWindow == NULL)
213-
hwMTAWindow = FindWindow(NULL, "MTA: San Andreas [DEBUG]");
210+
if (gameWindow == nullptr)
211+
gameWindow = FindWindowA(nullptr, "MTA: San Andreas [DEBUG]");
214212
#endif
215-
if (hwMTAWindow != NULL)
216-
{
217-
LPWSTR szCommandLine = GetCommandLineW();
218-
int numArgs;
219-
LPWSTR* aCommandLineArgs = CommandLineToArgvW(szCommandLine, &numArgs);
220-
for (int i = 1; i < numArgs; ++i)
221-
{
222-
if (WStringX(aCommandLineArgs[i]).BeginsWith(L"mtasa://"))
223-
{
224-
WString wideConnectInfo = aCommandLineArgs[i];
225-
SString strConnectInfo = ToUTF8(wideConnectInfo);
226213

227-
COPYDATASTRUCT cdStruct;
228-
cdStruct.cbData = strConnectInfo.length() + 1;
229-
cdStruct.lpData = const_cast<char*>(strConnectInfo.c_str());
230-
cdStruct.dwData = URI_CONNECT;
214+
if (gameWindow == nullptr)
215+
return;
231216

232-
SendMessage(hwMTAWindow, WM_COPYDATA, NULL, (LPARAM)&cdStruct);
233-
break;
234-
}
235-
}
236-
}
237-
else
238-
{
239-
if (iRecheckTimeLimit > 0)
240-
{
241-
// Sleep a little bit and check the mutex again
242-
Sleep(500);
243-
iRecheckTimeLimit -= 500;
244-
continue;
245-
}
246-
SString strMessage;
247-
strMessage +=
248-
_("Trouble restarting MTA:SA\n\n"
249-
"If the problem persists, open Task Manager and\n"
250-
"stop the 'gta_sa.exe' and 'Multi Theft Auto.exe' processes\n\n\n"
251-
"Try to launch MTA:SA again?");
252-
if (MessageBoxUTF8(0, strMessage, _("Error") + _E("CL04"), MB_ICONWARNING | MB_YESNO | MB_TOPMOST) ==
253-
IDYES) // Trouble restarting MTA:SA
254-
{
255-
TerminateGTAIfRunning();
256-
TerminateOtherMTAIfRunning();
257-
ShellExecuteNonBlocking("open", PathJoin(GetMTASAPath(), MTA_EXE_NAME), lpCmdLine);
258-
}
259-
return ExitProcess(EXIT_ERROR);
260-
}
261-
}
262-
else
217+
int numArgs;
218+
LPWSTR* aCommandLineArgs = CommandLineToArgvW(szCommandLine, &numArgs);
219+
220+
for (int i = 1; i < numArgs; ++i)
221+
{
222+
if (WStringX(aCommandLineArgs[i]).BeginsWith(L"mtasa://"))
263223
{
264-
if (!IsGTARunning() && !IsOtherMTARunning())
265-
{
266-
MessageBoxUTF8(0, _("Another instance of MTA is already running.\n\nIf this problem persists, please restart your computer"),
267-
_("Error") + _E("CL05"), MB_ICONERROR | MB_TOPMOST);
268-
}
269-
else if (MessageBoxUTF8(0, _("Another instance of MTA is already running.\n\nDo you want to terminate it?"), _("Error") + _E("CL06"),
270-
MB_ICONQUESTION | MB_YESNO | MB_TOPMOST) == IDYES)
271-
{
272-
TerminateGTAIfRunning();
273-
TerminateOtherMTAIfRunning();
274-
ShellExecuteNonBlocking("open", PathJoin(GetMTASAPath(), MTA_EXE_NAME), lpCmdLine);
275-
}
224+
WString wideConnectInfo = aCommandLineArgs[i];
225+
SString strConnectInfo = ToUTF8(wideConnectInfo);
226+
227+
COPYDATASTRUCT cdStruct;
228+
cdStruct.cbData = strConnectInfo.length() + 1;
229+
cdStruct.lpData = const_cast<char*>(strConnectInfo.c_str());
230+
cdStruct.dwData = URI_CONNECT;
231+
232+
SendMessage(gameWindow, WM_COPYDATA, NULL, (LPARAM)&cdStruct);
233+
return ExitProcess(EXIT_ERROR);
276234
}
277-
return ExitProcess(EXIT_ERROR);
278235
}
279236
}
280237

@@ -480,8 +437,6 @@ void HandleCustomStartMessage()
480437
//////////////////////////////////////////////////////////
481438
void PreLaunchWatchDogs()
482439
{
483-
assert(!CreateSingleInstanceMutex());
484-
485440
//
486441
// "L0" is opened before the launch sequence and is closed if MTA shutsdown with no error
487442
// "L1" is opened before the launch sequence and is closed if GTA is succesfully started
@@ -587,35 +542,6 @@ void PostRunWatchDogs(int iReturnCode)
587542
}
588543
}
589544

590-
//////////////////////////////////////////////////////////
591-
//
592-
// HandleIfGTAIsAlreadyRunning
593-
//
594-
// Check for and maybe stop a running GTA process
595-
//
596-
//////////////////////////////////////////////////////////
597-
void HandleIfGTAIsAlreadyRunning()
598-
{
599-
if (IsGTARunning())
600-
{
601-
if (MessageBoxUTF8(
602-
0, _("An instance of GTA: San Andreas is already running. It needs to be terminated before MTA:SA can be started. Do you want to do that now?"),
603-
_("Information") + _E("CL10"), MB_YESNO | MB_ICONQUESTION | MB_TOPMOST) == IDYES)
604-
{
605-
TerminateOtherMTAIfRunning();
606-
TerminateGTAIfRunning();
607-
if (IsGTARunning())
608-
{
609-
MessageBoxUTF8(0, _("Unable to terminate GTA: San Andreas. If the problem persists, please restart your computer."),
610-
_("Information") + _E("CL11"), MB_OK | MB_ICONERROR | MB_TOPMOST);
611-
return ExitProcess(EXIT_ERROR);
612-
}
613-
}
614-
else
615-
return ExitProcess(EXIT_OK);
616-
}
617-
}
618-
619545
//////////////////////////////////////////////////////////
620546
//
621547
// ValidateGTAPath
@@ -844,7 +770,6 @@ void CheckDataFiles()
844770
{
845771
SString strMessage(_("Main file has an incorrect name (%s)"), *GetLaunchFilename());
846772
int iResponse = MessageBoxUTF8(NULL, strMessage, _("Error") + _E("CL33"), MB_RETRYCANCEL | MB_ICONERROR | MB_TOPMOST);
847-
ReleaseSingleInstanceMutex();
848773
if (iResponse == IDRETRY)
849774
ShellExecuteNonBlocking("open", PathJoin(strMTASAPath, MTA_EXE_NAME));
850775
return ExitProcess(EXIT_ERROR);
@@ -1272,7 +1197,6 @@ int LaunchGame(SString strCmdLine)
12721197
//
12731198
// Cleanup and exit.
12741199
CloseHandle(piLoadee.hProcess);
1275-
ReleaseSingleInstanceMutex();
12761200

12771201
// Success, maybe
12781202
return dwExitCode;

Client/loader/MainFunctions.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ void HandleDuplicateLaunching();
1616
void HandleCustomStartMessage();
1717
void PreLaunchWatchDogs();
1818
void PostRunWatchDogs(int iReturnCode);
19-
void HandleIfGTAIsAlreadyRunning();
2019
void ValidateGTAPath();
2120
void CheckAntiVirusStatus();
2221
void CheckDataFiles();

0 commit comments

Comments
 (0)