Remove LCIDToLocaleName P/Invoke from GetComputerInfoCommand (#9716)

- Remove LCIDToLocaleName P/Invoke with StringBuilder
- Reduce allocations by using GetCultureInfo to get cached CultureInfo
- Use UInt32.TryParse to parse Hex
- Minor cleanups after above changes
This commit is contained in:
Ilya 2019-06-25 08:22:00 +05:00 committed by GitHub
parent 17b2cec163
commit e3d8131390
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -5,11 +5,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Diagnostics.CodeAnalysis;
using System.Reflection; using System.Globalization;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Management.Automation; using System.Management.Automation;
using System.Diagnostics.CodeAnalysis; using System.Reflection;
using System.Runtime.InteropServices;
using Microsoft.Management.Infrastructure; using Microsoft.Management.Infrastructure;
using Microsoft.Win32; using Microsoft.Win32;
@ -887,9 +888,8 @@ namespace Microsoft.PowerShell.Commands
// we display info for only one // we display info for only one
string layout = otherInfo.keyboards[0].Layout; string layout = otherInfo.keyboards[0].Layout;
var culture = Conversion.MakeLocale(layout);
output.KeyboardLayout = culture == null ? layout : culture.Name; output.KeyboardLayout = Conversion.GetLocaleName(layout);
} }
if (otherInfo.hyperV != null) if (otherInfo.hyperV != null)
@ -1097,29 +1097,6 @@ namespace Microsoft.PowerShell.Commands
} }
} }
public static string LocaleIdToLocaleName(uint localeID)
{
// CoreCLR's System.Globalization.Culture does not appear to have a constructor
// that accepts an integer LocalID (LCID) value, so we'll PInvoke native code
// to get a locale name from an LCID value
try
{
var sbName = new System.Text.StringBuilder(Native.LOCALE_NAME_MAX_LENGTH);
var len = Native.LCIDToLocaleName(localeID, sbName, sbName.Capacity, 0);
if (len > 0 && sbName.Length > 0)
return sbName.ToString();
}
catch (Exception)
{
// Probably failed to load the DLL or to file the function entry point.
// Fail silently
}
return null;
}
/// <summary> /// <summary>
/// Attempt to create a <see cref="System.Globalization.CultureInfo"/> /// Attempt to create a <see cref="System.Globalization.CultureInfo"/>
/// object from a locale string as retrieved from WMI. /// object from a locale string as retrieved from WMI.
@ -1136,38 +1113,36 @@ namespace Microsoft.PowerShell.Commands
/// Failing that it attempts to retrieve the CultureInfo object /// Failing that it attempts to retrieve the CultureInfo object
/// using the locale string as passed. /// using the locale string as passed.
/// </remarks> /// </remarks>
internal static System.Globalization.CultureInfo MakeLocale(string locale) internal static string GetLocaleName(string locale)
{ {
System.Globalization.CultureInfo culture = null; CultureInfo culture = null;
if (locale != null) if (locale != null)
{ {
try try
{ {
uint localeNum; // The "locale" must contain a hexadecimal value, with no
// base-indication prefix. For example, the string "0409" will be
if (TryParseHex(locale, out localeNum)) // parsed into the base-10 integer value 1033, while the string "0x0409"
// will fail to parse due to the "0x" base-indication prefix.
if (UInt32.TryParse(locale, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint localeNum))
{ {
string localeName = LocaleIdToLocaleName(localeNum); culture = CultureInfo.GetCultureInfo((int)localeNum);
if (localeName != null)
culture = new System.Globalization.CultureInfo(localeName);
} }
if (culture == null) if (culture == null)
{ {
// either the TryParseHex failed, or the LocaleIdToLocaleName // If TryParse failed we'll try using the original string as culture name
// failed, so we'll try using the original string culture = CultureInfo.GetCultureInfo(locale);
culture = new System.Globalization.CultureInfo(locale);
} }
} }
catch (Exception/* ex*/) catch (Exception)
{ {
culture = null; culture = null;
} }
} }
return culture; return culture == null ? null : culture.Name;
} }
/// <summary> /// <summary>
@ -1336,7 +1311,7 @@ namespace Microsoft.PowerShell.Commands
/// <summary> /// <summary>
/// Get a language name from a language identifier. /// Get a language name from a language identifier.
/// </summary> /// </summary>
/// <param name="language"> /// <param name="lcid">
/// A nullable integer containing the language ID for the desired language. /// A nullable integer containing the language ID for the desired language.
/// </param> /// </param>
/// <returns> /// <returns>
@ -1344,10 +1319,18 @@ namespace Microsoft.PowerShell.Commands
/// the language parameter. If the language parameter is null or has a /// the language parameter. If the language parameter is null or has a
/// value that is not a valid language ID, the method returns null. /// value that is not a valid language ID, the method returns null.
/// </returns> /// </returns>
protected static string GetLanguageName(uint? language) protected static string GetLanguageName(uint? lcid)
{ {
if (language != null) if (lcid != null && lcid >= 0)
return Conversion.LocaleIdToLocaleName(language.Value); {
try
{
return CultureInfo.GetCultureInfo((int)lcid.Value).Name;
}
catch
{
}
}
return null; return null;
} }
@ -1896,12 +1879,7 @@ namespace Microsoft.PowerShell.Commands
#region Public Methods #region Public Methods
public string GetLocale() public string GetLocale()
{ {
System.Globalization.CultureInfo culture = null; return Conversion.GetLocaleName(Locale);
if (Locale != null)
culture = Conversion.MakeLocale(Locale);
return culture == null ? null : culture.Name;
} }
#endregion Public Methods #endregion Public Methods
@ -5112,7 +5090,6 @@ namespace Microsoft.PowerShell.Commands
private static class PInvokeDllNames private static class PInvokeDllNames
{ {
public const string GetPhysicallyInstalledSystemMemoryDllName = "api-ms-win-core-sysinfo-l1-2-1.dll"; public const string GetPhysicallyInstalledSystemMemoryDllName = "api-ms-win-core-sysinfo-l1-2-1.dll";
public const string LCIDToLocaleNameDllName = "kernelbase.dll";
public const string PowerDeterminePlatformRoleExDllName = "api-ms-win-power-base-l1-1-0.dll"; public const string PowerDeterminePlatformRoleExDllName = "api-ms-win-power-base-l1-1-0.dll";
public const string GetFirmwareTypeDllName = "api-ms-win-core-kernel32-legacy-l1-1-1"; public const string GetFirmwareTypeDllName = "api-ms-win-core-kernel32-legacy-l1-1-1";
} }
@ -5152,17 +5129,6 @@ namespace Microsoft.PowerShell.Commands
[return: MarshalAs(UnmanagedType.Bool)] [return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetFirmwareType(out FirmwareType firmwareType); public static extern bool GetFirmwareType(out FirmwareType firmwareType);
/// <summary>
/// Convert a Local Identifier to a Locale name.
/// </summary>
/// <param name="localeID">The Locale ID (LCID) to be converted.</param>
/// <param name="localeName">Destination of the Locale name.</param>
/// <param name="localeNameSize">Capacity of <paramref name="localeName"/></param>
/// <param name="flags"></param>
/// <returns></returns>
[DllImport(PInvokeDllNames.LCIDToLocaleNameDllName, SetLastError = true, CharSet = CharSet.Unicode)]
public static extern int LCIDToLocaleName(uint localeID, System.Text.StringBuilder localeName, int localeNameSize, int flags);
/// <summary> /// <summary>
/// Gets the data specified for the passed in property name from the /// Gets the data specified for the passed in property name from the
/// Software Licensing API. /// Software Licensing API.