Change reading time zone display names (#56171)
authorTarek Mahmoud Sayed <tarekms@microsoft.com>
Fri, 23 Jul 2021 16:36:39 +0000 (09:36 -0700)
committerGitHub <noreply@github.com>
Fri, 23 Jul 2021 16:36:39 +0000 (09:36 -0700)
src/libraries/Common/src/Interop/Windows/Kernel32/Interop.MUI.cs [deleted file]
src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs
src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Win32.cs
src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.cs

diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.MUI.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.MUI.cs
deleted file mode 100644 (file)
index 779d26d..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Runtime.InteropServices;
-
-internal static partial class Interop
-{
-    internal static partial class Kernel32
-    {
-        internal const uint MUI_USER_PREFERRED_UI_LANGUAGES = 0x10;
-        internal const uint MUI_USE_INSTALLED_LANGUAGES = 0x20;
-
-        [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]
-        internal static extern unsafe bool GetFileMUIPath(uint dwFlags, string pcwszFilePath, char* pwszLanguage, ref uint pcchLanguage, char* pwszFileMUIPath, ref uint pcchFileMUIPath, ref ulong pululEnumerator);
-    }
-}
index 2c67834..df824ab 100644 (file)
     <Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.MEMORYSTATUSEX.cs">
       <Link>Common\Interop\Windows\Kernel32\Interop.MEMORYSTATUSEX.cs</Link>
     </Compile>
-    <Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.MUI.cs">
-      <Link>Common\Interop\Windows\Kernel32\Interop.MUI.cs</Link>
-    </Compile>
     <Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.MultiByteToWideChar.cs">
       <Link>Common\Interop\Windows\Kernel32\Interop.MultiByteToWideChar.cs</Link>
     </Compile>
index 6221957..9c470c8 100644 (file)
@@ -32,8 +32,6 @@ namespace System
             "Zulu"
         };
 
-        private static readonly TimeZoneInfo s_utcTimeZone = CreateUtcTimeZone();
-
         private TimeZoneInfo(byte[] data, string id, bool dstDisabled)
         {
             _id = id;
index 30862ef..7bdfce0 100644 (file)
@@ -35,9 +35,6 @@ namespace System
         private const int MaxKeyLength = 255;
         private const string InvariantUtcStandardDisplayName = "Coordinated Universal Time";
 
-        private static readonly Dictionary<string, string> s_fileMuiPathCache = new();
-        private static readonly TimeZoneInfo s_utcTimeZone = CreateUtcTimeZone(); // must be initialized after s_fileMuiPathCache
-
         private sealed partial class CachedData
         {
             private static TimeZoneInfo GetCurrentOneYearLocal()
@@ -738,115 +735,12 @@ namespace System
             }
         }
 
-        /// <summary>
-        /// Helper function for getting the MUI path for a given resource and culture, using a cache to prevent duplicating work.
-        /// Searches the installed OS languages for either an exact matching culture, or one that has the same parent.
-        /// If not found, uses the preferred default OS UI language, to align with prior behavior.
-        /// </summary>
-        private static string GetCachedFileMuiPath(string filePath, CultureInfo cultureInfo)
-        {
-            string? result;
-            string cacheKey = $"{cultureInfo.Name};{filePath}";
-
-            lock (s_fileMuiPathCache)
-            {
-                if (s_fileMuiPathCache.TryGetValue(cacheKey, out result))
-                {
-                    return result;
-                }
-            }
-
-            result = GetFileMuiPath(filePath, cultureInfo);
-
-            lock (s_fileMuiPathCache)
-            {
-                s_fileMuiPathCache.TryAdd(cacheKey, result);
-            }
-
-            return result;
-        }
 
         /// <summary>
