Skip to content

Commit

Permalink
Update RegionInfo data and Fix RegionInfo.CurrentRegion on Windows (d…
Browse files Browse the repository at this point in the history
…otnet#33834)

* Update RegionInfo data and Fix RegionInfo.CurrentRegion on Windows

* Address the feedback

* feedback

* More Feedback addressing
  • Loading branch information
tarekgh authored Mar 21, 2020
1 parent a43d6c4 commit 3a769f7
Show file tree
Hide file tree
Showing 9 changed files with 199 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ normaliz.dll!NormalizeString
<!-- 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
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ internal static unsafe partial class Kernel32

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";

Expand Down Expand Up @@ -133,6 +137,12 @@ internal static extern bool IsNLSDefinedString(
[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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public static partial class PlatformDetection
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
Expand Down Expand Up @@ -206,7 +207,7 @@ private static bool GetSsl3Support()
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"));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.DotNet.RemoteExecutor;
using System.Text;
using Xunit;

Expand Down Expand Up @@ -631,10 +632,13 @@ public void GetCulturesTest(string cultureName, int lcid, string specificCulture
[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]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public void Ctor_InvalidName_ThrowsArgumentException(string name)
AssertExtensions.Throws<ArgumentException>("name", () => new RegionInfo(name));
}

[Fact]
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows))]
public void CurrentRegion()
{
using (new ThreadCultureChange("en-US"))
Expand All @@ -63,6 +63,21 @@ public void CurrentRegion()
}
}

[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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -418,5 +418,7 @@ private static string GetConsoleFallbackName(string cultureName)
internal bool IsWin32Installed => false;

internal bool IsReplacementCulture => false;

internal static CultureData GetCurrentRegionData() => CultureInfo.CurrentCulture._cultureData;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Text;
using Internal.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace System.Globalization
{
Expand Down Expand Up @@ -714,5 +715,33 @@ internal bool IsReplacementCulture
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;
}
}
}
Loading

0 comments on commit 3a769f7

Please sign in to comment.