GetThreadLocale returns different value than GetUserDefaultLCID?

15,682

Solution 1

You're not the only one. I've seen this too with Windows 7 here in New Zealand and it seems to only trip up Delphi applications for some reason as far as I can tell.

The strange thing we found is that switching to a different regional settings via Control Panel and then switching back to NZ resolves the issue. I'd be curious to know if the same workaround resolves it for you just to verify that we're seeing the same phenomenon.

I'm wondering if selecting non-US regional settings via the Windows 7 install process is not quite 'doing the right thing' in some subtle way that only trips up Delphi applications for some reason.

I'd arrived at similar test code to JP's in an attempt to track it down and find a software workaround but our QA guy had since found the 'regional settings switcheroo' workaround and he didn't fancy completely reinstalling Windows 7 again to get back to the original funky state for some reason :-)

Solution 2

For some background information have a look here:

http://www.siao2.com/2010/03/19/9980203.aspx

So it seems this problem manifests itself on Vista as well as Windows 7. It occurs because Microsoft seems to be in the process of deprecating the Locale ID in favor of the Locale Name.

To summarize: The relevant API calls all operate on registry values that can be found at HKCU\Control Panel\International. The value "Locale" is maintained for backward compatibility reasons and under normal circumstances is kept in synch with its newer counterpart called "LocaleName". This synch process however doesn't work under some circumstances.

Anyway, the GetThreadLocale API call gets its return value from the "Locale" registry entry mentioned above, while the others (GetUserDefaultLCID, GetSystemDefaultLCID, etc) use the "LocaleName" registry entry.

Hence the confusion.

BTW, the solution mentioned by JP in a previous post should probably be extended to

initialization
  SetThreadLocale(GetUserDefaultLCID);
  GetFormatSettings;

because (if i'm reading it correctly!) according to the docco the GetUserDefaultLCID call will account for user customizations.

After a bit more research, Vista is not affected at all. I've got some more detail too ...

The relevant API calls all operate on registry values that can be found at HKCU\Control Panel\International. The value " Locale " is maintained for backward compatibility reasons and under normal circumstances is kept in synch with its newer counterpart called " LocaleName ". Under Windows 7 at least, this synch process however doesn't work where processes are being run as another user (i.e. RunAs or Impersonation). This seems to be the case during installation, where the installer is launched from an existing windows session. It does however seem to work correctly if you've booted from the install CD.

  • GetThreadLocale gets its value from Thread Information Block or Thread Environment Block (TIB or TEB) See: http://en.wikipedia.org/wiki/Thread_Environment_Block For both Vista and Windows 7, the TIB is initialised with the HKCU\Control Panel\International\Locale registry entry at logon. This becomes the default Locale for all threads created during the session. Changing this registry value during a session has no effect on the value returned by the GetThreadLocale API call. The user must log out and log in again to see a change. This is the API call that Delphi uses as the basis to initialize all its locale format strings ( See SysUtils.GetFormatSettings method), from which all date fields are formatted.

  • GetUserDefaultLCID: in Vista, bases its return value on the HKCU\Control Panel\International\Locale registry entry. In Windows 7, bases its return value on the HKCU\Control Panel\International\LocaleName registry entry. The respective registry entry can be changed during a session and the result is immediately reflected in this API call return value.

  • SetThreadLocale updates the TIB to reflect the locale provided in the parameter to this call. Note that this only ever effects the thread the API call is executed from. The API calls SetThreadLocale(LOCALE_USER_DEFAULT) and SetThreadLocale(GetUserDefaultLCID) are functionally equivalent. They both derive the source locale as described in the GetUserDefaultLCID API call above.

Solution 3

I noticed same problem, when I started using new Windows 7 computer. I spent some time trying to find what causes this, but found nothing. So I just added these two lines to some units initialization section.

initialization
  SetThreadLocale(LOCALE_USER_DEFAULT);
  GetFormatSettings;

Strange is that this behavior occurs only in my computer as we have few other Win7 computers in office also.

Solution 4

A new post in the RTL forum suggests this fix in SysUtils->InitSysLocale:

SetThreadLocale(LOCALE_USER_DEFAULT); 
SysLocale.DefaultLCID := LOCALE_USER_DEFAULT; 
GetFormatSettings;

And further explains:

It Must be set by default to LOCALE_USER_DEFAULT and not to 0x409! This bug is in 2010, XE and XE2

Solution 5

I've just tested a new installation of Windows 7 Starter Edition, and had the same problem, but I found that the locale that GetThreadLocale returns was exactly the locale sugested by the Windows installation program, but I changed it during installation to another, wich is the one that GetUserDefaultLCID returns, also the one I wanted to use, (I maked a small program just for this). So, the locale changed for user, but somewhere was still specified the first locale and it's been returned by GetThreadLocale. As JP commented, really there is an issue with installation, it doesn't change the locale at all places where it can be found. It seems that changing the locale via Control Panel does the job fine, and that could explain wy changing it as proposed works, by the way, it explains why other computers could not have the same problem (if you didn't change the locale during installation). Hope this help.

Share:
15,682
Mick
Author by

Mick

Updated on June 15, 2022

Comments

  • Mick
    Mick almost 2 years

    To get the locale settings, e.g. short date format, we've always used GetLocaleFormatSettings with GetThreadLocale. This has always worked without problem until now.

    A couple of our users are getting different values for GetThreadLocale that don't match what they've configured in the regional settings in Windows 7. We've been unable to reproduce this no matter what we try, but I sent one user a test program to get the locale information, and sure enough GetThreadLocale returns a different LCID (1033) than GetUserDefaultLCID (2057). So instead of getting UK locale settings, they end up with US locale settings.

    Are we getting the locale information incorrectly? Should we be using GetUserDefaultLCID instead of GetThreadLocale?

    Thanks