diff --git a/Client/loader/CInstallManager.cpp b/Client/loader/CInstallManager.cpp index c16c3afcec..8a9d3bd786 100644 --- a/Client/loader/CInstallManager.cpp +++ b/Client/loader/CInstallManager.cpp @@ -1269,17 +1269,31 @@ SString CInstallManager::_ProcessAppCompatChecks() } // Windows 7: Fix invalid GameUX URL (which causes rundll32.exe to use excessive CPU) - WString strUrlKey = L"SOFTWARE\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\GameUX\\ServiceLocation"; - WString strUrlItem = L"Games"; - WString strUrlValue = ReadCompatibilityEntries(strUrlItem, strUrlKey, HKEY_CURRENT_USER, 0); - if (!strUrlValue.empty()) { - WriteDebugEvent(SString("GameUX ServiceLocation was '%s'", *ToUTF8(strUrlValue))); - if (strUrlValue.ContainsI(L":")) + WString strUrlKey = L"SOFTWARE\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\GameUX\\ServiceLocation"; + WString strUrlItem = L"Games"; + WString strUrlValue = ReadCompatibilityEntries(strUrlItem, strUrlKey, HKEY_CURRENT_USER, 0); + if (!strUrlValue.empty()) { - strUrlValue = L"disabled"; // Can be anything not containing `:` - if (!WriteCompatibilityEntries(strUrlItem, strUrlKey, HKEY_CURRENT_USER, 0, strUrlValue)) - bTryAdmin = true; + WriteDebugEvent(SString("GameUX ServiceLocation was '%s'", *ToUTF8(strUrlValue))); + if (strUrlValue.ContainsI(L":")) + { + strUrlValue = L"disabled"; // Can be anything not containing `:` + if (!WriteCompatibilityEntries(strUrlItem, strUrlKey, HKEY_CURRENT_USER, 0, strUrlValue)) + bTryAdmin = true; + } + } + } + + // Windows 10: Disable multi-threaded loading of DLLs. + { + DWORD maxLoaderThreads{}; + LPCWSTR imageFileExecutionOptions = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\" GTA_EXE_NAME; + RegQueryInteger(HKEY_LOCAL_MACHINE, imageFileExecutionOptions, L"MaxLoaderThreads", maxLoaderThreads); + + if (maxLoaderThreads != 1 && !RegWriteInteger(HKEY_LOCAL_MACHINE, imageFileExecutionOptions, L"MaxLoaderThreads", 1)) + { + bTryAdmin = true; } } diff --git a/Client/loader/Utils.cpp b/Client/loader/Utils.cpp index db8cde4125..9d3ead9eba 100644 --- a/Client/loader/Utils.cpp +++ b/Client/loader/Utils.cpp @@ -2178,6 +2178,32 @@ bool IsNativeArm64Host() return isArm64; } +bool RegQueryInteger(HKEY rootKey, LPCWSTR keyName, LPCWSTR valueName, DWORD& value) +{ + value = {}; + + HKEY key{}; + if (RegOpenKeyExW(rootKey, keyName, 0, KEY_READ, &key) != ERROR_SUCCESS) + return false; + + DWORD valueType = REG_DWORD; + DWORD valueSize = sizeof(value); + LSTATUS status = RegQueryValueExW(key, valueName, nullptr, &valueType, reinterpret_cast(&value), &valueSize); + RegCloseKey(key); + return status == ERROR_SUCCESS; +} + +bool RegWriteInteger(HKEY rootKey, LPCWSTR keyName, LPCWSTR valueName, DWORD value) +{ + HKEY key{}; + if (RegCreateKeyExW(rootKey, keyName, 0, 0, REG_OPTION_NON_VOLATILE, KEY_WRITE, nullptr, &key, nullptr) != ERROR_SUCCESS) + return false; + + LSTATUS status = RegSetValueExW(key, valueName, 0, REG_DWORD, reinterpret_cast(&value), sizeof(value)); + RegCloseKey(key); + return status == ERROR_SUCCESS; +} + ////////////////////////////////////////////////////////// // // ReadCompatibilityEntries diff --git a/Client/loader/Utils.h b/Client/loader/Utils.h index ab7530f4f2..be0685a83c 100644 --- a/Client/loader/Utils.h +++ b/Client/loader/Utils.h @@ -156,6 +156,16 @@ bool IsErrorCodeLoggable(const std::error_code& ec); */ bool IsNativeArm64Host(); +/** + * @brief Queries the integer value of a specific value item from the registry. + */ +bool RegQueryInteger(HKEY rootKey, LPCWSTR keyName, LPCWSTR valueName, DWORD& value); + +/** + * @brief Writes an integer value to a specific value item in the registry. + */ +bool RegWriteInteger(HKEY rootKey, LPCWSTR keyName, LPCWSTR valueName, DWORD value); + // Return false on read failure template bool ReadFileValue(const SString& strFilename, T& value, uint uiOffset) diff --git a/Shared/installer/nightly.nsi b/Shared/installer/nightly.nsi index d3d7759cdd..7890e37fdc 100644 --- a/Shared/installer/nightly.nsi +++ b/Shared/installer/nightly.nsi @@ -369,6 +369,9 @@ Function .onInstSuccess WriteRegStr HKLM "SOFTWARE\Multi Theft Auto: San Andreas All\Common" "GTA:SA Path" $GTA_DIR WriteRegStr HKLM "SOFTWARE\Multi Theft Auto: San Andreas All\${0.0}" "Last Install Location" $INSTDIR + + # Add 'MaxLoaderThreads' DWORD value for gta_sa.exe to disable multi-threaded loading of DLLs. + WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\gta_sa.exe" "MaxLoaderThreads" 1 # Initilize variables holding paths and names Call MTAInitFileNamesAndPaths @@ -1142,6 +1145,10 @@ Section Uninstall DeleteRegKey HKCR "mtasa" ${EndIf} + # Remove 'MaxLoaderThreads' DWORD value for gta_sa.exe. + DeleteRegValue HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\gta_sa.exe" "MaxLoaderThreads" + DeleteRegKey /ifempty HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\gta_sa.exe" + ${GameExplorer_RemoveGame} ${GUID} ; Delete client shortcuts