diff --git a/src/openrct2/cmdline/RootCommands.cpp b/src/openrct2/cmdline/RootCommands.cpp index a2ee4f5a78..e9fc2f311d 100644 --- a/src/openrct2/cmdline/RootCommands.cpp +++ b/src/openrct2/cmdline/RootCommands.cpp @@ -21,6 +21,7 @@ #include "../network/network.h" #include "../object/ObjectRepository.h" #include "../platform/Crash.h" +#include "../platform/Platform2.h" #include "../platform/platform.h" #include "CommandLine.hpp" @@ -423,7 +424,7 @@ static exitcode_t HandleCommandRegisterShell([[maybe_unused]] CommandLineArgEnum if (!_removeShell) { - platform_setup_file_associations(); + Platform::SetUpFileAssociations(); } else { diff --git a/src/openrct2/platform/Platform.Win32.cpp b/src/openrct2/platform/Platform.Win32.cpp index 789b63f171..e847ea9ce2 100644 --- a/src/openrct2/platform/Platform.Win32.cpp +++ b/src/openrct2/platform/Platform.Win32.cpp @@ -13,6 +13,8 @@ # include // Then the rest +# include "../Version.h" + # include # include # include @@ -35,6 +37,8 @@ # include +constexpr wchar_t SOFTWARE_CLASSES[] = L"Software\\Classes"; + namespace Platform { # ifdef __USE_SHGETKNOWNFOLDERPATH__ @@ -347,6 +351,127 @@ namespace Platform return reinterpret_cast(input); } + void SetUpFileAssociations() + { + // Setup file extensions + SetUpFileAssociation(".sc4", "RCT1 Scenario (.sc4)", "Play", "\"%1\"", 0); + SetUpFileAssociation(".sc6", "RCT2 Scenario (.sc6)", "Play", "\"%1\"", 0); + SetUpFileAssociation(".sv4", "RCT1 Saved Game (.sc4)", "Play", "\"%1\"", 0); + SetUpFileAssociation(".sv6", "RCT2 Saved Game (.sv6)", "Play", "\"%1\"", 0); + SetUpFileAssociation(".sv7", "RCT Modified Saved Game (.sv7)", "Play", "\"%1\"", 0); + SetUpFileAssociation(".td4", "RCT1 Track Design (.td4)", "Install", "\"%1\"", 0); + SetUpFileAssociation(".td6", "RCT2 Track Design (.td6)", "Install", "\"%1\"", 0); + + // Refresh explorer + SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); + } + + static HMODULE _dllModule = nullptr; + static HMODULE GetDLLModule() + { + if (_dllModule == nullptr) + { + _dllModule = GetModuleHandle(nullptr); + } + return _dllModule; + } + + static std::wstring get_progIdName(const std::string_view& extension) + { + auto progIdName = std::string(OPENRCT2_NAME) + std::string(extension); + auto progIdNameW = String::ToWideChar(progIdName); + return progIdNameW; + } + + bool SetUpFileAssociation( + const std::string extension, const std::string fileTypeText, const std::string commandText, + const std::string commandArgs, const uint32_t iconIndex) + { + wchar_t exePathW[MAX_PATH]; + wchar_t dllPathW[MAX_PATH]; + + [[maybe_unused]] int32_t printResult; + + GetModuleFileNameW(nullptr, exePathW, static_cast(std::size(exePathW))); + GetModuleFileNameW(GetDLLModule(), dllPathW, static_cast(std::size(dllPathW))); + + auto extensionW = String::ToWideChar(extension); + auto fileTypeTextW = String::ToWideChar(fileTypeText); + auto commandTextW = String::ToWideChar(commandText); + auto commandArgsW = String::ToWideChar(commandArgs); + auto progIdNameW = get_progIdName(extension); + + HKEY hKey = nullptr; + HKEY hRootKey = nullptr; + + // [HKEY_CURRENT_USER\Software\Classes] + if (RegOpenKeyW(HKEY_CURRENT_USER, SOFTWARE_CLASSES, &hRootKey) != ERROR_SUCCESS) + { + RegCloseKey(hRootKey); + return false; + } + + // [hRootKey\.ext] + if (RegSetValueW(hRootKey, extensionW.c_str(), REG_SZ, progIdNameW.c_str(), 0) != ERROR_SUCCESS) + { + RegCloseKey(hRootKey); + return false; + } + + if (RegCreateKeyW(hRootKey, progIdNameW.c_str(), &hKey) != ERROR_SUCCESS) + { + RegCloseKey(hKey); + RegCloseKey(hRootKey); + return false; + } + + // [hRootKey\OpenRCT2.ext] + if (RegSetValueW(hKey, nullptr, REG_SZ, fileTypeTextW.c_str(), 0) != ERROR_SUCCESS) + { + RegCloseKey(hKey); + RegCloseKey(hRootKey); + return false; + } + // [hRootKey\OpenRCT2.ext\DefaultIcon] + wchar_t szIconW[MAX_PATH]; + printResult = swprintf_s(szIconW, MAX_PATH, L"\"%s\",%d", dllPathW, iconIndex); + assert(printResult >= 0); + if (RegSetValueW(hKey, L"DefaultIcon", REG_SZ, szIconW, 0) != ERROR_SUCCESS) + { + RegCloseKey(hKey); + RegCloseKey(hRootKey); + return false; + } + + // [hRootKey\OpenRCT2.sv6\shell] + if (RegSetValueW(hKey, L"shell", REG_SZ, L"open", 0) != ERROR_SUCCESS) + { + RegCloseKey(hKey); + RegCloseKey(hRootKey); + return false; + } + + // [hRootKey\OpenRCT2.sv6\shell\open] + if (RegSetValueW(hKey, L"shell\\open", REG_SZ, commandTextW.c_str(), 0) != ERROR_SUCCESS) + { + RegCloseKey(hKey); + RegCloseKey(hRootKey); + return false; + } + + // [hRootKey\OpenRCT2.sv6\shell\open\command] + wchar_t szCommandW[MAX_PATH]; + printResult = swprintf_s(szCommandW, MAX_PATH, L"\"%s\" %s", exePathW, commandArgsW.c_str()); + assert(printResult >= 0); + if (RegSetValueW(hKey, L"shell\\open\\command", REG_SZ, szCommandW, 0) != ERROR_SUCCESS) + { + RegCloseKey(hKey); + RegCloseKey(hRootKey); + return false; + } + return true; + } + bool HandleSpecialCommandLineArgument(const char* argument) { return false; diff --git a/src/openrct2/platform/Platform2.h b/src/openrct2/platform/Platform2.h index 0805443ce9..e960e33719 100644 --- a/src/openrct2/platform/Platform2.h +++ b/src/openrct2/platform/Platform2.h @@ -43,6 +43,10 @@ namespace Platform #ifdef _WIN32 bool IsOSVersionAtLeast(uint32_t major, uint32_t minor, uint32_t build); + void SetUpFileAssociations(); + bool SetUpFileAssociation( + const std::string extension, const std::string fileTypeText, const std::string commandText, + const std::string commandArgs, const uint32_t iconIndex); #endif bool IsRunningInWine(); diff --git a/src/openrct2/platform/Windows.cpp b/src/openrct2/platform/Windows.cpp index 4f22404a02..9fc1572d06 100644 --- a/src/openrct2/platform/Windows.cpp +++ b/src/openrct2/platform/Windows.cpp @@ -27,6 +27,7 @@ # include "../localisation/Language.h" # include "../rct2/RCT2.h" # include "../util/Util.h" +# include "Platform2.h" # include "platform.h" # include @@ -54,17 +55,6 @@ # define swprintf_s(a, b, c, d, ...) swprintf(a, b, c, ##__VA_ARGS__) # endif -static HMODULE _dllModule = nullptr; - -static HMODULE plaform_get_dll_module() -{ - if (_dllModule == nullptr) - { - _dllModule = GetModuleHandle(nullptr); - } - return _dllModule; -} - void platform_get_date_local(rct2_date* out_date) { assert(out_date != nullptr); @@ -551,86 +541,6 @@ static std::wstring get_progIdName(const std::string_view& extension) return progIdNameW; } -static bool windows_setup_file_association( - const utf8* extension, const utf8* fileTypeText, const utf8* commandText, const utf8* commandArgs, const uint32_t iconIndex) -{ - wchar_t exePathW[MAX_PATH]; - wchar_t dllPathW[MAX_PATH]; - - [[maybe_unused]] int32_t printResult; - - GetModuleFileNameW(nullptr, exePathW, (DWORD)std::size(exePathW)); - GetModuleFileNameW(plaform_get_dll_module(), dllPathW, (DWORD)std::size(dllPathW)); - - auto extensionW = String::ToWideChar(extension); - auto fileTypeTextW = String::ToWideChar(fileTypeText); - auto commandTextW = String::ToWideChar(commandText); - auto commandArgsW = String::ToWideChar(commandArgs); - auto progIdNameW = get_progIdName(extension); - - bool result = false; - HKEY hKey = nullptr; - HKEY hRootKey = nullptr; - - // [HKEY_CURRENT_USER\Software\Classes] - if (RegOpenKeyW(HKEY_CURRENT_USER, SOFTWARE_CLASSES, &hRootKey) != ERROR_SUCCESS) - { - goto fail; - } - - // [hRootKey\.ext] - if (RegSetValueW(hRootKey, extensionW.c_str(), REG_SZ, progIdNameW.c_str(), 0) != ERROR_SUCCESS) - { - goto fail; - } - - if (RegCreateKeyW(hRootKey, progIdNameW.c_str(), &hKey) != ERROR_SUCCESS) - { - goto fail; - } - - // [hRootKey\OpenRCT2.ext] - if (RegSetValueW(hKey, nullptr, REG_SZ, fileTypeTextW.c_str(), 0) != ERROR_SUCCESS) - { - goto fail; - } - // [hRootKey\OpenRCT2.ext\DefaultIcon] - wchar_t szIconW[MAX_PATH]; - printResult = swprintf_s(szIconW, MAX_PATH, L"\"%s\",%d", dllPathW, iconIndex); - assert(printResult >= 0); - if (RegSetValueW(hKey, L"DefaultIcon", REG_SZ, szIconW, 0) != ERROR_SUCCESS) - { - goto fail; - } - - // [hRootKey\OpenRCT2.sv6\shell] - if (RegSetValueW(hKey, L"shell", REG_SZ, L"open", 0) != ERROR_SUCCESS) - { - goto fail; - } - - // [hRootKey\OpenRCT2.sv6\shell\open] - if (RegSetValueW(hKey, L"shell\\open", REG_SZ, commandTextW.c_str(), 0) != ERROR_SUCCESS) - { - goto fail; - } - - // [hRootKey\OpenRCT2.sv6\shell\open\command] - wchar_t szCommandW[MAX_PATH]; - printResult = swprintf_s(szCommandW, MAX_PATH, L"\"%s\" %s", exePathW, commandArgsW.c_str()); - assert(printResult >= 0); - if (RegSetValueW(hKey, L"shell\\open\\command", REG_SZ, szCommandW, 0) != ERROR_SUCCESS) - { - goto fail; - } - - result = true; -fail: - RegCloseKey(hKey); - RegCloseKey(hRootKey); - return result; -} - static void windows_remove_file_association(const utf8* extension) { # if _WIN32_WINNT >= 0x0600 @@ -650,21 +560,6 @@ static void windows_remove_file_association(const utf8* extension) # endif } -void platform_setup_file_associations() -{ - // Setup file extensions - windows_setup_file_association(".sc4", "RCT1 Scenario (.sc4)", "Play", "\"%1\"", 0); - windows_setup_file_association(".sc6", "RCT2 Scenario (.sc6)", "Play", "\"%1\"", 0); - windows_setup_file_association(".sv4", "RCT1 Saved Game (.sc4)", "Play", "\"%1\"", 0); - windows_setup_file_association(".sv6", "RCT2 Saved Game (.sv6)", "Play", "\"%1\"", 0); - windows_setup_file_association(".sv7", "RCT Modified Saved Game (.sv7)", "Play", "\"%1\"", 0); - windows_setup_file_association(".td4", "RCT1 Track Design (.td4)", "Install", "\"%1\"", 0); - windows_setup_file_association(".td6", "RCT2 Track Design (.td6)", "Install", "\"%1\"", 0); - - // Refresh explorer - SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); -} - void platform_remove_file_associations() { // Remove file extensions diff --git a/src/openrct2/platform/platform.h b/src/openrct2/platform/platform.h index 619409d07e..2aabe7f161 100644 --- a/src/openrct2/platform/platform.h +++ b/src/openrct2/platform/platform.h @@ -151,7 +151,6 @@ void core_init(); # undef CreateWindow # undef GetMessage -void platform_setup_file_associations(); void platform_remove_file_associations(); bool platform_setup_uri_protocol(); // This function cannot be marked as 'static', even though it may seem to be,