Move TimeZoneInfo.Win32.cs to shared CoreLib partition (#15953)
authorJan Kotas <jkotas@microsoft.com>
Mon, 22 Jan 2018 21:30:20 +0000 (13:30 -0800)
committerGitHub <noreply@github.com>
Mon, 22 Jan 2018 21:30:20 +0000 (13:30 -0800)
Reconcile deltas with CoreRT and refactor interop to follow coding conventions

src/mscorlib/Resources/Strings.resx
src/mscorlib/System.Private.CoreLib.csproj
src/mscorlib/shared/Interop/Windows/Kernel32/Interop.MUI.cs [new file with mode: 0644]
src/mscorlib/shared/Interop/Windows/Kernel32/Interop.TimeZone.Registry.cs [new file with mode: 0644]
src/mscorlib/shared/Interop/Windows/Kernel32/Interop.TimeZone.cs [new file with mode: 0644]
src/mscorlib/shared/System.Private.CoreLib.Shared.projitems
src/mscorlib/shared/System/TimeZoneInfo.Win32.cs [moved from src/mscorlib/src/System/TimeZoneInfo.Win32.cs with 86% similarity]
src/mscorlib/src/Microsoft/Win32/UnsafeNativeMethods.cs
src/mscorlib/src/Microsoft/Win32/Win32Native.cs

index c69dae6..585cbc7 100644 (file)
   <data name="Argument_InvalidPathChars" xml:space="preserve">
     <value>Illegal characters in path.</value>
   </data>
-  <data name="Argument_InvalidREG_TZI_FORMAT" xml:space="preserve">
-    <value>The REG_TZI_FORMAT structure is corrupt.</value>
-  </data>
   <data name="Argument_InvalidRegistryViewCheck" xml:space="preserve">
     <value>The specified RegistryView value is invalid.</value>
   </data>
   <data name="IO_InvalidReadLength" xml:space="preserve">
     <value>The read operation returned an invalid length.</value>
   </data>
-</root>
\ No newline at end of file
+</root>
index dcfe620..904bb48 100644 (file)
     <Compile Include="$(BclSourcesRoot)\System\Globalization\GlobalizationMode.Windows.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Threading\ClrThreadPoolBoundHandle.Windows.cs" />
     <Compile Include="$(BclSourcesRoot)\System\Environment.Windows.cs" />
-    <Compile Include="$(BclSourcesRoot)\System\TimeZoneInfo.Win32.cs" />
   </ItemGroup>
   <!-- Include additional sources shared files in the compilation -->
   <ItemGroup>
diff --git a/src/mscorlib/shared/Interop/Windows/Kernel32/Interop.MUI.cs b/src/mscorlib/shared/Interop/Windows/Kernel32/Interop.MUI.cs
new file mode 100644 (file)
index 0000000..6ed7aa2
--- /dev/null
@@ -0,0 +1,18 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+
+internal static partial class Interop
+{
+    internal static partial class Kernel32
+    {
+        internal const uint MUI_PREFERRED_UI_LANGUAGES = 0x10;
+
+        [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]
+        internal static extern bool GetFileMUIPath(uint flags, String filePath, [Out] StringBuilder language, ref int languageLength, [Out] StringBuilder fileMuiPath, ref int fileMuiPathLength, ref Int64 enumerator);
+    }
+}
diff --git a/src/mscorlib/shared/Interop/Windows/Kernel32/Interop.TimeZone.Registry.cs b/src/mscorlib/shared/Interop/Windows/Kernel32/Interop.TimeZone.Registry.cs
new file mode 100644 (file)
index 0000000..062d1ca
--- /dev/null
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal static partial class Interop
+{
+    internal static partial class Kernel32
+    {
+        [StructLayout(LayoutKind.Sequential)]
+        internal struct REG_TZI_FORMAT
+        {
+            internal int Bias;
+            internal int StandardBias;
+            internal int DaylightBias;
+            internal SYSTEMTIME StandardDate;
+            internal SYSTEMTIME DaylightDate;
+
+            internal REG_TZI_FORMAT(in TIME_ZONE_INFORMATION tzi)
+            {
+                Bias = tzi.Bias;
+                StandardDate = tzi.StandardDate;
+                StandardBias = tzi.StandardBias;
+                DaylightDate = tzi.DaylightDate;
+                DaylightBias = tzi.DaylightBias;
+            }
+        }
+    }
+}
diff --git a/src/mscorlib/shared/Interop/Windows/Kernel32/Interop.TimeZone.cs b/src/mscorlib/shared/Interop/Windows/Kernel32/Interop.TimeZone.cs
new file mode 100644 (file)
index 0000000..05f13ac
--- /dev/null
@@ -0,0 +1,94 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal static partial class Interop
+{
+    internal static partial class Kernel32
+    {
+        internal struct SYSTEMTIME
+        {
+            internal ushort Year;
+            internal ushort Month;
+            internal ushort DayOfWeek;
+            internal ushort Day;
+            internal ushort Hour;
+            internal ushort Minute;
+            internal ushort Second;
+            internal ushort Milliseconds;
+
+            internal bool Equals(in SYSTEMTIME other) =>
+                    Year == other.Year &&
+                    Month == other.Month &&
+                    DayOfWeek == other.DayOfWeek &&
+                    Day == other.Day &&
+                    Hour == other.Hour &&
+                    Minute == other.Minute &&
+                    Second == other.Second &&
+                    Milliseconds == other.Milliseconds;
+        }
+
+        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+        internal unsafe struct TIME_DYNAMIC_ZONE_INFORMATION
+        {
+            internal int Bias;
+            internal fixed char StandardName[32];
+            internal SYSTEMTIME StandardDate;
+            internal int StandardBias;
+            internal fixed char DaylightName[32];
+            internal SYSTEMTIME DaylightDate;
+            internal int DaylightBias;
+            internal fixed char TimeZoneKeyName[128];
+            internal byte DynamicDaylightTimeDisabled;
+
+            internal string GetTimeZoneKeyName()
+            {
+                fixed (char* p = TimeZoneKeyName)
+                    return new string(p);
+            }
+        }
+
+        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+        internal unsafe struct TIME_ZONE_INFORMATION
+        {
+            internal int Bias;
+            internal fixed char StandardName[32];
+            internal SYSTEMTIME StandardDate;
+            internal int StandardBias;
+            internal fixed char DaylightName[32];
+            internal SYSTEMTIME DaylightDate;
+            internal int DaylightBias;
+
+            internal TIME_ZONE_INFORMATION(in TIME_DYNAMIC_ZONE_INFORMATION dtzi)
+            {
+                // The start of TIME_DYNAMIC_ZONE_INFORMATION has identical layout as TIME_ZONE_INFORMATION
+                fixed (TIME_ZONE_INFORMATION* pTo = &this)
+                fixed (TIME_DYNAMIC_ZONE_INFORMATION* pFrom = &dtzi)
+                    *pTo = *(TIME_ZONE_INFORMATION*)pFrom;
+            }
+
+            internal string GetStandardName()
+            {
+                fixed (char* p = StandardName)
+                    return new string(p);
+            }
+
+            internal string GetDaylightName()
+            {
+                fixed (char* p = DaylightName)
+                    return new string(p);
+            }
+        }
+
+        internal const uint TIME_ZONE_ID_INVALID = unchecked((uint)-1);
+
+        [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]
+        internal extern static uint GetDynamicTimeZoneInformation(out TIME_DYNAMIC_ZONE_INFORMATION pTimeZoneInformation);
+
+        [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]
+        internal static extern uint GetTimeZoneInformation(out TIME_ZONE_INFORMATION lpTimeZoneInformation);
+    }
+}
index 9819da7..bfe1eec 100644 (file)
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.WriteFile_SafeHandle_NativeOverlapped.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Normaliz\Interop.Idna.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Normaliz\Interop.Normalization.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
+    <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.TimeZone.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\OleAut32\Interop.SysAllocStringLen.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\OleAut32\Interop.SysFreeString.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\OleAut32\Interop.SysStringLen.cs" />
   </ItemGroup>
   <ItemGroup Condition="$(TargetsWindows) and '$(EnableWinRT)' != 'true'">
     <Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Win32.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)System\TimeZoneInfo.Win32.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeLibraryHandle.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.LoadLibraryEx.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.FreeLibrary.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.CreateFile.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.MUI.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.TimeZone.Registry.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\User32\Interop.Constants.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\User32\Interop.SendMessageTimeout.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\User32\Interop.LoadString.cs" />
