2011. március 31., csütörtök

System and User Locale vs. System and User UI Language


Problem/Question/Abstract:

This sorts out the business of Language IDs and UI Language IDs. Why they are different and how to access them.

Answer:

I became quite confused (easy for me) on the subject of Language ID’s. It turns out, that what I failed to realize is that there is really two, potentially different, languages IDs on a system. Sure, I knew that there is both a default “system” ID and a “user” ID for each defined user on the system but what I didn’t know, was that there is also a system and user UI Language ID.

Windows 32 bit operating systems have a System Locale, which can be retrieved with GetSystemDefaultLangID. System This ID determines which bitmap fonts, and OEM, ANSI and MAC code pages are defaults for the system.

Complementing the system locale default is the user locale default that determines which settings are used for dates, times, currency, numbers, and sort order as a default for each user. The GetUserDefaultLangID retrieves the default value for the current user.

Threads can also have a default locale. New threads default to the default user locale but can be changed with SetThreadLocale and retrieved with GetThreadLocale. The thread locale determines which settings are used for formatting dates, times, currency, numbers, and sort order for the thread.

Eventually, I realized that there is also separate default User Interface (UI) language IDs. These determine the language of menus, dialogs, messages, INF files and help files. The System UI Language is retrieved using GetSystemDefaultUILanguage, while the user UI language is retrieved using GetUseDefaultUILanguage.

Once I finally came to terms with this, not so subtle, distinction between “locals” and “UI languages” I realized that what I needed was the user UI language ID unfortunately none of my copies of Delphi (including Delphi 6) support either GetSystemDefaultUILanguage or GetUseDefaultUILanguage. Even worse, these are relatively new API calls and only first appeared with Windows ME and 2000.

Here is a GetUseDefaultUILanguage I pieced together from various MSDN documents, samples, and factoids. This was written with Delphi 6 and supports OSs from Win95 on up. I’ve only tested it on Windows 2000 so please let me know if it hiccups on Win9x and NT.

Send comments to alecb@o2a.com.

// Helper

function HrFromWin32(dwErr: DWord): HResult;
begin
  result := HResultFromWin32(dwErr);
end;

// Helper

function HrFromLastWin32Error: HResult;
var
  dw: DWord;
begin
  dw := GetLastError;
  if dw = 0 then
    result := E_Fail
  else
    result := HrFromWin32(dw);
end;

// Helper

function MAKELANGID(p, s: word): word;
begin
  result := (s shl 10) or p;
end;

// The good stuff

function GetUserDefaultUILanguage: LANGID;
type
  TGetLang = function: LangID;
  THandle = Integer;
var
  GetLang: TGetLang;
  wUILang: LANGID;
  Osv: OSVERSIONINFO;
  Reg: TRegistry;
  Handle: THandle;
begin
  wUILang := 0;
  Osv.dwOSVersionInfoSize := sizeof(Osv);

  if not GetVersionEx(Osv) then
  begin
    OleError(HrFromLastWin32Error);
  end
    // Get the UI language by one of three methods, depending on OS
  else if Osv.dwPlatformId <> VER_PLATFORM_WIN32_NT then
  begin
    // Case 1: Running on Windows 9x. Get the system UI language from registry:
    Reg := TRegistry.Create;
    try
      Reg.RootKey := HKEY_USERS;
      if Reg.OpenKey('.Default\Control Panel\desktop\ResourceLocale', False) then
      begin
        wUILang := LangID(Reg.ReadInteger(''));
        Reg.CloseKey;
      end;
    finally
      Reg.Free;
    end;
  end
  else if (Osv.dwMajorVersion >= 5.0) then
  begin
    // Case 2: Running on Windows 2000 or later. Use GetUserDefaultUILanguage
    // to find the user's prefered UI language
    Handle := LoadLibrary('kernel32.dll');
    if Handle <> 0 then
    begin
      @GetLang := GetProcAddress(Handle, 'GetUserDefaultUILanguage');
      if @GetLang <> nil then
        wUILang := GetLang;
      FreeLibrary(Handle);
    end;
  end
  else
  begin
    // Case 3: Running on Windows NT 4.0 or earlier. Get UI language
    // from locale of .default user in registry:
    // HKEY_USERS\.DEFAULT\Control Panel\International\Locale
    Reg := TRegistry.Create;
    try
      Reg.RootKey := HKEY_USERS;
      if Reg.OpenKey('.Default\Control Panel\desktop\International', False) then
      begin
        wUILang := LangID(Reg.ReadInteger('Locale'));
        Reg.CloseKey;

        // Special case these to the English UI.
        // These versions of Windows NT 4.0 were enabled only, i.e., the
        // UI was English. However, the registry setting
        // HKEY_USERS\.DEFAULT\Control Panel\International\Locale was set
        // to the respective locale for application compatibility.
        if ($0401 = wUILang) or // Arabic
        ($040D = wUILang) or // Hebrew
        ($041E = wUILang) then // Thai
        begin
          wUILang := MakeLangID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
        end;

      end;
    finally
      Reg.Free;
    end;
  end;
  result := wUILang;
end;

Nincsenek megjegyzések:

Megjegyzés küldése