方法: 管理者特権なしでカスタム カルチャを保存する

更新 : 2010 年 12 月

ここでは、管理者特権なしでカスタム カルチャ データをファイルに保存する方法について説明します。 トピック「方法: カスタム カルチャを作成する」で説明されているように、管理者特権で実行されるアプリケーションでは、CultureAndRegionInfoBuilder.Register メソッドを使用してカスタム カルチャを登録します。 このメソッドは、管理者特権を必要としない CultureDefinition.Compile メソッドを内部で呼び出します。

管理者特権なしでカスタム カルチャを保存するために、リフレクションを使用して CultureDefinition.Compile メソッドに直接アクセスできます。

Caution メモ注意

CultureDefinition.Compile メソッドの直接呼び出しはサポートされていません。メソッドは予告なしに変更、さらには削除される場合があります。このトピックでは、.NET Framework Version 4 の場合のその動作についてのみ説明します。このメソッドを誤って使用すると、コンピューターが不安定な状態になり、アプリケーションのクラッシュやデータの損失が発生する可能性があります。

CultureDefinition.Compile について

CultureDefinition.Compile メソッドは、sysglobl.dll アセンブリの内部 System.Globalization.CultureDefinition クラスのメンバーです。 CultureDefinition.Compile は、カスタム カルチャについての情報をファイルに書き込みます。 ただし、レジストリには何も書き込まないため、管理者特権は不要です。

構文

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

パラメーター

  • builder
    読み込む CultureAndRegionInfoBuilder オブジェクト。 このオブジェクトに関する条件は、CultureAndRegionInfoBuilder.Register の場合と同じです。

  • outFile
    出力ファイルの完全パスを表す文字列。 このメソッドにより、カスタム カルチャ ファイルが書き込まれますが、登録は行われません。 出力ファイルを %windir%\globalization ディレクトリに配置しても、出力ファイルに含まれているカスタム カルチャ定義は認識されません。

例外

これはサポートされていないプライベート メソッドであるため、例外はエラーと見なす必要があります。

解説

CultureAndRegionInfoBuilder.Register と CultureDefinition.Compile の違いは次のとおりです。

  • CultureAndRegionInfoBuilder.Register は、サポートされているパブリック メソッドです。 CultureDefinition.Compile は内部メソッドで、将来のバージョンで変更または削除される可能性があるため、信頼できません。

  • CultureAndRegionInfoBuilder.Register には管理者特権が必要ですが、CultureDefinition.Compile ではユーザーが作成する権限を持つ任意のファイルに書き込むことができます。

  • CultureAndRegionInfoBuilder.Register は、CultureDefinition.Compile よりも多くの検証を実行します。 したがって、後者のメソッドを直接呼び出すと、コンピューターに正常にインストールできない無効なカルチャが作成される可能性があります。 作成されたカルチャに、不規則なデータ、またはオペレーティング システムあるいは .NET Framework でエラーを引き起こすデータが含まれる可能性があります。

  • CultureAndRegionInfoBuilder.Register は、常に %windir%\globalization ディレクトリに出力ファイルを作成します。 CultureDefinition.Compile は、指定した任意の出力ファイルに書き込みます。

  • builder パラメーターで指定された CultureAndRegionInfoBuilder オブジェクトに矛盾したデータまたは予期しないデータが含まれる場合、CultureAndRegionInfoBuilder.Register で例外がスローされることがあります。 ただし、このメソッドでは、CultureAndRegionInfoBuilder.Register のように綿密に検証を行うわけではありません。

    Caution メモ注意

    CultureDefinition.Compile で使用する検証のしくみは限られているため、無効なカルチャまたは矛盾したカルチャが作成され、アプリケーションのクラッシュまたはデータの損失が発生する可能性があります。

  • CultureAndRegionInfoBuilder.Register では、カスタム カルチャ ファイルをレジストリに登録します。 CultureDefinition.Compile はカスタム カルチャを作成しますが、ローカル オペレーティング システムへの登録 (インストール) は行いません。 %windir%\globalization ディレクトリに登録されていないファイルはエラーになり、.NET Framework 4 では完全には機能しません。 これらは実行可能に見えることもありますが、カスタム カルチャ ファイルが正しく登録されていないと、オペレーティング システムまたは .NET Framework がアクセスした場合に、不規則な動作またはエラーが発生する可能性があります。

  • CultureAndRegionInfoBuilder.Register メソッドを呼び出すと、このメソッドによりカスタム カルチャ ファイルが作成されます。 また、HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CustomLocale レジストリ キーが設定され、このキーに対してカルチャに名前を付ける文字列値が作成されます。 CultureDefinition.Compile メソッドによって、カスタム カルチャ ファイルは作成されますが、対応するレジストリ キーは作成されません。

    メモメモ

    .NET Framework Version 3.5 以降では HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\IetfLanguage レジストリ キーは使用されないため、このキーは CultureDefinition.Compile メソッドで設定されなくなりました。カルチャ名は、RFC 4646 に準拠するように修正されました。

CultureDefinition.Compile を直接使用する方法

CultureDefinition.Compile を使用してカスタム カルチャを保存するには

  1. 必要な検証を実行するコードをアプリケーションに含めます。 CultureAndRegionInfoBuilder.Register メソッドによって実行される検証は、CultureDefinition.Compile メソッドを直接使用する場合は実行されないことに注意してください。 生成されたカスタム カルチャ ファイルにアクセスすることはできますが、正しく構築されていないファイルでは、無効な動作または不規則な動作が発生する可能性があります。

  2. CultureAndRegionInfoBuilder.Register を呼び出す代わりに、CultureDefinition.Compile メソッドを呼び出し、適切なファイル名と共に CultureAndRegionInfoBuilder オブジェクトを渡します。

  3. 次の手順で説明するように、生成されたカスタム カルチャ ファイルを登録します。

カスタム カルチャ ファイルを登録 (インストール) する方法

カスタム カルチャ ファイルを登録 (インストール) するには

  1. CultureDefinition.Compile の呼び出しの出力を %windir%\globalization サブディレクトリに書き込むコードをアプリケーションに含めます。

  2. .NET Framework 4 での実行時にカスタム カルチャを正常に実行できるようにするには、HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CustomLocale レジストリ キーに書き込むコードを含めます。

使用例

次の例では、CultureAndRegionInfoBuilder クラスを使用して、x-en-US-example という名前のカスタム カルチャを作成しています。このカスタム カルチャは、英語 (米国) カルチャに基づいていますが、異なる通貨記号を使用しています ($ ではなく USD)。 例では、プライベート CultureDefinition.Compile メソッドを呼び出して、リフレクションを使用してカルチャ定義をコンパイルしています。 その後で、コンパイル済み .nlp ファイルを Windows ディレクトリの Globalization サブディレクトリにコピーして、カスタム カルチャをレジストリに登録します。 次に、カスタム カルチャを表す CultureInfo オブジェクトをインスタンス化して、それを書式設定操作で使用します。 最後に、例では、CultureAndRegionInfoBuilder.Unregister 基本メソッドが呼び出され、カスタム カルチャ定義が削除されます。 例を正常にコンパイルできるようにするには、sysglobl.dll への参照をプロジェクトに追加する必要がある点に注意してください。

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

参照

処理手順

方法: カスタム カルチャを作成する

履歴の変更

日付

履歴

理由

2010 年 12 月

.NET Framework 4 用に改訂され、例が追加されました。

情報の拡充