@@ -12,9 +12,12 @@ using System.Threading;
 
 using Microsoft.Win32;
 using Microsoft.Win32.SafeHandles;
-using REG_TZI_FORMAT = Microsoft.Win32.Win32Native.RegistryTimeZoneInformation;
-using TIME_ZONE_INFORMATION = Microsoft.Win32.Win32Native.TimeZoneInformation;
-using TIME_DYNAMIC_ZONE_INFORMATION = Microsoft.Win32.Win32Native.DynamicTimeZoneInformation;
+
+using Internal.Runtime.CompilerServices;
+
+using REG_TZI_FORMAT = Interop.Kernel32.REG_TZI_FORMAT;
+using TIME_ZONE_INFORMATION = Interop.Kernel32.TIME_ZONE_INFORMATION;
+using TIME_DYNAMIC_ZONE_INFORMATION = Interop.Kernel32.TIME_DYNAMIC_ZONE_INFORMATION;
 
 namespace System
 {
@@ -34,7 +37,6 @@ namespace System
         private const string LastEntryValue = "LastEntry";
 
         private const int MaxKeyLength = 255;
-        private const int RegByteLength = 44;
 
 #pragma warning disable 0420
         private sealed partial class CachedData
@@ -43,8 +45,8 @@ namespace System
             {
                 // load the data from the OS
                 TIME_ZONE_INFORMATION timeZoneInformation;
-                long result = UnsafeNativeMethods.GetTimeZoneInformation(out timeZoneInformation);
-                return result == Win32Native.TIME_ZONE_ID_INVALID ?
+                uint result = Interop.Kernel32.GetTimeZoneInformation(out timeZoneInformation);
+                return result == Interop.Kernel32.TIME_ZONE_ID_INVALID ?
                     CreateCustomTimeZone(LocalId, TimeSpan.Zero, LocalId, LocalId) :
                     GetLocalTimeZoneFromWin32Data(timeZoneInformation, dstDisabled: false);
             }
@@ -113,13 +115,14 @@ namespace System
 
         private TimeZoneInfo(in TIME_ZONE_INFORMATION zone, bool dstDisabled)
         {
-            if (string.IsNullOrEmpty(zone.StandardName))
+            string standardName = zone.GetStandardName();
+            if (standardName.Length == 0)
             {
                 _id = LocalId;  // the ID must contain at least 1 character - initialize _id to "Local"
             }
             else
             {
-                _id = zone.StandardName;
+                _id = standardName;
             }
             _baseUtcOffset = new TimeSpan(0, -(zone.Bias), 0);
 
@@ -130,15 +133,14 @@ namespace System
                 AdjustmentRule rule = CreateAdjustmentRuleFromTimeZoneInformation(regZone, DateTime.MinValue.Date, DateTime.MaxValue.Date, zone.Bias);
                 if (rule != null)
                 {
-                    _adjustmentRules = new AdjustmentRule[1];
-                    _adjustmentRules[0] = rule;
+                    _adjustmentRules = new[] { rule };
                 }
             }
 
             ValidateTimeZoneInfo(_id, _baseUtcOffset, _adjustmentRules, out _supportsDaylightSavingTime);
-            _displayName = zone.StandardName;
-            _standardDisplayName = zone.StandardName;
-            _daylightDisplayName = zone.DaylightName;
+            _displayName = standardName;
+            _standardDisplayName = standardName;
+            _daylightDisplayName = zone.GetDaylightName();
         }
 
         /// <summary>
