mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
Remove NativeCultureResolver as dead code (#18582)
This commit is contained in:
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom culture.
|
||||
/// </summary>
|
||||
internal class VistaCultureInfo : CultureInfo
|
||||
{
|
||||
private string[] _fallbacks;
|
||||
// Cache the immediate parent and immediate fallback
|
||||
private VistaCultureInfo _parentCI = null;
|
||||
private object _syncObject = new object();
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a CultureInfo that keeps track of fallbacks.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the culture to construct.</param>
|
||||
/// <param name="fallbacks">
|
||||
/// ordered,null-delimited list of fallbacks
|
||||
/// </param>
|
||||
public VistaCultureInfo(string name,
|
||||
string[] fallbacks)
|
||||
: base(name)
|
||||
{
|
||||
_fallbacks = fallbacks;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is called to create the parent culture (as defined by CLR)
|
||||
/// of the current culture.
|
||||
/// </summary>
|
||||
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<string>(ref fallbacksForTheParent, currentIndex);
|
||||
}
|
||||
}
|
||||
|
||||
_parentCI = new VistaCultureInfo(parentCulture, fallbacksForTheParent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _parentCI;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clones the custom CultureInfo retaining the fallbacks.
|
||||
/// </summary>
|
||||
/// <returns>Cloned custom CultureInfo.</returns>
|
||||
public override object Clone()
|
||||
{
|
||||
return new VistaCultureInfo(base.Name, _fallbacks);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Static wrappers to get User chosen UICulture (for Vista and later)
|
||||
/// </summary>
|
||||
internal static class NativeCultureResolver
|
||||
{
|
||||
private static CultureInfo s_uiCulture = null;
|
||||
private static CultureInfo s_culture = null;
|
||||
private static object s_syncObject = new object();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the UICulture to be used by console host.
|
||||
/// </summary>
|
||||
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();
|
||||
|
||||
/// <summary>
|
||||
/// Constructs CultureInfo object without considering any Vista and later
|
||||
/// custom culture fallback logic.
|
||||
/// </summary>
|
||||
/// <returns>A CultureInfo object.</returns>
|
||||
[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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the current operating system is Vista or later.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true, if vista and above
|
||||
/// false, otherwise.
|
||||
/// </returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is called on vista and above.
|
||||
/// Using GetThreadPreferredUILanguages this method gets
|
||||
/// the UI languages a user has chosen.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// List of ThreadPreferredUILanguages.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This method will work only on Vista and later.
|
||||
/// </remarks>
|
||||
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
|
||||
|
||||
/// <summary>
|
||||
/// Returns the locale identifier for the user default locale.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
[DllImport("kernel32.dll", SetLastError = false, CharSet = CharSet.Unicode)]
|
||||
private static extern int GetUserDefaultLCID();
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the user default locale name.
|
||||
/// </summary>
|
||||
/// <param name="lpLocaleName"></param>
|
||||
/// <param name="cchLocaleName"></param>
|
||||
/// <returns>
|
||||
/// 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.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
[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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user