Gewusst wie: Speichern benutzerdefinierter Kulturen ohne Administratorrechte

In diesem Thema wird ein Verfahren beschrieben, mit dem benutzerdefinierte Kulturdaten ohne Administratorrechte in einer Datei gespeichert werden können. Eine Anwendung, die mit Administratorrechten ausgeführt wird, registriert eine benutzerdefinierte Kultur mithilfe der Methode CultureAndRegionInfoBuilder.Register, wie beschrieben im Thema Gewusst wie: Erstellen von benutzerdefinierten Kulturen. Intern ruft diese Methode die CultureDefinition.Compile -Methode auf, für die keine Administratorrechte erforderlich sind.

Um benutzerdefinierte Kulturen ohne Administratorrechte zu speichern, können Sie mit der Reflexion auf die CultureDefinition.Compile-Methode direkt zugreifen.

WarnhinweisVorsicht

Die CultureDefinition.Compile-Methode direkt aufrufen, wird nicht unterstützt.Die Methode kann ohne Ankündigung geändert oder sogar entfernt werden.Dieses Thema beschreibt nur das Verhalten für die .NET Framework, Version 4.Bei einer fehlerhaften Verwendung dieser Methode funktioniert der Computer möglicherweise nicht mehr stabil. Dies wiederum führt u. U. zu Anwendungsabstürzen oder Datenverlust.

Informationen über CultureDefinition.Compile

Die CultureDefinition.Compile -Methode ist ein Member der internen System.Globalization.CultureDefinition-Klasse in der Assembly sysglobl.dll. CultureDefinition.Compile schreibt Informationen über eine benutzerdefinierte Kultur in eine Datei. Da diese Methode aber keine Daten in die Registrierung schreibt, erfordert sie keine Administratorrechte.

Syntax

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

Parameter

  • builder
    Das zu lesende CultureAndRegionInfoBuilder-Objekt. Die Bedingungen für dieses Objekt sind dieselben wie für CultureAndRegionInfoBuilder.Register.

  • outFile
    Eine Zeichenfolge, die den vollständigen Pfad für die Ausgabe-Datei darstellt. Die Methode schreibt die benutzerdefinierte Kulturdatei, registriert sie aber nicht. Die benutzerdefinierte Kulturdefinition in der Ausgabedatei wird nicht anerkannt, auch wenn sie im Verzeichnis %windir%\globalization gespeichert ist.

Ausnahmen

Da es eine nicht unterstützte private Methode ist, sollte jede Ausnahme als ein Fehler betrachtet werden.

Hinweise

Im Folgenden sind die Unterschiede zwischen CultureAndRegionInfoBuilder.Register und CultureDefinition.Compile dargestellt:

  • CultureAndRegionInfoBuilder.Register ist eine unterstützte öffentliche Methode. CultureDefinition.Compile kann als interne Methode in künftigen Versionen geändert oder entfernt werden. Daher sollte nicht allein auf diese Methode zurückgegriffen werden.

  • CultureAndRegionInfoBuilder.Register erfordert Administratorberechtigungen, aber CultureDefinition.Compile schreibt in jede Datei, die der Benutzer erstellen darf.

  • CultureAndRegionInfoBuilder.Register führt mehr Validierung aus als CultureDefinition.Compile. Durch einen direkten Aufruf der letztgenannten Methode kann somit eine ungültige Kultur erstellt werden, die sich normalerweise nicht auf einem Computer installieren lässt. Die erstellte Kultur enthält möglicherweise irreguläre Daten bzw. Daten, die zu einem Fehler des Betriebssystems oder von .NET Framework führen können.

  • CultureAndRegionInfoBuilder.Register die Ausgabedatei immer im Verzeichnis %windir%\globalization. CultureDefinition.Compile schreibt in eine Ausgabedatei, die Sie angeben.

  • CultureAndRegionInfoBuilder.Register kann eine Ausnahme auslösen, wenn das CultureAndRegionInfoBuilder-Objekt, das durch den Parameter builder angegeben wird, inkonsistente oder unerwartete Daten enthält. Diese Methode überprüft jedoch nicht so gründlich wie CultureAndRegionInfoBuilder.Register.

    WarnhinweisVorsicht

    Da CultureDefinition.Compile eingeschränkte Validierungsmechanismen verwendet, werden u. U. ungültige oder inkonsistente Kulturen erstellt, die potenziell zu Anwendungsabstürzen oder sogar zu Datenverlusten führen können.

  • CultureAndRegionInfoBuilder.Register registriert die benutzerdefinierte Kulturdatei in der Registrierung. CultureDefinition.Compile erstellt eine benutzerdefinierte Kultur, registriert (und installiert) sie aber nicht unter dem lokalen Betriebssystem. Nicht registrierte Dateien im Verzeichnis %windir%\globalization schlagen fehl und sind in .NET Framework 4 nicht voll funktionsfähig. Obwohl sie vielleicht betriebsfähig erscheinen, können nicht ordnungsgemäß registrierte benutzerdefinierte Kulturdateien Fehlverhalten oder Ausfälle verursachen, wenn auf sie durch das Betriebssystem oder .NET Framework zugegriffen wird.

  • Wenn Sie die CultureAndRegionInfoBuilder.Register-Methode aufrufen, wird die benutzerdefinierte Kultur-Datei. Zudem wird der Registrierungsschlüssel "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CustomLocale" festgelegt, für den ein Zeichenfolgenwert erstellt wird, mit dem die Kultur benannt wird. Die CultureDefinition.Compile-Methode erstellt die benutzerdefinierte Kulturdatei, aber nicht den entsprechenden Registrierungsschlüssel.

    HinweisHinweis

    Beginnend mit .NET Framework, Version 3.5 legt die CultureDefinition.Compile-Methode nicht mehr den HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\IetfLanguage-Registrierungsschlüssel fest, da der Schlüssel nicht von .NET Framework verwendet wird.Kulturnamen wurden korrigiert, um RFC 4646 zu entsprechen.