@@ -147,14 +149,7 @@ namespace System
         /// This check is only meant to be used for "Local".
         /// </summary>
         private static bool CheckDaylightSavingTimeNotSupported(in TIME_ZONE_INFORMATION timeZone) =>
-            timeZone.DaylightDate.Year == timeZone.StandardDate.Year &&
-            timeZone.DaylightDate.Month == timeZone.StandardDate.Month &&
-            timeZone.DaylightDate.DayOfWeek == timeZone.StandardDate.DayOfWeek &&
-            timeZone.DaylightDate.Day == timeZone.StandardDate.Day &&
-            timeZone.DaylightDate.Hour == timeZone.StandardDate.Hour &&
-            timeZone.DaylightDate.Minute == timeZone.StandardDate.Minute &&
-            timeZone.DaylightDate.Second == timeZone.StandardDate.Second &&
-            timeZone.DaylightDate.Milliseconds == timeZone.StandardDate.Milliseconds;
+            timeZone.DaylightDate.Equals(timeZone.StandardDate);
 
         /// <summary>
         /// Converts a REG_TZI_FORMAT struct to an AdjustmentRule.
@@ -255,32 +250,31 @@ namespace System
             var dynamicTimeZoneInformation = new TIME_DYNAMIC_ZONE_INFORMATION();
 
             // call kernel32!GetDynamicTimeZoneInformation...
-            int result = UnsafeNativeMethods.GetDynamicTimeZoneInformation(out dynamicTimeZoneInformation);
-            if (result == Win32Native.TIME_ZONE_ID_INVALID)
+            uint result = Interop.Kernel32.GetDynamicTimeZoneInformation(out dynamicTimeZoneInformation);
+            if (result == Interop.Kernel32.TIME_ZONE_ID_INVALID)
             {
                 // return a dummy entry
                 return CreateCustomTimeZone(LocalId, TimeSpan.Zero, LocalId, LocalId);
             }
 
-            var timeZoneInformation = new TIME_ZONE_INFORMATION(dynamicTimeZoneInformation);
-
-            bool dstDisabled = dynamicTimeZoneInformation.DynamicDaylightTimeDisabled;
-
             // check to see if we can use the key name returned from the API call
