Compartir a través de


Cómo: Guardar referencias culturales personalizadas sin privilegios administrativos

En este tema se describe una técnica para guardar datos de referencias culturales personalizados en un archivo sin privilegios de administrador. Una aplicación que se ejecuta con privilegios administrativos registra una referencia cultural personalizada mediante el método CultureAndRegionInfoBuilder.Register, como se describe en el tema Cómo: Crear referencias culturales personalizadas. Internamente, este método llama al método CultureDefinition.Compile, que no requiere privilegios administrativos.

Para guardar las referencias culturales personalizadas sin privilegios administrativos, puede utilizar la reflexión para obtener acceso al método CultureDefinition.Compile directamente.

Nota de precauciónPrecaución

Llamar directamente al método CultureDefinition.Compile no es compatible.El método puede cambiar o incluso eliminarse sin previo aviso.Este tema describe su comportamiento solo para .NET Framework versión 4.El uso incorrecto de este método puede dejar su equipo en un estado inestable, lo que podría producir que se bloqueara la aplicación o que se perdieran datos.

Acerca de CultureDefinition.Compile

El método CultureDefinition.Compile es miembro de la clase System.Globalization.CultureDefinition interna del ensamblado sysglobl.dll. CultureDefinition.Compile escribe información sobre una referencia cultural personalizada en un archivo. Pero como no escribe nada en el Registro, no requiere privilegios administrativos.

Sintaxis

internal static void Compile(
   CultureAndRegionInfoBuilder builder,
   String outFile
);

Parámetros

  • builder
    El objeto CultureAndRegionInfoBuilder que se lee. Las condiciones de este objeto son las mismas que para CultureAndRegionInfoBuilder.Register.

  • outFile
    Una cadena que representa la ruta de acceso completa del archivo de salida. El método escribe el archivo de referencia cultural personalizado pero no lo registra. La definición de la referencia cultural personalizada contenida en el archivo de salida no se reconocerá aunque se encuentre en el directorio %windir%\globalization.

Excepciones

Porque se trata de un método privado no compatible, cualquier excepción debe considerarse un fracaso.

Comentarios

Las siguientes son las diferencias entre CultureAndRegionInfoBuilder.Register y CultureDefinition.Compile:

  • CultureAndRegionInfoBuilder.Register es un método público compatible. Como método interno, CultureDefinition.Compile está sujeto a eliminación o cambio en versiones futuras y no se debería confiar en él.

  • CultureAndRegionInfoBuilder.Register requiere permisos administrativos, pero CultureDefinition.Compile escribe en cualquier archivo que el usuario tenga permiso para crear.

  • CultureAndRegionInfoBuilder.Register realiza una mayor validación que CultureDefinition.Compile. Así, llamar directamente a este último método puede crear una referencia cultural no válida que normalmente no se puede instalar en un equipo. La referencia cultural creada podría contener datos irregulares o datos que den error en el sistema operativo o en .NET Framework.

  • CultureAndRegionInfoBuilder.Register siempre crea su archivo de salida en el directorio %windir%\globalization. CultureDefinition.Compile escribe en cualquier archivo de salida especificado.

  • CultureAndRegionInfoBuilder.Register podría producir una excepción si el objeto CultureAndRegionInfoBuilder especificado por el parámetro builder contiene datos inconsistentes o inesperados. Sin embargo, este método no valida tan exhaustivamente como CultureAndRegionInfoBuilder.Register.

    Nota de precauciónPrecaución

    Puesto que CultureDefinition.Compile utiliza mecanismos de validación limitados, es posible que cree referencias culturales no válidas o incoherentes, y hacer que la aplicación se llegue a bloquear o incluso a perder datos.

  • CultureAndRegionInfoBuilder.Register registra el archivo de referencia cultural personalizado en el Registro. CultureDefinition.Compile crea una referencia cultural personalizada pero no la registra (instala) en el sistema operativo local. Los archivos sin registrar en el directorio %windir%\globalization fallan y no son totalmente funcionales en .NET Framework 4. Aunque podrían parecer operativos, los archivos de referencia cultural personalizados registrados incorrectamente pueden causar fallos o un comportamiento errático si el sistema operativo o .NET Framework tiene acceso a ellos.

  • Cuando se llama al método CultureAndRegionInfoBuilder.Register, crea el archivo de referencia cultural personalizado. También establece la clave del Registro HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CustomLocale, para la que crea un valor de cadena que denomina la referencia cultural. El método CultureDefinition.Compile crea el archivo de referencia cultural personalizado, pero no crea la clave del Registro correspondiente.

    NotaNota

    A partir de .NET Framework versión 3.5, el método CultureDefinition.Compile ya no establece la clave del Registro HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\IetfLanguage, porque no la utiliza .NET Framework.Los nombres de la referencia cultural se han corregido para cumplir con RFC 4646.

