Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GetThreadLocale returns different value than GetUserDefaultLCID?

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

like image 456
Mick Avatar asked Nov 20 '09 02:11

Mick


3 Answers

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.

like image 86
Robert Avatar answered Oct 21 '22 02:10

Robert


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 :-)

like image 40
Paul Heinz Avatar answered Oct 21 '22 03:10

Paul Heinz


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.

like image 38
J.Pelttari Avatar answered Oct 21 '22 03:10

J.Pelttari