-            if (!string.IsNullOrEmpty(dynamicTimeZoneInformation.TimeZoneKeyName))
+            string dynamicTimeZoneKeyName = dynamicTimeZoneInformation.GetTimeZoneKeyName();
+            if (dynamicTimeZoneKeyName.Length != 0)
             {
                 TimeZoneInfo zone;
                 Exception ex;
 
-                if (TryGetTimeZone(dynamicTimeZoneInformation.TimeZoneKeyName, dstDisabled, out zone, out ex, cachedData) == TimeZoneInfoResult.Success)
+                if (TryGetTimeZone(dynamicTimeZoneKeyName, dynamicTimeZoneInformation.DynamicDaylightTimeDisabled != 0, out zone, out ex, cachedData) == TimeZoneInfoResult.Success)
                 {
                     // successfully loaded the time zone from the registry
                     return zone;
                 }
             }
 
+            var timeZoneInformation = new TIME_ZONE_INFORMATION(dynamicTimeZoneInformation);
+
             // the key name was not returned or it pointed to a bogus entry - search for the entry ourselves
-            string id = FindIdFromTimeZoneInformation(timeZoneInformation, out dstDisabled);
+            string id = FindIdFromTimeZoneInformation(timeZoneInformation, out bool dstDisabled);
 
             if (id != null)
             {
@@ -350,7 +344,7 @@ namespace System
             {
                 throw new ArgumentNullException(nameof(id));
             }
-            else if (id.Length == 0 || id.Length > MaxKeyLength || id.Contains('\0'))
+            if (id.Length == 0 || id.Length > MaxKeyLength || id.Contains('\0'))
             {
                 throw new TimeZoneNotFoundException(SR.Format(SR.TimeZoneNotFound_MissingData, id));
             }
@@ -533,6 +527,7 @@ namespace System
         /// </summary>
         private static bool TryCreateAdjustmentRules(string id, in REG_TZI_FORMAT defaultTimeZoneInformation, out AdjustmentRule[] rules, out Exception e, int defaultBaseUtcOffset)
         {
+            rules = null;
             e = null;
 
             try
@@ -564,7 +559,10 @@ namespace System
                     {
                         AdjustmentRule rule = CreateAdjustmentRuleFromTimeZoneInformation(
                             defaultTimeZoneInformation, DateTime.MinValue.Date, DateTime.MaxValue.Date, defaultBaseUtcOffset);
-                        rules = rule == null ? null : new[] { rule };
+                        if (rule != null)
+                        {
+                            rules = new[] { rule };
+                        }
                         return true;
                     }
 
@@ -581,25 +579,25 @@ namespace System
 
                     if (first == -1 || last == -1 || first > last)
                     {
-                        rules = null;
                         return false;
                     }
 
                     // read the first year entry
                     REG_TZI_FORMAT dtzi;
-                    byte[] regValue = dynamicKey.GetValue(first.ToString(CultureInfo.InvariantCulture), null, RegistryValueOptions.None) as byte[];
-                    if (regValue == null || regValue.Length != RegByteLength)
+
+                    if (!TryGetTimeZoneEntryFromRegistry(dynamicKey, first.ToString(CultureInfo.InvariantCulture), out dtzi))
                     {
-                        rules = null;
                         return false;
                     }
-                    dtzi = new REG_TZI_FORMAT(regValue);
 
                     if (first == last)
                     {
                         // there is just 1 dynamic rule for this time zone.
                         AdjustmentRule rule = CreateAdjustmentRuleFromTimeZoneInformation(dtzi, DateTime.MinValue.Date, DateTime.MaxValue.Date, defaultBaseUtcOffset);
-                        rules = rule == null ? null : new[] { rule };
+                        if (rule != null)
+                        {
+                            rules = new[] { rule };
+                        }
                         return true;
                     }
 
@@ -620,13 +618,10 @@ namespace System
                     // read the middle year entries
                     for (int i = first + 1; i < last; i++)
                     {
-                        regValue = dynamicKey.GetValue(i.ToString(CultureInfo.InvariantCulture), null, RegistryValueOptions.None) as byte[];
-                        if (regValue == null || regValue.Length != RegByteLength)
+                        if (!TryGetTimeZoneEntryFromRegistry(dynamicKey, i.ToString(CultureInfo.InvariantCulture), out dtzi))
                         {
-                            rules = null;
                             return false;
                         }
-                        dtzi = new REG_TZI_FORMAT(regValue);
                         AdjustmentRule middleRule = CreateAdjustmentRuleFromTimeZoneInformation(
                             dtzi,
                             new DateTime(i, 1, 1),    // January  01, <Year>
@@ -640,11 +635,8 @@ namespace System
                     }
 
                     // read the last year entry
-                    regValue = dynamicKey.GetValue(last.ToString(CultureInfo.InvariantCulture), null, RegistryValueOptions.None) as byte[];
-                    dtzi = new REG_TZI_FORMAT(regValue);
-                    if (regValue == null || regValue.Length != RegByteLength)
+                    if (!TryGetTimeZoneEntryFromRegistry(dynamicKey, last.ToString(CultureInfo.InvariantCulture), out dtzi))
                     {
-                        rules = null;
                         return false;
                     }
                     AdjustmentRule lastRule = CreateAdjustmentRuleFromTimeZoneInformation(
@@ -658,36 +650,45 @@ namespace System
                         rulesList.Add(lastRule);
                     }
 
-                    // convert the ArrayList to an AdjustmentRule array
-                    rules = rulesList.ToArray();
-                    if (rules != null && rules.Length == 0)
+                    // convert the List to an AdjustmentRule array
+                    if (rulesList.Count != 0)
                     {
-                        rules = null;
+                        rules = rulesList.ToArray();
                     }
                 } // end of: using (RegistryKey dynamicKey...
             }
             catch (InvalidCastException ex)
             {
                 // one of the RegistryKey.GetValue calls could not be cast to an expected value type
-                rules = null;
                 e = ex;
                 return false;
             }
             catch (ArgumentOutOfRangeException ex)
             {
-                rules = null;
                 e = ex;
                 return false;
             }
             catch (ArgumentException ex)
             {
-                rules = null;
                 e = ex;
                 return false;
             }
             return true;
         }
 