Utilizar directamente CultureDefinition.Compile

Para guardar las referencias culturales personalizadas mediante el uso de CultureDefinition.Compile:

  1. Incluya código en la aplicación para realizar las validaciones necesarias. Recuerde que las validaciones que realiza el método CultureAndRegionInfoBuilder.Register no se realizan cuando se utiliza el método CultureDefinition.Compile directamente. Aunque el archivo de referencia cultural personalizado será accesible, los archivos construidos incorrectamente podrían presentar un comportamiento no válido o extraño.

  2. En lugar de llamar a CultureAndRegionInfoBuilder.Register, llame al método CultureDefinition.Compile y pase el objeto CultureAndRegionInfoBuilder junto con un nombre de archivo apropiado.

  3. Registre el archivo de referencia cultural personalizada resultante como se describe en el procedimiento siguiente.

Registrar (instalar) el archivo de referencia cultural personalizada

Para registrar (instalar) el archivo de referencia cultural personalizada:

  1. Incluya el código en su aplicación para escribir el resultado de la llamada a CultureDefinition.Compile en el subdirectorio %windir%\globalization.

  2. Para habilitar la referencia cultural personalizada para que tenga éxito cuando se ejecute bajo .NET Framework 4, incluya código para escribir en la clave del Registro HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CustomLocale.

Ejemplo

En el ejemplo siguiente se utiliza la clase CultureAndRegionInfoBuilder para crear una referencia cultural personalizada llamada x-en-US-example que se basa en la referencia cultural del inglés (Estados Unidos) pero utiliza un símbolo de moneda diferente (USD en lugar de $). En el ejemplo se utiliza la reflexión para compilar la definición de referencia cultural llamando al método CultureDefinition.Compile privado. A continuación, copia el compilado. el archivo nlp compilado en el subdirectorio de globalización del directorio de Windows y registra la referencia cultural personalizada en el Registro. A continuación, crea una instancia de un objeto CultureInfo que representa la referencia cultural personalizada y la utiliza en una operación de formato. Finalmente, el ejemplo llama al método CultureAndRegionInfoBuilder.Unregister para quitar la definición de la referencia cultural personalizada. Tenga en cuenta que debe agregar una referencia a sysglobl.dll al proyecto para compilar correctamente el ejemplo.

Imports Microsoft.Win32
Imports System.Globalization
Imports System.IO
Imports System.Reflection

Module Example
   Private Const MAX_PATH As Integer = 260
   Private Const CUSTOM_KEY As String = "SYSTEM\CurrentControlSet\Control\Nls\CustomLocale"
   Private Declare Function GetWindowsDirectory Lib "Kernel32" _
           Alias "GetWindowsDirectoryA" _ 
           (lpBuffer As String, nSize As Integer) As Integer

   Private cultureName As String = "x-en-US-example"

   Public Sub Main()
      ' Create an alternate en-US culture.
      Dim enUS As New CultureAndRegionInfoBuilder(cultureName, CultureAndRegionModifiers.None)
      enUS.LoadDataFromCultureInfo(CultureInfo.CreateSpecificCulture("en-US"))
      enUS.LoadDataFromRegionInfo(New RegionInfo("US"))
      enUS.NumberFormat.CurrencySymbol = "USD"
      enUS.NumberFormat.CurrencyPositivePattern = 2
      enUS.NumberFormat.CurrencyNegativePattern = 12

      ' Use reflection to get the CultureDefinition.Compile method.
      Dim assem As Assembly = Assembly.Load("sysglobl, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")            
      Dim defType As Type = assem.GetType("System.Globalization.CultureDefinition")
      Dim method As MethodInfo = defType.GetMethod("Compile", BindingFlags.NonPublic Or BindingFlags.Static)
      Dim tempPath As String = ".\" + cultureName + ".nlp"
      Dim args() As Object = { enUS, tempPath }

      ' Delete target file if it already exists.
      If File.Exists(tempPath) Then File.Delete(tempPath)

      ' Compile the culture definition.
      method.Invoke(Nothing, args)  

      ' Copy the file.
      Try
         Dim buffer As New String(ChrW(0), MAX_PATH)
         Dim charsWritten As Integer = GetWindowsDirectory(buffer, MAX_PATH)
         Dim fileName As String = String.Format("{0}{1}Globalization{1}{2}.nlp", 
                                                buffer.Substring(0, charsWritten),
                                                Path.DirectorySeparatorChar,
                                                cultureName) 
         File.Copy(tempPath, fileName, True)
         WriteToRegistry(CUSTOM_KEY, cultureName)       
      Catch e As UnauthorizedAccessException
         Console.WriteLine("You must run this application as an administrator")
         Console.WriteLine("so that you can install culture definition files.") 
         Exit Sub
      End Try

      ' Create and use the new culture.
      Try
         Dim value As Decimal = 1603.42d
         Dim ci As New CultureInfo(cultureName)
         Console.WriteLine(String.Format(ci, "{0:C2}", value))
      Catch e As CultureNotFoundException
         Console.WriteLine("Unable to create the '{0}' culture.", cultureName)
      End Try

      CultureAndRegionInfoBuilder.Unregister(cultureName)
   End Sub

   Public Sub WriteToRegistry(keyName As String, valueName As String)
      Dim key As RegistryKey = Registry.LocalMachine.OpenSubKey(keyName, True)
      ' Create the key if it does not already exist.
      If key Is Nothing      
         key = Registry.LocalMachine.CreateSubKey(keyName)
         If key Is Nothing Then Throw New NullReferenceException("Cannot create the registry key")
      End If
      ' Set the new name
      key.SetValue(valueName, valueName)
      key.Close()
   End Sub
