共用方式為


HOW TO:在沒有系統管理權限時儲存自訂文化特性

更新:2010 年 12 月

本主題會說明在沒有系統管理權限情況下將自訂文化特性 (Culture) 資料儲存至檔案的技巧。 使用系統管理權限執行的應用程式會使用 CultureAndRegionInfoBuilder.Register 方法來註冊自訂文化特性,如 HOW TO:建立自訂文化特性主題中所述。 這個方法會在內部呼叫不需要系統管理權限的 CultureDefinition.Compile 方法。

若要在沒有系統管理權限的情況下儲存自訂文化特性,您可以使用反映直接存取 CultureDefinition.Compile 方法。

注意事項警告

不支援直接呼叫 CultureDefinition.Compile 方法。方法可能變更,或甚至被移除,恕不另行通知。本主題僅說明其在 .NET Framework 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 那樣進行完整的驗證。

    注意事項警告

    由於 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 3.5 版 開始,CultureDefinition.Compile 方法不再設定 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\IetfLanguage 登錄機碼,因為 .NET Framework 沒有使用這個機碼。已修正文化特性名稱以符合 RFC 4646。

直接使用 CultureDefinition.Compile

若要使用 CultureDefinition.Compile 儲存自訂文化特性:

  1. 在應用程式中包含程式碼以執行任何必要的驗證。 請記住,當您直接使用 CultureDefinition.Compile 方法時,不會執行由 CultureAndRegionInfoBuilder.Register 方法所執行的驗證。 雖然最後產生的自訂文化特性檔仍可存取,但是未正確建構的檔案卻可能會呈現不合法或不正常的行為。

  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

請參閱

工作

HOW TO:建立自訂文化特性

變更記錄

日期

記錄

原因

2010 年 12 月

已修訂 .NET Framework 4 並加入範例。

資訊加強。