+        private unsafe static bool TryGetTimeZoneEntryFromRegistry(RegistryKey key, string name, out REG_TZI_FORMAT dtzi)
+        {
+            byte[] regValue = key.GetValue(name, null, RegistryValueOptions.None) as byte[];
+            if (regValue == null || regValue.Length != sizeof(REG_TZI_FORMAT))
+            {
+                dtzi = default;
+                return false;
+            }
+            fixed (byte * pBytes = &regValue[0])
+                dtzi = *(REG_TZI_FORMAT *)pBytes;
+            return true;
+        }
+
         /// <summary>
         /// Helper function that compares the StandardBias and StandardDate portion a
         /// TimeZoneInformation struct to a time zone registry entry.
@@ -695,14 +696,7 @@ namespace System
         private static bool TryCompareStandardDate(in TIME_ZONE_INFORMATION timeZone, in REG_TZI_FORMAT registryTimeZoneInfo) =>
             timeZone.Bias == registryTimeZoneInfo.Bias &&
             timeZone.StandardBias == registryTimeZoneInfo.StandardBias &&
-            timeZone.StandardDate.Year == registryTimeZoneInfo.StandardDate.Year &&
-            timeZone.StandardDate.Month == registryTimeZoneInfo.StandardDate.Month &&
-            timeZone.StandardDate.DayOfWeek == registryTimeZoneInfo.StandardDate.DayOfWeek &&
-            timeZone.StandardDate.Day == registryTimeZoneInfo.StandardDate.Day &&
-            timeZone.StandardDate.Hour == registryTimeZoneInfo.StandardDate.Hour &&
-            timeZone.StandardDate.Minute == registryTimeZoneInfo.StandardDate.Minute &&
-            timeZone.StandardDate.Second == registryTimeZoneInfo.StandardDate.Second &&
-            timeZone.StandardDate.Milliseconds == registryTimeZoneInfo.StandardDate.Milliseconds;
+            timeZone.StandardDate.Equals(registryTimeZoneInfo.StandardDate);
 
         /// <summary>
         /// Helper function that compares a TimeZoneInformation struct to a time zone registry entry.
@@ -719,9 +713,10 @@ namespace System
                 }
 
                 REG_TZI_FORMAT registryTimeZoneInfo;
-                byte[] regValue = key.GetValue(TimeZoneInfoValue, null, RegistryValueOptions.None) as byte[];
-                if (regValue == null || regValue.Length != RegByteLength) return false;
-                registryTimeZoneInfo = new REG_TZI_FORMAT(regValue);
+                if (!TryGetTimeZoneEntryFromRegistry(key, TimeZoneInfoValue, out registryTimeZoneInfo))
+                {
+                    return false;
+                }
 
                 //
                 // first compare the bias and standard date information between the data from the Win32 API
