mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-04 13:42:55 +01:00
Merge pull request #18217 from CookiePLMonster/fix-18200
Refactor Windows locales and remove the last non-Unicode functions
This commit is contained in:
@@ -23,3 +23,6 @@ SET(CMAKE_FIND_ROOT_PATH ${TARGET_ENVIRONMENT})
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
|
||||
# Enable Unicode
|
||||
add_compile_options(-municode)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<TargetPlatformVersion>10.0.17763.0</TargetPlatformVersion>
|
||||
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
|
||||
<OutDir>$(SolutionDir)bin\</OutDir>
|
||||
<IntDir>$(SolutionDir)obj\$(ProjectName)\$(Configuration)_$(Platform)\</IntDir>
|
||||
|
||||
@@ -62,20 +62,20 @@ namespace OpenRCT2::Ui
|
||||
public:
|
||||
Win32Context()
|
||||
{
|
||||
_win32module = GetModuleHandleA(nullptr);
|
||||
_win32module = GetModuleHandle(nullptr);
|
||||
}
|
||||
|
||||
void SetWindowIcon(SDL_Window* window) override
|
||||
{
|
||||
if (_win32module != nullptr)
|
||||
{
|
||||
HICON icon = LoadIconA(_win32module, MAKEINTRESOURCEA(IDI_ICON));
|
||||
HICON icon = LoadIcon(_win32module, MAKEINTRESOURCE(IDI_ICON));
|
||||
if (icon != nullptr)
|
||||
{
|
||||
HWND hwnd = GetHWND(window);
|
||||
if (hwnd != nullptr)
|
||||
{
|
||||
SendMessageA(hwnd, WM_SETICON, ICON_SMALL, reinterpret_cast<LPARAM>(icon));
|
||||
SendMessage(hwnd, WM_SETICON, ICON_SMALL, reinterpret_cast<LPARAM>(icon));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,7 @@ namespace OpenRCT2::Ui
|
||||
|
||||
bool IsSteamOverlayAttached() override
|
||||
{
|
||||
return (GetModuleHandleA("GameOverlayRenderer.dll") != nullptr);
|
||||
return (GetModuleHandleW(L"GameOverlayRenderer.dll") != nullptr);
|
||||
}
|
||||
|
||||
void ShowMessageBox(SDL_Window* window, const std::string& message) override
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace Guard
|
||||
static std::optional<std::string> _lastAssertMessage = std::nullopt;
|
||||
|
||||
#ifdef _WIN32
|
||||
[[nodiscard]] static std::string CreateDialogAssertMessage(std::string_view);
|
||||
[[nodiscard]] static std::wstring CreateDialogAssertMessage(std::string_view);
|
||||
static void ForceCrash();
|
||||
#endif
|
||||
|
||||
@@ -104,7 +104,8 @@ namespace Guard
|
||||
{
|
||||
// Show message box if we are not building for testing
|
||||
auto buffer = CreateDialogAssertMessage(formattedMessage);
|
||||
int32_t result = MessageBoxA(nullptr, buffer.c_str(), OPENRCT2_NAME, MB_ABORTRETRYIGNORE | MB_ICONEXCLAMATION);
|
||||
int32_t result = MessageBoxW(
|
||||
nullptr, buffer.c_str(), L"" OPENRCT2_NAME, MB_ABORTRETRYIGNORE | MB_ICONEXCLAMATION);
|
||||
if (result == IDABORT)
|
||||
{
|
||||
ForceCrash();
|
||||
@@ -134,19 +135,19 @@ namespace Guard
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
[[nodiscard]] static std::string CreateDialogAssertMessage(std::string_view formattedMessage)
|
||||
[[nodiscard]] static std::wstring CreateDialogAssertMessage(std::string_view formattedMessage)
|
||||
{
|
||||
StringBuilder sb;
|
||||
sb.Append(ASSERTION_MESSAGE);
|
||||
sb.Append("\r\n\r\n");
|
||||
sb.Append("\n\n");
|
||||
sb.Append("Version: ");
|
||||
sb.Append(gVersionInfoFull);
|
||||
if (!formattedMessage.empty())
|
||||
{
|
||||
sb.Append("\r\n");
|
||||
sb.Append("\n");
|
||||
sb.Append(formattedMessage);
|
||||
}
|
||||
return sb.GetStdString();
|
||||
return String::ToWideChar({ sb.GetBuffer(), sb.GetLength() });
|
||||
}
|
||||
|
||||
static void ForceCrash()
|
||||
|
||||
@@ -104,13 +104,13 @@ static bool OnCrash(
|
||||
{
|
||||
if (!succeeded)
|
||||
{
|
||||
constexpr const char* DumpFailedMessage = "Failed to create the dump. Please file an issue with OpenRCT2 on GitHub and "
|
||||
"provide latest save, and provide "
|
||||
"information about what you did before the crash occurred.";
|
||||
printf("%s\n", DumpFailedMessage);
|
||||
constexpr const wchar_t* DumpFailedMessage = L"Failed to create the dump. Please file an issue with OpenRCT2 on GitHub "
|
||||
L"and provide latest save, and provide information about what you did "
|
||||
L"before the crash occurred.";
|
||||
wprintf(L"%ls\n", DumpFailedMessage);
|
||||
if (!gOpenRCT2SilentBreakpad)
|
||||
{
|
||||
MessageBoxA(nullptr, DumpFailedMessage, OPENRCT2_NAME, MB_OK | MB_ICONERROR);
|
||||
MessageBoxW(nullptr, DumpFailedMessage, L"" OPENRCT2_NAME, MB_OK | MB_ICONERROR);
|
||||
}
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ static uint32_t _frequency = 0;
|
||||
static LARGE_INTEGER _entryTimestamp;
|
||||
|
||||
// The name of the mutex used to prevent multiple instances of the game from running
|
||||
static constexpr char SINGLE_INSTANCE_MUTEX_NAME[] = "RollerCoaster Tycoon 2_GSKMUTEX";
|
||||
static constexpr wchar_t SINGLE_INSTANCE_MUTEX_NAME[] = L"RollerCoaster Tycoon 2_GSKMUTEX";
|
||||
|
||||
# define SOFTWARE_CLASSES L"Software\\Classes"
|
||||
# define MUI_CACHE L"Local Settings\\Software\\Microsoft\\Windows\\Shell\\MuiCache"
|
||||
@@ -224,7 +224,7 @@ namespace Platform
|
||||
bool IsOSVersionAtLeast(uint32_t major, uint32_t minor, uint32_t build)
|
||||
{
|
||||
bool result = false;
|
||||
auto hModule = GetModuleHandleA("ntdll.dll");
|
||||
auto hModule = GetModuleHandleW(L"ntdll.dll");
|
||||
if (hModule != nullptr)
|
||||
{
|
||||
using RtlGetVersionPtr = long(WINAPI*)(PRTL_OSVERSIONINFOW);
|
||||
@@ -470,7 +470,7 @@ namespace Platform
|
||||
if (RegOpenKeyW(HKEY_CURRENT_USER, SOFTWARE_CLASSES, &hRootKey) == ERROR_SUCCESS)
|
||||
{
|
||||
// [hRootKey\.ext]
|
||||
RegDeleteTreeA(hRootKey, extension);
|
||||
RegDeleteTreeW(hRootKey, String::ToWideChar(extension).c_str());
|
||||
|
||||
// [hRootKey\OpenRCT2.ext]
|
||||
auto progIdName = get_progIdName(extension);
|
||||
@@ -590,109 +590,81 @@ namespace Platform
|
||||
|
||||
uint16_t GetLocaleLanguage()
|
||||
{
|
||||
CHAR langCode[4];
|
||||
|
||||
if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SABBREVLANGNAME, reinterpret_cast<LPSTR>(&langCode), sizeof(langCode))
|
||||
== 0)
|
||||
wchar_t langCode[LOCALE_NAME_MAX_LENGTH];
|
||||
if (GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, langCode, static_cast<int>(std::size(langCode))) == 0)
|
||||
{
|
||||
return LANGUAGE_UNDEFINED;
|
||||
}
|
||||
|
||||
if (strcmp(langCode, "ENG") == 0)
|
||||
const std::pair<std::wstring_view, int16_t> supportedLocales[] = {
|
||||
{ L"ar", /*LANGUAGE_ARABIC*/ LANGUAGE_UNDEFINED }, // Experimental, don't risk offering it by default yet
|
||||
{ L"ca", LANGUAGE_CATALAN },
|
||||
{ L"zh-Hans", LANGUAGE_CHINESE_SIMPLIFIED }, // May not be accurate enough
|
||||
{ L"zh-Hant", LANGUAGE_CHINESE_TRADITIONAL }, // May not be accurate enough
|
||||
{ L"cs", LANGUAGE_CZECH },
|
||||
{ L"da", LANGUAGE_DANISH },
|
||||
{ L"de", LANGUAGE_GERMAN },
|
||||
{ L"en-GB", LANGUAGE_ENGLISH_UK },
|
||||
{ L"en-US", LANGUAGE_ENGLISH_US },
|
||||
{ L"eo", LANGUAGE_ESPERANTO },
|
||||
{ L"es", LANGUAGE_SPANISH },
|
||||
{ L"fr", LANGUAGE_FRENCH },
|
||||
{ L"it", LANGUAGE_ITALIAN },
|
||||
{ L"ja", LANGUAGE_JAPANESE },
|
||||
{ L"ko", LANGUAGE_KOREAN },
|
||||
{ L"hu", LANGUAGE_HUNGARIAN },
|
||||
{ L"nl", LANGUAGE_DUTCH },
|
||||
{ L"no", LANGUAGE_NORWEGIAN },
|
||||
{ L"pl", LANGUAGE_POLISH },
|
||||
{ L"pt-BR", LANGUAGE_PORTUGUESE_BR },
|
||||
{ L"ru", LANGUAGE_RUSSIAN },
|
||||
{ L"fi", LANGUAGE_FINNISH },
|
||||
{ L"sv", LANGUAGE_SWEDISH },
|
||||
{ L"tr", LANGUAGE_TURKISH },
|
||||
{ L"vi", LANGUAGE_VIETNAMESE },
|
||||
};
|
||||
static_assert(
|
||||
std::size(supportedLocales) == LANGUAGE_COUNT - 1, "GetLocaleLanguage: List of languages does not match the enum!");
|
||||
|
||||
for (const auto& locale : supportedLocales)
|
||||
{
|
||||
return LANGUAGE_ENGLISH_UK;
|
||||
}
|
||||
if (strcmp(langCode, "ENU") == 0)
|
||||
{
|
||||
return LANGUAGE_ENGLISH_US;
|
||||
}
|
||||
if (strcmp(langCode, "DEU") == 0)
|
||||
{
|
||||
return LANGUAGE_GERMAN;
|
||||
}
|
||||
if (strcmp(langCode, "NLD") == 0)
|
||||
{
|
||||
return LANGUAGE_DUTCH;
|
||||
}
|
||||
if (strcmp(langCode, "FRA") == 0)
|
||||
{
|
||||
return LANGUAGE_FRENCH;
|
||||
}
|
||||
if (strcmp(langCode, "HUN") == 0)
|
||||
{
|
||||
return LANGUAGE_HUNGARIAN;
|
||||
}
|
||||
if (strcmp(langCode, "PLK") == 0)
|
||||
{
|
||||
return LANGUAGE_POLISH;
|
||||
}
|
||||
if (strcmp(langCode, "ESP") == 0)
|
||||
{
|
||||
return LANGUAGE_SPANISH;
|
||||
}
|
||||
if (strcmp(langCode, "SVE") == 0)
|
||||
{
|
||||
return LANGUAGE_SWEDISH;
|
||||
}
|
||||
if (strcmp(langCode, "ITA") == 0)
|
||||
{
|
||||
return LANGUAGE_ITALIAN;
|
||||
}
|
||||
if (strcmp(langCode, "POR") == 0)
|
||||
{
|
||||
return LANGUAGE_PORTUGUESE_BR;
|
||||
}
|
||||
if (strcmp(langCode, "FIN") == 0)
|
||||
{
|
||||
return LANGUAGE_FINNISH;
|
||||
}
|
||||
if (strcmp(langCode, "NOR") == 0)
|
||||
{
|
||||
return LANGUAGE_NORWEGIAN;
|
||||
}
|
||||
if (strcmp(langCode, "DAN") == 0)
|
||||
{
|
||||
return LANGUAGE_DANISH;
|
||||
if (wcsncmp(langCode, locale.first.data(), locale.first.length()) == 0)
|
||||
{
|
||||
return locale.second;
|
||||
}
|
||||
}
|
||||
return LANGUAGE_UNDEFINED;
|
||||
}
|
||||
|
||||
CurrencyType GetLocaleCurrency()
|
||||
{
|
||||
CHAR currCode[4];
|
||||
if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SINTLSYMBOL, reinterpret_cast<LPSTR>(&currCode), sizeof(currCode)) == 0)
|
||||
wchar_t currCode[9];
|
||||
if (GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SINTLSYMBOL, currCode, static_cast<int>(std::size(currCode))) == 0)
|
||||
{
|
||||
return Platform::GetCurrencyValue(nullptr);
|
||||
}
|
||||
|
||||
return Platform::GetCurrencyValue(currCode);
|
||||
return Platform::GetCurrencyValue(String::ToUtf8(currCode).c_str());
|
||||
}
|
||||
|
||||
MeasurementFormat GetLocaleMeasurementFormat()
|
||||
{
|
||||
UINT measurement_system;
|
||||
if (GetLocaleInfo(
|
||||
LOCALE_USER_DEFAULT, LOCALE_IMEASURE | LOCALE_RETURN_NUMBER, reinterpret_cast<LPSTR>(&measurement_system),
|
||||
sizeof(measurement_system))
|
||||
if (GetLocaleInfoEx(
|
||||
LOCALE_NAME_USER_DEFAULT, LOCALE_IMEASURE | LOCALE_RETURN_NUMBER, reinterpret_cast<LPWSTR>(&measurement_system),
|
||||
sizeof(measurement_system) / sizeof(wchar_t))
|
||||
== 0)
|
||||
{
|
||||
return MeasurementFormat::Metric;
|
||||
}
|
||||
|
||||
switch (measurement_system)
|
||||
{
|
||||
case 1:
|
||||
return MeasurementFormat::Imperial;
|
||||
case 0:
|
||||
default:
|
||||
return MeasurementFormat::Metric;
|
||||
}
|
||||
return measurement_system == 1 ? MeasurementFormat::Imperial : MeasurementFormat::Metric;
|
||||
}
|
||||
|
||||
uint8_t GetLocaleDateFormat()
|
||||
{
|
||||
// Retrieve short date format, eg "MM/dd/yyyy"
|
||||
wchar_t dateFormat[20];
|
||||
wchar_t dateFormat[80];
|
||||
if (GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SSHORTDATE, dateFormat, static_cast<int>(std::size(dateFormat)))
|
||||
== 0)
|
||||
{
|
||||
@@ -705,8 +677,8 @@ namespace Platform
|
||||
// in our date formats.
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd317787(v=vs.85).aspx
|
||||
//
|
||||
wchar_t first[sizeof(dateFormat)];
|
||||
wchar_t second[sizeof(dateFormat)];
|
||||
wchar_t first[std::size(dateFormat)];
|
||||
wchar_t second[std::size(dateFormat)];
|
||||
if (swscanf_s(
|
||||
dateFormat, L"%l[dyM]%*l[^dyM]%l[dyM]%*l[^dyM]%*l[dyM]", first, static_cast<uint32_t>(std::size(first)), second,
|
||||
static_cast<uint32_t>(std::size(second)))
|
||||
@@ -715,17 +687,17 @@ namespace Platform
|
||||
return DATE_FORMAT_DAY_MONTH_YEAR;
|
||||
}
|
||||
|
||||
if (wcsncmp(L"d", first, 1) == 0)
|
||||
if (first[0] == L'd')
|
||||
{
|
||||
return DATE_FORMAT_DAY_MONTH_YEAR;
|
||||
}
|
||||
if (wcsncmp(L"M", first, 1) == 0)
|
||||
if (first[0] == L'M')
|
||||
{
|
||||
return DATE_FORMAT_MONTH_DAY_YEAR;
|
||||
}
|
||||
if (wcsncmp(L"y", first, 1) == 0)
|
||||
if (first[0] == L'y')
|
||||
{
|
||||
if (wcsncmp(L"d", second, 1) == 0)
|
||||
if (second[0] == 'd')
|
||||
{
|
||||
return DATE_FORMAT_YEAR_DAY_MONTH;
|
||||
}
|
||||
@@ -742,21 +714,18 @@ namespace Platform
|
||||
{
|
||||
UINT fahrenheit;
|
||||
|
||||
// GetLocaleInfo will set fahrenheit to 1 if the locale on this computer
|
||||
// GetLocaleInfoEx will set fahrenheit to 1 if the locale on this computer
|
||||
// uses the United States measurement system or 0 otherwise.
|
||||
if (GetLocaleInfo(
|
||||
LOCALE_USER_DEFAULT, LOCALE_IMEASURE | LOCALE_RETURN_NUMBER, reinterpret_cast<LPSTR>(&fahrenheit),
|
||||
sizeof(fahrenheit))
|
||||
if (GetLocaleInfoEx(
|
||||
LOCALE_NAME_USER_DEFAULT, LOCALE_IMEASURE | LOCALE_RETURN_NUMBER, reinterpret_cast<LPWSTR>(&fahrenheit),
|
||||
sizeof(fahrenheit) / sizeof(wchar_t))
|
||||
== 0)
|
||||
{
|
||||
// Assume celsius by default if function call fails
|
||||
return TemperatureUnit::Celsius;
|
||||
}
|
||||
|
||||
if (fahrenheit)
|
||||
return TemperatureUnit::Fahrenheit;
|
||||
|
||||
return TemperatureUnit::Celsius;
|
||||
return fahrenheit == 1 ? TemperatureUnit::Fahrenheit : TemperatureUnit::Celsius;
|
||||
}
|
||||
|
||||
bool ProcessIsElevated()
|
||||
@@ -817,18 +786,15 @@ namespace Platform
|
||||
|
||||
bool EnsureDirectoryExists(u8string_view path)
|
||||
{
|
||||
if (Path::DirectoryExists(path))
|
||||
return 1;
|
||||
|
||||
auto wPath = String::ToWideChar(path);
|
||||
auto success = CreateDirectoryW(wPath.c_str(), nullptr);
|
||||
return success != FALSE;
|
||||
return success != FALSE || GetLastError() == ERROR_ALREADY_EXISTS;
|
||||
}
|
||||
|
||||
bool LockSingleInstance()
|
||||
{
|
||||
// Check if operating system mutex exists
|
||||
HANDLE mutex = CreateMutex(nullptr, FALSE, SINGLE_INSTANCE_MUTEX_NAME);
|
||||
HANDLE mutex = CreateMutexW(nullptr, FALSE, SINGLE_INSTANCE_MUTEX_NAME);
|
||||
if (mutex == nullptr)
|
||||
{
|
||||
log_error("unable to create mutex");
|
||||
@@ -902,11 +868,11 @@ namespace Platform
|
||||
{
|
||||
// [hRootKey\openrct2]
|
||||
HKEY hClassKey;
|
||||
if (RegCreateKeyA(hRootKey, "openrct2", &hClassKey) == ERROR_SUCCESS)
|
||||
if (RegCreateKeyW(hRootKey, L"openrct2", &hClassKey) == ERROR_SUCCESS)
|
||||
{
|
||||
if (RegSetValueA(hClassKey, nullptr, REG_SZ, "URL:openrct2", 0) == ERROR_SUCCESS)
|
||||
if (RegSetValueW(hClassKey, nullptr, REG_SZ, L"URL:openrct2", 0) == ERROR_SUCCESS)
|
||||
{
|
||||
if (RegSetKeyValueA(hClassKey, nullptr, "URL Protocol", REG_SZ, "", 0) == ERROR_SUCCESS)
|
||||
if (RegSetKeyValueW(hClassKey, nullptr, L"URL Protocol", REG_SZ, "", 0) == ERROR_SUCCESS)
|
||||
{
|
||||
// [hRootKey\openrct2\shell\open\command]
|
||||
wchar_t exePath[MAX_PATH];
|
||||
|
||||
Reference in New Issue
Block a user