<!-- On Nano these are stubs that return failure -->
user32.dll!GetProcessWindowStation
user32.dll!GetUserObjectInformationW
+
+<!-- GetGeoInfo is supported by the analyzer complain for nit using GetGeoInfoW instead and we need to keep the style of not using 'W' in the names -->
+kernel32.dll!GetGeoInfo
\ No newline at end of file
internal const uint TIME_NOSECONDS = 0x00000002;
+ internal const int GEOCLASS_NATION = 16;
+ internal const int GEO_ISO2 = 4;
+ internal const int GEOID_NOT_AVAILABLE = -1;
+
internal const string LOCALE_NAME_USER_DEFAULT = null;
internal const string LOCALE_NAME_SYSTEM_DEFAULT = "!x-sys-default-locale";
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
internal static extern int GetCalendarInfoEx(string? lpLocaleName, uint Calendar, IntPtr lpReserved, uint CalType, IntPtr lpCalData, int cchData, IntPtr lpValue);
+ [DllImport("kernel32.dll")]
+ internal static extern int GetUserGeoID(int geoClass);
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
+ internal static extern int GetGeoInfo(int location, int geoType, char* lpGeoData, int cchData, int LangId);
+
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
internal static extern bool EnumCalendarInfoExEx(EnumCalendarInfoProcExEx pCalInfoEnumProcExEx, string lpLocaleName, uint Calendar, string? lpReserved, uint CalType, void* lParam);
public static bool IsArgIteratorSupported => IsMonoRuntime || (IsWindows && IsNotArmProcess);
public static bool IsArgIteratorNotSupported => !IsArgIteratorSupported;
public static bool Is32BitProcess => IntPtr.Size == 4;
+ public static bool IsNotWindows => !IsWindows;
// Please make sure that you have the libgdiplus dependency installed.
// For details, see https://docs.microsoft.com/dotnet/core/install/dependencies?pivots=os-macos&tabs=netcore31#libgdiplus
private static bool GetIsRunningOnMonoInterpreter()
{
// This is a temporary solution because mono does not support interpreter detection
- // within the runtime.
+ // within the runtime.
var val = Environment.GetEnvironmentVariable("MONO_ENV_OPTIONS");
return (val != null && val.Contains("--interpreter"));
}
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
+using Microsoft.DotNet.RemoteExecutor;
using System.Text;
using Xunit;
[Fact]
public void ClearCachedDataTest()
{
- CultureInfo ci = CultureInfo.GetCultureInfo("ja-JP");
- Assert.True((object) ci == (object) CultureInfo.GetCultureInfo("ja-JP"), "Expected getting same object reference");
- ci.ClearCachedData();
- Assert.False((object) ci == (object) CultureInfo.GetCultureInfo("ja-JP"), "expected to get a new object reference");
+ RemoteExecutor.Invoke(() =>
+ {
+ CultureInfo ci = CultureInfo.GetCultureInfo("ja-JP");
+ Assert.True((object) ci == (object) CultureInfo.GetCultureInfo("ja-JP"), "Expected getting same object reference");
+ ci.ClearCachedData();
+ Assert.False((object) ci == (object) CultureInfo.GetCultureInfo("ja-JP"), "expected to get a new object reference");
+ }).Dispose();
}
[Fact]
AssertExtensions.Throws<ArgumentException>("name", () => new RegionInfo(name));
}
- [Fact]
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows))]
public void CurrentRegion()
{
using (new ThreadCultureChange("en-US"))
}
}
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows))]
+ public void TestCurrentRegion()
+ {
+ RemoteExecutor.Invoke(() =>
+ {
+ RegionInfo ri = RegionInfo.CurrentRegion;
+ CultureInfo.CurrentCulture.ClearCachedData(); // clear the current region cached data
+
+ CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("ja-JP");
+
+ // Changing the current culture shouldn't affect the default current region as we get it from Windows settings.
+ Assert.Equal(ri.TwoLetterISORegionName, RegionInfo.CurrentRegion.TwoLetterISORegionName);
+ }).Dispose();
+ }
+
[Theory]
[InlineData("en-US", "United States")]
[OuterLoop("May fail on machines with multiple language packs installed")] // see https://github.com/dotnet/runtime/issues/30132
internal bool IsWin32Installed => false;
internal bool IsReplacementCulture => false;
+
+ internal static CultureData GetCurrentRegionData() => CultureInfo.CurrentCulture._cultureData;
}
}
using System.Diagnostics.CodeAnalysis;
using System.Text;
using Internal.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
namespace System.Globalization
{
return false;
}
}
+
+ internal static unsafe CultureData GetCurrentRegionData()
+ {
+ Span<char> geoIso2Letters = stackalloc char[10];
+
+ int geoId = Interop.Kernel32.GetUserGeoID(Interop.Kernel32.GEOCLASS_NATION);
+ if (geoId != Interop.Kernel32.GEOID_NOT_AVAILABLE)
+ {
+ int geoIsoIdLength;
+ fixed (char* pGeoIsoId = geoIso2Letters)
+ {
+ geoIsoIdLength = Interop.Kernel32.GetGeoInfo(geoId, Interop.Kernel32.GEO_ISO2, pGeoIsoId, geoIso2Letters.Length, 0);
+ }
+
+ if (geoIsoIdLength != 0)
+ {
+ geoIsoIdLength -= geoIso2Letters[geoIsoIdLength - 1] == 0 ? 1 : 0; // handle null termination and exclude it.
+ CultureData? cd = GetCultureDataForRegion(geoIso2Letters.Slice(0, geoIsoIdLength).ToString(), true);
+ if (cd != null)
+ {
+ return cd;
+ }
+ }
+ }
+
+ // Fallback to current locale data.
+ return CultureInfo.CurrentCulture._cultureData;
+ }
}
}
/// </remarks>
private static Dictionary<string, string> RegionNames =>
s_regionNames ??=
- new Dictionary<string, string>(211 /* prime */)
+ new Dictionary<string, string>(257 /* prime */)
{
+ { "001", "en-001" },
{ "029", "en-029" },
+ { "150", "en-150" },
+ { "419", "es-419" },
+ { "AD", "ca-AD" },
{ "AE", "ar-AE" },
{ "AF", "prs-AF" },
+ { "AG", "en-AG" },
+ { "AI", "en-AI" },
{ "AL", "sq-AL" },
{ "AM", "hy-AM" },
+ { "AO", "pt-AO" },
+ { "AQ", "en-A" },
{ "AR", "es-AR" },
+ { "AS", "en-AS" },
{ "AT", "de-AT" },
{ "AU", "en-AU" },
+ { "AW", "nl-AW" },
+ { "AX", "sv-AX" },
{ "AZ", "az-Cyrl-AZ" },
{ "BA", "bs-Latn-BA" },
+ { "BB", "en-BB" },
{ "BD", "bn-BD" },
{ "BE", "nl-BE" },
+ { "BF", "fr-BF" },
{ "BG", "bg-BG" },
{ "BH", "ar-BH" },
+ { "BI", "rn-BI" },
+ { "BJ", "fr-BJ" },
+ { "BL", "fr-BL" },
+ { "BM", "en-BM" },
{ "BN", "ms-BN" },
{ "BO", "es-BO" },
+ { "BQ", "nl-BQ" },
{ "BR", "pt-BR" },
+ { "BS", "en-BS" },
+ { "BT", "dz-BT" },
+ { "BV", "nb-B" },
+ { "BW", "en-BW" },
{ "BY", "be-BY" },
{ "BZ", "en-BZ" },
{ "CA", "en-CA" },
+ { "CC", "en-CC" },
+ { "CD", "fr-CD" },
+ { "CF", "sg-CF" },
+ { "CG", "fr-CG" },
{ "CH", "it-CH" },
+ { "CI", "fr-CI" },
+ { "CK", "en-CK" },
{ "CL", "es-CL" },
+ { "CM", "fr-C" },
{ "CN", "zh-CN" },
{ "CO", "es-CO" },
{ "CR", "es-CR" },
{ "CS", "sr-Cyrl-CS" },
+ { "CU", "es-CU" },
+ { "CV", "pt-CV" },
+ { "CW", "nl-CW" },
+ { "CX", "en-CX" },
+ { "CY", "el-CY" },
{ "CZ", "cs-CZ" },
{ "DE", "de-DE" },
+ { "DJ", "fr-DJ" },
{ "DK", "da-DK" },
+ { "DM", "en-DM" },
{ "DO", "es-DO" },
{ "DZ", "ar-DZ" },
{ "EC", "es-EC" },
{ "EE", "et-EE" },
{ "EG", "ar-EG" },
+ { "ER", "tig-ER" },
{ "ES", "es-ES" },
{ "ET", "am-ET" },
{ "FI", "fi-FI" },
+ { "FJ", "en-FJ" },
+ { "FK", "en-FK" },
+ { "FM", "en-FM" },
{ "FO", "fo-FO" },
{ "FR", "fr-FR" },
+ { "GA", "fr-GA" },
{ "GB", "en-GB" },
+ { "GD", "en-GD" },
{ "GE", "ka-GE" },
+ { "GF", "fr-GF" },
+ { "GG", "en-GG" },
+ { "GH", "en-GH" },
+ { "GI", "en-GI" },
{ "GL", "kl-GL" },
+ { "GM", "en-GM" },
+ { "GN", "fr-GN" },
+ { "GP", "fr-GP" },
+ { "GQ", "es-GQ" },
{ "GR", "el-GR" },
+ { "GS", "en-G" },
{ "GT", "es-GT" },
+ { "GU", "en-GU" },
+ { "GW", "pt-GW" },
+ { "GY", "en-GY" },
{ "HK", "zh-HK" },
+ { "HM", "en-H" },
{ "HN", "es-HN" },
{ "HR", "hr-HR" },
+ { "HT", "fr-HT" },
{ "HU", "hu-HU" },
{ "ID", "id-ID" },
{ "IE", "en-IE" },
{ "IL", "he-IL" },
+ { "IM", "gv-IM" },
{ "IN", "hi-IN" },
+ { "IO", "en-IO" },
{ "IQ", "ar-IQ" },
{ "IR", "fa-IR" },
{ "IS", "is-IS" },
{ "IT", "it-IT" },
{ "IV", "" },
+ { "JE", "en-JE" },
{ "JM", "en-JM" },
{ "JO", "ar-JO" },
{ "JP", "ja-JP" },
{ "KE", "sw-KE" },
{ "KG", "ky-KG" },
{ "KH", "km-KH" },
+ { "KI", "en-KI" },
+ { "KM", "ar-KM" },
+ { "KN", "en-KN" },
+ { "KP", "ko-KP" },
{ "KR", "ko-KR" },
{ "KW", "ar-KW" },
+ { "KY", "en-KY" },
{ "KZ", "kk-KZ" },
{ "LA", "lo-LA" },
{ "LB", "ar-LB" },
+ { "LC", "en-LC" },
{ "LI", "de-LI" },
{ "LK", "si-LK" },
+ { "LR", "en-LR" },
+ { "LS", "st-LS" },
{ "LT", "lt-LT" },
{ "LU", "lb-LU" },
{ "LV", "lv-LV" },
{ "LY", "ar-LY" },
{ "MA", "ar-MA" },
{ "MC", "fr-MC" },
+ { "MD", "ro-MD" },
{ "ME", "sr-Latn-ME" },
+ { "MF", "fr-MF" },
+ { "MG", "mg-MG" },
+ { "MH", "en-MH" },
{ "MK", "mk-MK" },
+ { "ML", "fr-ML" },
+ { "MM", "my-MM" },
{ "MN", "mn-MN" },
{ "MO", "zh-MO" },
+ { "MP", "en-MP" },
+ { "MQ", "fr-MQ" },
+ { "MR", "ar-MR" },
+ { "MS", "en-MS" },
{ "MT", "mt-MT" },
+ { "MU", "en-MU" },
{ "MV", "dv-MV" },
+ { "MW", "en-MW" },
{ "MX", "es-MX" },
{ "MY", "ms-MY" },
+ { "MZ", "pt-MZ" },
+ { "NA", "en-NA" },
+ { "NC", "fr-NC" },
+ { "NE", "fr-NE" },
+ { "NF", "en-NF" },
{ "NG", "ig-NG" },
{ "NI", "es-NI" },
{ "NL", "nl-NL" },
{ "NO", "nn-NO" },
{ "NP", "ne-NP" },
+ { "NR", "en-NR" },
+ { "NU", "en-NU" },
{ "NZ", "en-NZ" },
{ "OM", "ar-OM" },
{ "PA", "es-PA" },
{ "PE", "es-PE" },
+ { "PF", "fr-PF" },
+ { "PG", "en-PG" },
{ "PH", "en-PH" },
{ "PK", "ur-PK" },
{ "PL", "pl-PL" },
+ { "PM", "fr-PM" },
+ { "PN", "en-PN" },
{ "PR", "es-PR" },
+ { "PS", "ar-PS" },
{ "PT", "pt-PT" },
+ { "PW", "en-PW" },
{ "PY", "es-PY" },
{ "QA", "ar-QA" },
+ { "RE", "fr-RE" },
{ "RO", "ro-RO" },
{ "RS", "sr-Latn-RS" },
{ "RU", "ru-RU" },
{ "RW", "rw-RW" },
{ "SA", "ar-SA" },
+ { "SB", "en-SB" },
+ { "SC", "fr-SC" },
+ { "SD", "ar-SD" },
{ "SE", "sv-SE" },
{ "SG", "zh-SG" },
+ { "SH", "en-SH" },
{ "SI", "sl-SI" },
+ { "SJ", "nb-SJ" },
{ "SK", "sk-SK" },
+ { "SL", "en-SL" },
+ { "SM", "it-SM" },
{ "SN", "wo-SN" },
+ { "SO", "so-SO" },
+ { "SR", "nl-SR" },
+ { "SS", "en-SS" },
+ { "ST", "pt-ST" },
{ "SV", "es-SV" },
+ { "SX", "nl-SX" },
{ "SY", "ar-SY" },
+ { "SZ", "ss-SZ" },
+ { "TC", "en-TC" },
+ { "TD", "fr-TD" },
+ { "TF", "fr-T" },
+ { "TG", "fr-TG" },
{ "TH", "th-TH" },
{ "TJ", "tg-Cyrl-TJ" },
+ { "TK", "en-TK" },
+ { "TL", "pt-TL" },
{ "TM", "tk-TM" },
{ "TN", "ar-TN" },
+ { "TO", "to-TO" },
{ "TR", "tr-TR" },
{ "TT", "en-TT" },
+ { "TV", "en-TV" },
{ "TW", "zh-TW" },
+ { "TZ", "sw-TZ" },
{ "UA", "uk-UA" },
+ { "UG", "sw-UG" },
+ { "UM", "en-UM" },
{ "US", "en-US" },
{ "UY", "es-UY" },
{ "UZ", "uz-Cyrl-UZ" },
+ { "VA", "it-VA" },
+ { "VC", "en-VC" },
{ "VE", "es-VE" },
+ { "VG", "en-VG" },
+ { "VI", "en-VI" },
{ "VN", "vi-VN" },
+ { "VU", "fr-VU" },
+ { "WF", "fr-WF" },
+ { "WS", "en-WS" },
+ { "XK", "sq-XK" },
{ "YE", "ar-YE" },
+ { "YT", "fr-YT" },
{ "ZA", "af-ZA" },
+ { "ZM", "en-ZM" },
{ "ZW", "en-ZW" }
};
RegionInfo? temp = s_currentRegionInfo;
if (temp == null)
{
- temp = new RegionInfo(CultureInfo.CurrentCulture._cultureData);
+ temp = new RegionInfo(CultureData.GetCurrentRegionData());
// Need full name for custom cultures
temp._name = temp._cultureData.RegionName;