@@ -740,14 +735,7 @@ namespace System
                     // the Win32 API data and the registry data ...
                     //
                     (timeZone.DaylightBias == registryTimeZoneInfo.DaylightBias &&
-                    timeZone.DaylightDate.Year == registryTimeZoneInfo.DaylightDate.Year &&
-                    timeZone.DaylightDate.Month == registryTimeZoneInfo.DaylightDate.Month &&
-                    timeZone.DaylightDate.DayOfWeek == registryTimeZoneInfo.DaylightDate.DayOfWeek &&
-                    timeZone.DaylightDate.Day == registryTimeZoneInfo.DaylightDate.Day &&
-                    timeZone.DaylightDate.Hour == registryTimeZoneInfo.DaylightDate.Hour &&
-                    timeZone.DaylightDate.Minute == registryTimeZoneInfo.DaylightDate.Minute &&
-                    timeZone.DaylightDate.Second == registryTimeZoneInfo.DaylightDate.Second &&
-                    timeZone.DaylightDate.Milliseconds == registryTimeZoneInfo.DaylightDate.Milliseconds);
+                    timeZone.DaylightDate.Equals(registryTimeZoneInfo.DaylightDate));
 
                 // Finally compare the "StandardName" string value...
                 //
@@ -757,7 +745,7 @@ namespace System
                 if (result)
                 {
                     string registryStandardName = key.GetValue(StandardValue, string.Empty, RegistryValueOptions.None) as string;
-                    result = string.Equals(registryStandardName, timeZone.StandardName, StringComparison.Ordinal);
+                    result = string.Equals(registryStandardName, timeZone.GetStandardName(), StringComparison.Ordinal);
                 }
                 return result;
             }
@@ -819,12 +807,13 @@ namespace System
             try
             {
                 StringBuilder fileMuiPath = StringBuilderCache.Acquire(Interop.Kernel32.MAX_PATH);
+                fileMuiPath.Length = Interop.Kernel32.MAX_PATH;
                 int fileMuiPathLength = Interop.Kernel32.MAX_PATH;
                 int languageLength = 0;
                 long enumerator = 0;
 
-                bool succeeded = UnsafeNativeMethods.GetFileMUIPath(
-                                        Win32Native.MUI_PREFERRED_UI_LANGUAGES,
+                bool succeeded = Interop.Kernel32.GetFileMUIPath(
+                                        Interop.Kernel32.MUI_PREFERRED_UI_LANGUAGES,
                                         filePath, null /* language */, ref languageLength,
                                         fileMuiPath, ref fileMuiPathLength, ref enumerator);
                 if (!succeeded)
@@ -877,7 +866,7 @@ namespace System
         /// resource dll(s).  When the keys do not exist, the function falls back to reading from the standard
         /// key-values
         /// </summary>
-        private static bool TryGetLocalizedNamesByRegistryKey(RegistryKey key, out string displayName, out string standardName, out string daylightName)
+        private static void GetLocalizedNamesByRegistryKey(RegistryKey key, out string displayName, out string standardName, out string daylightName)
         {
             displayName = string.Empty;
             standardName = string.Empty;
@@ -917,8 +906,6 @@ namespace System
             {
                 daylightName = key.GetValue(DaylightValue, string.Empty, RegistryValueOptions.None) as string;
             }
-
-            return true;
         }
 
         /// <summary>
@@ -963,14 +950,12 @@ namespace System
                 }
 
                 REG_TZI_FORMAT defaultTimeZoneInformation;
-                byte[] regValue = key.GetValue(TimeZoneInfoValue, null, RegistryValueOptions.None) as byte[];
-                if (regValue == null || regValue.Length != RegByteLength)
+                if (!TryGetTimeZoneEntryFromRegistry(key, TimeZoneInfoValue, out defaultTimeZoneInformation))
                 {
                     // the registry value could not be cast to a byte array
                     value = null;
                     return TimeZoneInfoResult.InvalidTimeZoneException;
                 }
-                defaultTimeZoneInformation = new REG_TZI_FORMAT(regValue);
 
                 AdjustmentRule[] adjustmentRules;
                 if (!TryCreateAdjustmentRules(id, defaultTimeZoneInformation, out adjustmentRules, out e, defaultTimeZoneInformation.Bias))
@@ -979,15 +964,7 @@ namespace System
                     return TimeZoneInfoResult.InvalidTimeZoneException;
                 }
 