End Module
' The example displays the following output:
'         USD 1,603.42
using Microsoft.Win32;
using System;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;

public class Example
{
   private const int MAX_PATH = 260;
   private const string CUSTOM_KEY = @"SYSTEM\CurrentControlSet\Control\Nls\CustomLocale";

   [DllImport("kernel32", SetLastError=true)]
   private static extern int GetWindowsDirectory(StringBuilder lpBuffer, 
                                                  int nSize);

   private static string cultureName = "x-en-US-example";

   public static void Main()
   {
      // Create an alternate en-US culture.
      CultureAndRegionInfoBuilder enUS = new CultureAndRegionInfoBuilder(cultureName, CultureAndRegionModifiers.None);
      enUS.LoadDataFromCultureInfo(CultureInfo.CreateSpecificCulture("en-US"));
      enUS.LoadDataFromRegionInfo(new RegionInfo("US"));
      enUS.NumberFormat.CurrencySymbol = "USD";
      enUS.NumberFormat.CurrencyPositivePattern = 2;
      enUS.NumberFormat.CurrencyNegativePattern = 12;

      // Use reflection to get the CultureDefinition.Compile method.
      Assembly assem = Assembly.Load("sysglobl, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");            
      Type defType = assem.GetType("System.Globalization.CultureDefinition");
      MethodInfo method = defType.GetMethod("Compile", BindingFlags.NonPublic | BindingFlags.Static);
      string tempPath = @".\" + cultureName + ".nlp";
      object[] args = { enUS, tempPath };
      // Delete target file if it already exists.
      if (File.Exists(tempPath))
         File.Delete(tempPath);

      // Compile the culture definition.
      method.Invoke(null, args);  
      // Copy the file.
      try {
         StringBuilder buffer = new StringBuilder(MAX_PATH);
         int charsWritten = GetWindowsDirectory(buffer, MAX_PATH);
         string fileName = String.Format("{0}{1}Globalization{1}{2}.nlp", 
                                         buffer.ToString().Substring(0, charsWritten),
                                         Path.DirectorySeparatorChar,
                                         cultureName); 
         File.Copy(tempPath, fileName, true);
         WriteToRegistry(CUSTOM_KEY, cultureName);       
      }
      catch (UnauthorizedAccessException) {
         Console.WriteLine("You must run this application as an administrator");
         Console.WriteLine("so that you can install culture definition files."); 
         return;
      }

      // Create and use the new culture.
      try {
         decimal value = 1603.42m;
         CultureInfo ci = new CultureInfo(cultureName);
         Console.WriteLine(String.Format(ci, "{0:C2}", value));
      }
      catch (CultureNotFoundException) {
         Console.WriteLine("Unable to create the '{0}' culture.", cultureName);
      }

      CultureAndRegionInfoBuilder.Unregister(cultureName);
   }

   public static void WriteToRegistry(string keyName, string valueName)
   {
      RegistryKey key = Registry.LocalMachine.OpenSubKey(keyName, true);
      // Create the key if it does not already exist.
      if (key == null) {      
         key = Registry.LocalMachine.CreateSubKey(keyName);
         if (key == null) throw new NullReferenceException("Cannot create the registry key");
      }
      // Set the new name
      key.SetValue(valueName, valueName);
      key.Close();
   }
}
// The example displays the following output:
//        USD 1,603.42

Vea también

Tareas

Cómo: Crear referencias culturales personalizadas

Historial de cambios

Fecha

Historial

Motivo

Diciembre de 2010

Revisado para .NET Framework 4 y agregado un ejemplo.

Mejora de la información.