-        /// Helper function for getting the MUI path for a given resource and culture.
-        /// Searches the installed OS languages for either an exact matching culture, or one that has the same parent.
-        /// If not found, uses the preferred default OS UI language, to align with prior behavior.
-        /// </summary>
-        private static unsafe string GetFileMuiPath(string filePath, CultureInfo cultureInfo)
-        {
-            char* fileMuiPath = stackalloc char[Interop.Kernel32.MAX_PATH + 1];
-            char* language = stackalloc char[Interop.Kernel32.LOCALE_NAME_MAX_LENGTH + 1];
-            uint fileMuiPathLength = Interop.Kernel32.MAX_PATH;
-            uint languageLength = Interop.Kernel32.LOCALE_NAME_MAX_LENGTH;
-            ulong enumerator = 0;
-
-            while (true)
-            {
-                // Search all installed languages.  The enumerator is re-used between loop iterations.
-                language[0] = '\0';
-                bool succeeded = Interop.Kernel32.GetFileMUIPath(
-                    Interop.Kernel32.MUI_USE_INSTALLED_LANGUAGES,
-                    filePath, language, ref languageLength,
-                    fileMuiPath, ref fileMuiPathLength, ref enumerator);
-                fileMuiPath[Interop.Kernel32.MAX_PATH] = '\0';
-
-                if (!succeeded)
-                {
-                    // Recurse to search using the parent of the desired culture.
-                    if (cultureInfo.Parent.Name != string.Empty)
-                    {
-                        return GetFileMuiPath(filePath, cultureInfo.Parent);
-                    }
-
-                    // Final fallback, using the preferred installed UI language.
-                    enumerator = 0;
-                    language[0] = '\0';
-                    succeeded = Interop.Kernel32.GetFileMUIPath(
-                        Interop.Kernel32.MUI_USER_PREFERRED_UI_LANGUAGES,
-                        filePath, language, ref languageLength,
-                        fileMuiPath, ref fileMuiPathLength, ref enumerator);
-                    fileMuiPath[Interop.Kernel32.MAX_PATH] = '\0';
-
-                    if (succeeded)
-                    {
-                        return new string(fileMuiPath);
-                    }
-
-                    return string.Empty;
-                }
-
-                // Lookup succeeded.  Check for exact match to the desired culture.
-                language[Interop.Kernel32.LOCALE_NAME_MAX_LENGTH] = '\0';
-                ReadOnlySpan<char> lang = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(language);
-                if (lang.Equals(cultureInfo.Name, StringComparison.OrdinalIgnoreCase))
-                {
-                    return new string(fileMuiPath);
-                }
-
-                // Check for match of any parent of the language returned to the desired culture.
-                var ci = CultureInfo.GetCultureInfo(lang.ToString());
-                while (ci.Parent.Name != string.Empty)
-                {
-                    if (ci.Parent.Name.Equals(cultureInfo.Name, StringComparison.OrdinalIgnoreCase))
-                    {
-                        return new string(fileMuiPath);
-                    }
-
-                    ci = ci.Parent;
-                }
-
-                // Not found yet.  Continue with next iteration.
-            }
-        }
-
-        /// <summary>
-        /// Helper function for retrieving a localized string resource via MUI.
-        /// The function expects a string in the form: "@resource.dll, -123"
-        ///
-        /// "resource.dll" is a language-neutral portable executable (LNPE) file in
-        /// the %windir%\system32 directory.  The OS is queried to find the best-fit
-        /// localized resource file for this LNPE (ex: %windir%\system32\en-us\resource.dll.mui).
-        /// If a localized resource file exists, we LoadString resource ID "123" and
-        /// return it to our caller.
+        /// Try to find the time zone resources Dll matching the CurrentUICulture or one of its parent cultures.
+        /// We try to check of such resource module e.g. %windir%\system32\[UI Culture Name]\tzres.dll.mui exist.
+        /// If a localized resource file exists, we LoadString resource with the id specified inside resource input
+        /// string and and return it to our caller.
         /// </summary>
         private static string GetLocalizedNameByMuiNativeResource(string resource)
         {
@@ -855,9 +749,6 @@ namespace System
                 return string.Empty;
             }
 
-            // Use the current UI culture when culture not specified
-            CultureInfo cultureInfo = CultureInfo.CurrentUICulture;
-
             // parse "@tzres.dll, -100"
             //
             // filePath   = "C:\Windows\System32\tzres.dll"
@@ -869,41 +760,42 @@ namespace System
                 return string.Empty;
             }
 
-            string filePath;
+            // Get the resource ID
+            if (!int.TryParse(resources[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out int resourceId))
+            {
+                return string.Empty;
+            }
+            resourceId = -resourceId;
+
+            // Use the current UI culture when culture not specified
+            CultureInfo cultureInfo = CultureInfo.CurrentUICulture;
 
             // get the path to Windows\System32
             string system32 = Environment.SystemDirectory;
 
-            // trim the string "@tzres.dll" => "tzres.dll"
-            ReadOnlySpan<char> tzresDll = resources[0].AsSpan().TrimStart('@');
+            // trim the string "@tzres.dll" to "tzres.dll" and append the "mui" file extension to it.
+            string tzresDll = $"{resources[0].AsSpan().TrimStart('@')}.mui";
 
             try
             {
-                filePath = Path.Join(system32, tzresDll);
+                while (cultureInfo.Name.Length != 0)
+                {
+                    string filePath = Path.Join(system32, cultureInfo.Name, tzresDll);
+                    if (File.Exists(filePath))
+                    {
+                        // Finally, get the resource from the resource path
+                        return GetLocalizedNameByNativeResource(filePath, resourceId);
+                    }
+
+                    cultureInfo = cultureInfo.Parent;
+                }
             }
             catch (ArgumentException)
             {
                 // there were probably illegal characters in the path
-                return string.Empty;
-            }
-
-            // Get the MUI File Path
-            string fileMuiPath = GetCachedFileMuiPath(filePath, cultureInfo);
-            if (fileMuiPath == string.Empty)
-            {
-                // not likely, but we could not resolve a MUI path
-                return string.Empty;
             }
 
-            // Get the resource ID
-            if (!int.TryParse(resources[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out int resourceId))
-            {
-                return string.Empty;
-            }
-            resourceId = -resourceId;
-
-            // Finally, get the resource from the resource path
-            return GetLocalizedNameByNativeResource(fileMuiPath, resourceId);
+            return string.Empty;
         }
 
         /// <summary>
index 89844b5..32ed950 100644 (file)
@@ -53,6 +53,7 @@ namespace System
         private const string UtcId = "UTC";
         private const string LocalId = "Local";
 
+        private static readonly TimeZoneInfo s_utcTimeZone = CreateUtcTimeZone();
         private static CachedData s_cachedData = new CachedData();
 
         //