-                string displayName;
-                string standardName;
-                string daylightName;
-
-                if (!TryGetLocalizedNamesByRegistryKey(key, out displayName, out standardName, out daylightName))
-                {
-                    value = null;
-                    return TimeZoneInfoResult.InvalidTimeZoneException;
-                }
+                GetLocalizedNamesByRegistryKey(key, out string displayName, out string standardName, out string daylightName);
 
                 try
                 {
index 6ce6263..c0e016d 100644 (file)
@@ -13,37 +13,6 @@ namespace Microsoft.Win32
 
     internal static class UnsafeNativeMethods
     {
-        [DllImport(Interop.Libraries.Kernel32, EntryPoint = "GetTimeZoneInformation", SetLastError = true, ExactSpelling = true)]
-        internal static extern int GetTimeZoneInformation(out Win32Native.TimeZoneInformation lpTimeZoneInformation);
-
-        [DllImport(Interop.Libraries.Kernel32, EntryPoint = "GetDynamicTimeZoneInformation", SetLastError = true, ExactSpelling = true)]
-        internal static extern int GetDynamicTimeZoneInformation(out Win32Native.DynamicTimeZoneInformation lpDynamicTimeZoneInformation);
-
-        // 
-        // BOOL GetFileMUIPath(
-        //   DWORD  dwFlags,
-        //   PCWSTR  pcwszFilePath,
-        //   PWSTR  pwszLanguage,
-        //   PULONG  pcchLanguage,
-        //   PWSTR  pwszFileMUIPath,
-        //   PULONG  pcchFileMUIPath,
-        //   PULONGLONG  pululEnumerator
-        // );
-        // 
-        [DllImport(Interop.Libraries.Kernel32, EntryPoint = "GetFileMUIPath", SetLastError = true, ExactSpelling = true)]
-        [return: MarshalAs(UnmanagedType.Bool)]
-        internal static extern bool GetFileMUIPath(
-                                     int flags,
-                                     [MarshalAs(UnmanagedType.LPWStr)]
-                                     String filePath,
-                                     [MarshalAs(UnmanagedType.LPWStr)]
-                                     StringBuilder language,
-                                     ref int languageLength,
-                                     [Out, MarshalAs(UnmanagedType.LPWStr)]
-                                     StringBuilder fileMuiPath,
-                                     ref int fileMuiPathLength,
-                                     ref Int64 enumerator);
-
         internal static unsafe class ManifestEtw
         {
             //
index be86024..a6b28db 100644 (file)
@@ -151,172 +151,6 @@ namespace Microsoft.Win32
         internal const int REG_RESOURCE_REQUIREMENTS_LIST = 10;
         internal const int REG_QWORD = 11;    // 64-bit number
 
-        // TimeZone
-        internal const int TIME_ZONE_ID_INVALID = -1;
-        internal const int TIME_ZONE_ID_UNKNOWN = 0;
-        internal const int TIME_ZONE_ID_STANDARD = 1;
-        internal const int TIME_ZONE_ID_DAYLIGHT = 2;
-        internal const int MAX_PATH = 260;
-
-        internal const int MUI_LANGUAGE_ID = 0x4;
-        internal const int MUI_LANGUAGE_NAME = 0x8;
-        internal const int MUI_PREFERRED_UI_LANGUAGES = 0x10;
-        internal const int MUI_INSTALLED_LANGUAGES = 0x20;
-        internal const int MUI_ALL_LANGUAGES = 0x40;
-        internal const int MUI_LANG_NEUTRAL_PE_FILE = 0x100;
-        internal const int MUI_NON_LANG_NEUTRAL_FILE = 0x200;
-
-        [StructLayout(LayoutKind.Sequential)]
-        internal struct SystemTime
-        {
-            [MarshalAs(UnmanagedType.U2)]
-            public short Year;
-            [MarshalAs(UnmanagedType.U2)]
-            public short Month;
-            [MarshalAs(UnmanagedType.U2)]
-            public short DayOfWeek;
-            [MarshalAs(UnmanagedType.U2)]
-            public short Day;
-            [MarshalAs(UnmanagedType.U2)]
-            public short Hour;
-            [MarshalAs(UnmanagedType.U2)]
-            public short Minute;
-            [MarshalAs(UnmanagedType.U2)]
-            public short Second;
-            [MarshalAs(UnmanagedType.U2)]
-            public short Milliseconds;
-        }
-
-        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
-        internal struct TimeZoneInformation
-        {
-            [MarshalAs(UnmanagedType.I4)]
-            public Int32 Bias;
-            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
-            public string StandardName;
-            public SystemTime StandardDate;
-            [MarshalAs(UnmanagedType.I4)]
-            public Int32 StandardBias;
-            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
-            public string DaylightName;
-            public SystemTime DaylightDate;
-            [MarshalAs(UnmanagedType.I4)]
-            public Int32 DaylightBias;
-
-            public TimeZoneInformation(Win32Native.DynamicTimeZoneInformation dtzi)
-            {
-                Bias = dtzi.Bias;
-                StandardName = dtzi.StandardName;
-                StandardDate = dtzi.StandardDate;
-                StandardBias = dtzi.StandardBias;
-                DaylightName = dtzi.DaylightName;
-                DaylightDate = dtzi.DaylightDate;
-                DaylightBias = dtzi.DaylightBias;
-            }
-        }
-
-
-        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
-        internal struct DynamicTimeZoneInformation
-        {
-            [MarshalAs(UnmanagedType.I4)]
-            public Int32 Bias;
-            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
-            public string StandardName;
-            public SystemTime StandardDate;
-            [MarshalAs(UnmanagedType.I4)]
-            public Int32 StandardBias;
-            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
-            public string DaylightName;
-            public SystemTime DaylightDate;
-            [MarshalAs(UnmanagedType.I4)]
-            public Int32 DaylightBias;
-            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
-            public string TimeZoneKeyName;
-            [MarshalAs(UnmanagedType.Bool)]
-            public bool DynamicDaylightTimeDisabled;
-        }
-
-
-        [StructLayout(LayoutKind.Sequential)]
-        internal struct RegistryTimeZoneInformation
-        {
-            [MarshalAs(UnmanagedType.I4)]
-            public Int32 Bias;
-            [MarshalAs(UnmanagedType.I4)]
-            public Int32 StandardBias;
-            [MarshalAs(UnmanagedType.I4)]
-            public Int32 DaylightBias;
-            public SystemTime StandardDate;
-            public SystemTime DaylightDate;
-
-            public RegistryTimeZoneInformation(Win32Native.TimeZoneInformation tzi)
-            {
-                Bias = tzi.Bias;
-                StandardDate = tzi.StandardDate;
-                StandardBias = tzi.StandardBias;
-                DaylightDate = tzi.DaylightDate;
-                DaylightBias = tzi.DaylightBias;
-            }
-
-            public RegistryTimeZoneInformation(Byte[] bytes)
-            {
-                //
-                // typedef struct _REG_TZI_FORMAT {
-                // [00-03]    LONG Bias;
-                // [04-07]    LONG StandardBias;
-                // [08-11]    LONG DaylightBias;
-                // [12-27]    SYSTEMTIME StandardDate;
-                // [12-13]        WORD wYear;
-                // [14-15]        WORD wMonth;
-                // [16-17]        WORD wDayOfWeek;
-                // [18-19]        WORD wDay;
-                // [20-21]        WORD wHour;
-                // [22-23]        WORD wMinute;
-                // [24-25]        WORD wSecond;
-                // [26-27]        WORD wMilliseconds;
-                // [28-43]    SYSTEMTIME DaylightDate;
-                // [28-29]        WORD wYear;
-                // [30-31]        WORD wMonth;
-                // [32-33]        WORD wDayOfWeek;
-                // [34-35]        WORD wDay;
-                // [36-37]        WORD wHour;
-                // [38-39]        WORD wMinute;
-                // [40-41]        WORD wSecond;
-                // [42-43]        WORD wMilliseconds;
-                // } REG_TZI_FORMAT;
-                //
-                if (bytes == null || bytes.Length != 44)
-                {
-                    throw new ArgumentException(SR.Argument_InvalidREG_TZI_FORMAT, nameof(bytes));
-                }
-                Bias = BitConverter.ToInt32(bytes, 0);
-                StandardBias = BitConverter.ToInt32(bytes, 4);
-                DaylightBias = BitConverter.ToInt32(bytes, 8);
-
-                StandardDate.Year = BitConverter.ToInt16(bytes, 12);
-                StandardDate.Month = BitConverter.ToInt16(bytes, 14);
-                StandardDate.DayOfWeek = BitConverter.ToInt16(bytes, 16);
-                StandardDate.Day = BitConverter.ToInt16(bytes, 18);
-                StandardDate.Hour = BitConverter.ToInt16(bytes, 20);
-                StandardDate.Minute = BitConverter.ToInt16(bytes, 22);
-                StandardDate.Second = BitConverter.ToInt16(bytes, 24);
-                StandardDate.Milliseconds = BitConverter.ToInt16(bytes, 26);
-
-                DaylightDate.Year = BitConverter.ToInt16(bytes, 28);
-                DaylightDate.Month = BitConverter.ToInt16(bytes, 30);
-                DaylightDate.DayOfWeek = BitConverter.ToInt16(bytes, 32);
-                DaylightDate.Day = BitConverter.ToInt16(bytes, 34);
-                DaylightDate.Hour = BitConverter.ToInt16(bytes, 36);
-                DaylightDate.Minute = BitConverter.ToInt16(bytes, 38);
-                DaylightDate.Second = BitConverter.ToInt16(bytes, 40);
-                DaylightDate.Milliseconds = BitConverter.ToInt16(bytes, 42);
-            }
-        }
-
-        // end of TimeZone 
-
-
         // Win32 ACL-related constants:
         internal const int READ_CONTROL = 0x00020000;
         internal const int SYNCHRONIZE = 0x00100000;