diff --git a/src/System.Management.Automation/engine/hostifaces/NativeCultureResolver.cs b/src/System.Management.Automation/engine/hostifaces/NativeCultureResolver.cs deleted file mode 100644 index 1c6779a0f3..0000000000 --- a/src/System.Management.Automation/engine/hostifaces/NativeCultureResolver.cs +++ /dev/null @@ -1,489 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -/********************************************************************++ - -Description: - -Windows Vista and later support non-traditional UI fallback ie., a -user on an Arabic machine can choose either French or English(US) as -UI fallback language. - -CLR does not support this (non-traditional) fallback mechanism. So -the static methods in this class calculate appropriate UI Culture -natively. ConsoleHot uses this API to set correct Thread UICulture. - -Dependent on: -GetThreadPreferredUILanguages -SetThreadPreferredUILanguages - -These methods are available on Windows Vista and later. - ---********************************************************************/ - -using System; -using System.Globalization; -using System.Runtime.InteropServices; -using System.Text; -using Dbg = System.Management.Automation.Diagnostics; -using WORD = System.UInt16; - -namespace Microsoft.PowerShell -{ - /// - /// Custom culture. - /// - internal class VistaCultureInfo : CultureInfo - { - private string[] _fallbacks; - // Cache the immediate parent and immediate fallback - private VistaCultureInfo _parentCI = null; - private object _syncObject = new object(); - - /// - /// Constructs a CultureInfo that keeps track of fallbacks. - /// - /// Name of the culture to construct. - /// - /// ordered,null-delimited list of fallbacks - /// - public VistaCultureInfo(string name, - string[] fallbacks) - : base(name) - { - _fallbacks = fallbacks; - } - - /// - /// Returns Parent culture for the current CultureInfo. - /// If Parent.Name is null or empty, then chooses the immediate fallback - /// If it is not empty, otherwise just returns Parent. - /// - public override CultureInfo Parent - { - get - { - // First traverse the parent hierarchy as established by CLR. - // This is required because there is difference in the parent hierarchy - // between CLR and Windows for Chinese. Ex: Native windows has - // zh-CN->zh-Hans->neutral whereas CLR has zh-CN->zh-CHS->zh-Hans->neutral - if ((base.Parent != null) && (!string.IsNullOrEmpty(base.Parent.Name))) - { - return ImmediateParent; - } - - // Check whether we have any fallback specified - // MUI_MERGE_SYSTEM_FALLBACK | MUI_MERGE_USER_FALLBACK - // returns fallback cultures (specified by the user) - // and also adds neutral culture where appropriate. - // Ex: ja-jp ja en-us en - while ((_fallbacks != null) && (_fallbacks.Length > 0)) - { - string fallback = _fallbacks[0]; - string[] fallbacksForParent = null; - - if (_fallbacks.Length > 1) - { - fallbacksForParent = new string[_fallbacks.Length - 1]; - Array.Copy(_fallbacks, 1, fallbacksForParent, 0, _fallbacks.Length - 1); - } - - try - { - return new VistaCultureInfo(fallback, fallbacksForParent); - } - // if there is any exception constructing the culture..catch..and go to - // the next culture in the list. - catch (ArgumentException) - { - _fallbacks = fallbacksForParent; - } - } - - // no fallbacks..just return base parent - return base.Parent; - } - } - - /// - /// This is called to create the parent culture (as defined by CLR) - /// of the current culture. - /// - private VistaCultureInfo ImmediateParent - { - get - { - if (_parentCI == null) - { - lock (_syncObject) - { - if (_parentCI == null) - { - string parentCulture = base.Parent.Name; - // remove the parentCulture from the m_fallbacks list. - // ie., remove duplicates from the parent hierarchy. - string[] fallbacksForTheParent = null; - if (_fallbacks != null) - { - fallbacksForTheParent = new string[_fallbacks.Length]; - int currentIndex = 0; - foreach (string culture in _fallbacks) - { - if (!parentCulture.Equals(culture, StringComparison.OrdinalIgnoreCase)) - { - fallbacksForTheParent[currentIndex] = culture; - currentIndex++; - } - } - - // There is at least 1 duplicate in m_fallbacks which was not added to - // fallbacksForTheParent array. Resize the array to take care of this. - if (_fallbacks.Length != currentIndex) - { - Array.Resize(ref fallbacksForTheParent, currentIndex); - } - } - - _parentCI = new VistaCultureInfo(parentCulture, fallbacksForTheParent); - } - } - } - - return _parentCI; - } - } - - /// - /// Clones the custom CultureInfo retaining the fallbacks. - /// - /// Cloned custom CultureInfo. - public override object Clone() - { - return new VistaCultureInfo(base.Name, _fallbacks); - } - } - - /// - /// Static wrappers to get User chosen UICulture (for Vista and later) - /// - internal static class NativeCultureResolver - { - private static CultureInfo s_uiCulture = null; - private static CultureInfo s_culture = null; - private static object s_syncObject = new object(); - - /// - /// Gets the UICulture to be used by console host. - /// - internal static CultureInfo UICulture - { - get - { - if (s_uiCulture == null) - { - lock (s_syncObject) - { - if (s_uiCulture == null) - { - s_uiCulture = GetUICulture(); - } - } - } - - return (CultureInfo)s_uiCulture.Clone(); - } - } - - internal static CultureInfo Culture - { - get - { - if (s_culture == null) - { - lock (s_syncObject) - { - if (s_culture == null) - { - s_culture = GetCulture(); - } - } - } - - return s_culture; - } - } - - internal static CultureInfo GetUICulture() - { - return GetUICulture(true); - } - - internal static CultureInfo GetCulture() - { - return GetCulture(true); - } - - internal static CultureInfo GetUICulture(bool filterOutNonConsoleCultures) - { - if (!IsVistaAndLater()) - { - s_uiCulture = EmulateDownLevel(); - return s_uiCulture; - } - - // We are running on Vista - string langBuffer = GetUserPreferredUILangs(filterOutNonConsoleCultures); - if (!string.IsNullOrEmpty(langBuffer)) - { - try - { - string[] fallbacks = langBuffer.Split('\0', StringSplitOptions.RemoveEmptyEntries); - string fallback = fallbacks[0]; - string[] fallbacksForParent = null; - - if (fallbacks.Length > 1) - { - fallbacksForParent = new string[fallbacks.Length - 1]; - Array.Copy(fallbacks, 1, fallbacksForParent, 0, fallbacks.Length - 1); - } - - s_uiCulture = new VistaCultureInfo(fallback, fallbacksForParent); - return s_uiCulture; - } - catch (ArgumentException) - { - } - } - - s_uiCulture = EmulateDownLevel(); - return s_uiCulture; - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("GoldMan", "#pw17903:UseOfLCID", Justification = "In XP and below GetUserDefaultLocaleName is not available")] - internal static CultureInfo GetCulture(bool filterOutNonConsoleCultures) - { - CultureInfo returnValue; - try - { - if (!IsVistaAndLater()) - { - int lcid = GetUserDefaultLCID(); - returnValue = new CultureInfo(lcid); - } - else - { - // Vista and above - StringBuilder name = new StringBuilder(16); - if (0 == GetUserDefaultLocaleName(name, 16)) - { - // ther is an error retrieving the culture, - // just use the current thread's culture - returnValue = CultureInfo.CurrentCulture; - } - else - { - returnValue = new CultureInfo(name.ToString().Trim()); - } - } - - if (filterOutNonConsoleCultures) - { - // filter out languages that console cannot display.. - // Sometimes GetConsoleFallbackUICulture returns neutral cultures - // like "en" on "ar-SA". However neutral culture cannot be - // assigned as CurrentCulture. CreateSpecificCulture fixes - // this problem. - returnValue = CultureInfo.CreateSpecificCulture( - returnValue.GetConsoleFallbackUICulture().Name); - } - } - catch (ArgumentException) - { - // if there is any exception retrieving the - // culture, just use the current thread's culture. - returnValue = CultureInfo.CurrentCulture; - } - - return returnValue; - } - - [DllImport("kernel32.dll", SetLastError = false, CharSet = CharSet.Unicode)] - internal static extern WORD GetUserDefaultUILanguage(); - - /// - /// Constructs CultureInfo object without considering any Vista and later - /// custom culture fallback logic. - /// - /// A CultureInfo object. - [System.Diagnostics.CodeAnalysis.SuppressMessage("GoldMan", "#pw17903:UseOfLCID", Justification = "This is only called In XP and below where GetUserDefaultLocaleName is not available, or as a fallback when GetThreadPreferredUILanguages fails")] - private static CultureInfo EmulateDownLevel() - { - // GetConsoleFallbackUICulture is not required. - // This is retained in order not to break existing code. - ushort langId = NativeCultureResolver.GetUserDefaultUILanguage(); - CultureInfo ci = new CultureInfo((int)langId); - return ci.GetConsoleFallbackUICulture(); - } - - /// - /// Checks if the current operating system is Vista or later. - /// - /// - /// true, if vista and above - /// false, otherwise. - /// - private static bool IsVistaAndLater() - { - // The version number is obtained from MSDN - // 4 - Windows NT 4.0, Windows Me, Windows 98, or Windows 95. - // 5 - Windows Server 2003 R2, Windows Server 2003, Windows XP, or Windows 2000. - // 6 - Windows Vista or Windows Server "Longhorn". - - if (Environment.OSVersion.Version.Major >= 6) - { - return true; - } - - return false; - } - - /// - /// This method is called on vista and above. - /// Using GetThreadPreferredUILanguages this method gets - /// the UI languages a user has chosen. - /// - /// - /// List of ThreadPreferredUILanguages. - /// - /// - /// This method will work only on Vista and later. - /// - private static string GetUserPreferredUILangs(bool filterOutNonConsoleCultures) - { - long numberLangs = 0; - int bufferSize = 0; - string returnval = string.Empty; - - if (filterOutNonConsoleCultures) - { - // Filter out languages that do not support console. - // The third parameter should be null otherwise this API will not - // set Console CodePage filter. - // The MSDN documentation does not call this out explicitly. Opened - // Bug 950 (Windows Developer Content) to track this. - if (!SetThreadPreferredUILanguages(s_MUI_CONSOLE_FILTER, null, IntPtr.Zero)) - { - return returnval; - } - } - - // calculate buffer size required - // MUI_MERGE_SYSTEM_FALLBACK | MUI_MERGE_USER_FALLBACK - // returns fallback cultures (specified by the user) - // and also adds neutral culture where appropriate. - // Ex: ja-jp ja en-us en - if (!GetThreadPreferredUILanguages( - s_MUI_LANGUAGE_NAME | s_MUI_MERGE_SYSTEM_FALLBACK | s_MUI_MERGE_USER_FALLBACK, - out numberLangs, - null, - out bufferSize)) - { - return returnval; - } - - // calculate space required to store output. - // StringBuilder will not work for this case as CLR - // does not copy the entire string if there are delimiter ('\0') - // in the middle of a string. - byte[] langBufferPtr = new byte[bufferSize * 2]; - - // Now get the actual value - if (!GetThreadPreferredUILanguages( - s_MUI_LANGUAGE_NAME | s_MUI_MERGE_SYSTEM_FALLBACK | s_MUI_MERGE_USER_FALLBACK, - out numberLangs, - langBufferPtr, // Pointer to a buffer in which this function retrieves an ordered, null-delimited list. - out bufferSize)) - { - return returnval; - } - - try - { - string langBuffer = Encoding.Unicode.GetString(langBufferPtr); - returnval = langBuffer.Trim().ToLowerInvariant(); - return returnval; - } - catch (ArgumentNullException) - { - } - catch (System.Text.DecoderFallbackException) - { - } - - return returnval; - } - - #region Dll Import data - - /// - /// Returns the locale identifier for the user default locale. - /// - /// - /// - /// This function can return data from custom locales. Locales are not - /// guaranteed to be the same from computer to computer or between runs - /// of an application. If your application must persist or transmit data, - /// see Using Persistent Locale Data. - /// Applications that are intended to run only on Windows Vista and later - /// should use GetUserDefaultLocaleName in preference to this function. - /// GetUserDefaultLocaleName provides good support for supplemental locales. - /// However, GetUserDefaultLocaleName is not supported for versions of Windows - /// prior to Windows Vista. - /// - [DllImport("kernel32.dll", SetLastError = false, CharSet = CharSet.Unicode)] - private static extern int GetUserDefaultLCID(); - - /// - /// Retrieves the user default locale name. - /// - /// - /// - /// - /// Returns the size of the buffer containing the locale name, including - /// the terminating null character, if successful. The function returns 0 - /// if it does not succeed. To get extended error information, the application - /// can call GetLastError. Possible returns from GetLastError - /// include ERR_INSUFFICIENT_BUFFER. - /// - /// - /// - [DllImport("kernel32.dll", SetLastError = false, CharSet = CharSet.Unicode)] - private static extern int GetUserDefaultLocaleName( - [MarshalAs(UnmanagedType.LPWStr)] - StringBuilder lpLocaleName, - int cchLocaleName); - - [DllImport("kernel32.dll", SetLastError = false, CharSet = CharSet.Unicode)] - private static extern bool SetThreadPreferredUILanguages(int dwFlags, - StringBuilder pwszLanguagesBuffer, - IntPtr pulNumLanguages); - - [DllImport("kernel32.dll", SetLastError = false, CharSet = CharSet.Unicode)] - private static extern bool GetThreadPreferredUILanguages(int dwFlags, - out long pulNumLanguages, - [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] - byte[] pwszLanguagesBuffer, - out int pcchLanguagesBuffer); - - [DllImport("kernel32.dll", SetLastError = false, CharSet = CharSet.Unicode)] - internal static extern Int16 SetThreadUILanguage(Int16 langId); - - // private static int MUI_LANGUAGE_ID = 0x4; - private static int s_MUI_LANGUAGE_NAME = 0x8; - private static int s_MUI_CONSOLE_FILTER = 0x100; - private static int s_MUI_MERGE_USER_FALLBACK = 0x20; - private static int s_MUI_MERGE_SYSTEM_FALLBACK = 0x10; - - #endregion - } -}