Direktes Verwenden von CultureDefinition.Compile

So speichern Sie benutzerdefinierte Kulturen mithilfe von CultureDefinition.Compile:

  1. Fügen Sie Code in Ihre Anwendung ein, um alle erforderlichen Validierungen durchzuführen. Denken Sie daran, dass die Validierungen der CultureAndRegionInfoBuilder.Register-Methode nicht ausgeführt werden, wenn Sie die CultureDefinition.Compile-Methode direkt verwenden. Auf die resultierende benutzerdefinierte Kulturdatei kann zwar zugegriffen werden, doch können nicht ordnungsgemäß erstellte Dateien u. U. zu unzulässigem oder unberechenbarem Verhalten führen.

  2. Anstatt CultureAndRegionInfoBuilder.Register aufzurufen, rufen Sie die CultureDefinition.Compile-Methode auf und übergeben Sie das CultureAndRegionInfoBuilder-Objekt zusammen mit einem entsprechenden Dateinamen.

  3. Registrieren Sie die resultierende benutzerdefinierte Kulturdatei wie in der nächsten Prozedur beschrieben.

Registrieren (Installieren) der benutzerdefinierten Kulturdatei

So registrieren (installieren) Sie die benutzerdefinierte Kulturdatei

  1. Nehmen Sie Code in die Anwendung auf, mit dem die Ausgabe des CultureDefinition.Compile-Aufrufs in das Unterverzeichnis %windir%\globalization geschrieben wird.

  2. Um die benutzerdefinierte Kultur erfolgreich beim Ausführen unter .NET Framework 4 zu aktivieren, fügen Sie Code zum Schreiben in den HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CustomLocale-Registrierungsschlüssel ein.

Beispiel

Im folgenden Beispiel wird die CultureAndRegionInfoBuilder-Klasse zum Erstellen einer benutzerdefinierten Kultur namens x-en-US-example verwendet, die basiert auf der Kultur Englisch (USA), aber ein anderes Währungssymbol (USD anstelle von $) verwendet. Das Beispiel verwendet Reflektion, um die Kulturdefinition zu kompilieren, indem die private CultureDefinition.Compile-Methode aufgerufen wird. Es kopiert anschließend die kompilierte . NLP-Datei für das Globalisierungs-Unterverzeichnis des Windows-Verzeichnisses und registriert die benutzerdefinierte Kultur in der Registrierung. Als nächstes wird ein CultureInfo-Objekt instanziiert, das die benutzerdefinierte Kultur darstellt und in einem Formatierungsvorgang verwendet. Schließlich ruft das Beispiel die CultureAndRegionInfoBuilder.Unregister-Methode auf, um die benutzerdefinierte Kultur-Definition zu entfernen. Beachten Sie, dass dem Projekt ein Verweis auf sysglobl.dll hinzugefügt werden muss, um das Beispiel erfolgreich kompilieren zu können.

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

Siehe auch

Aufgaben

Gewusst wie: Erstellen von benutzerdefinierten Kulturen

Änderungsprotokoll

Datum

Versionsgeschichte

Grund

Dezember 2010

Für .NET Framework 4 überarbeitet und ein Beispiel hinzugefügt.

Informationsergänzung.