About five months ago I was called in to look into an localization issue affecting one of our software products. The software in case is a Windows Service written in Delphi. This service is used to collect live data from a series of networked devices and store such data into a RDBMS. As usual my colleagues were very quick to blame the issue on Delphi.
The Investigation – Part I
The issue was that the service failed to obtain the proper local setting for decimal separator when running on a Spanish Mexican Windows Server 2003. In other words, the service would not correctly store numeric data in the database’s string fields. The issue presented itself only when the service started as part of the normal boot up process. When the service was restarted it would get the proper decimal separator. Strange behavior indeed.
I verified that the code was indeed written to obtain localization information from the OS. During the Service startup the program issued a call to the Windows function GetLocaleInfoA to obtain localized information – in this case LOCALE_SDECIMAL (0xE). This call uses locale ID information obtained on a prior call to the Windows function GetThreadLocale. So far so god.
So after looking into the issue I was able to determine that the problem happened only when I booted up the computer and that the problem would fix itself if the service was restarted. In light of that discovery the Project Manager in charge thanked me and assigned the issue to some other person – a Windows OS specialist.
Their plan was to either delay the service startup or to restart the service after the computer was up and running. I argued that his approach was not a proper way to fix the issue, specially because we did not have a complete understanding of why the issue was happening. Nevertheless I was told to go back to my prior assignment. So I did.
The Investigation – Part II
About a month ago I was approached yet again by the Project Manager because none of their quick solutions seemed to work. So I resumed my investigation.
After some digging around to try to isolate the issue I was able to determine that the problem lied in the Windows user that the service is using to start. The service is normally installed and set to use the Windows Local System account. When the service was started with the Local Administrator account the service performed as expected, and it did pick up the proper localization information.
The Investigation – Conclusion
Based on these facts I must conclude that Windows handles the locale information for the Local System account in a different way than it does for regular users. So my recommended fix for the issue was to have the services account information changed to run under a user account with enough privileges. In my view a much cleaner solution than restart services or delay service startup.
Service Security and Access Rights
Local System Account
10 thoughts on “Delphi Services and Localization Issue”
Just guessing here, but is it possible that the System Account runs with the default locale settings for whatever edition of Windows you are running, where-as your Administrator account had been specifically configured with certain locale settings.
If it was assumed that “System Account” = “Administrator” then it might be assumed that setting the DECIMAL char for the Administrator would set it for the System Account, but perhaps it doesn’t?
The default locale systems was for a Spanish Mexican OS. AFAIK nothing was changed.
Nothing I did to the Administrator account got reflected in the System Account.
I tried to convince the PM to call Microsoft Support and ask what was the reason. However he did not wanted me to pursue that. I guess because there was ($$$) involved?
That’s what I meant – that the Administrator account is entirely separate and unrelated to the Local System account, although you might think or assume that they would be the same. You simply need to know WHICH user account the System account derives it’s locale from (it has no User account of it’s own, so must get those settings from somewhere).
It seems that the Local System account derives it’s settings from the DEFAULT user account.
This blog and the comments on it provide an indication of how to establish the appropriate settings for the user locale of the system account:
But, if your service runs adequately under a specifically created and configured user account then it is probably advisable (more secure, more manageable) to run it under just such a specific account anyway.
“not correctly store numeric data in the database’s string fields”
“store numeric data in the database’s string fields”
“store numeric data in string fields”
Fail. Also, the game.
Had the same issue creating some services related to date formats. I agree with Jolyon. That’s also what I found. My workaround is let the service read the format from some ini file and use that to fill the ShortDateFormat and DateSeparator or in your case DecimalSeparator.
How about setting what you want in the main form’s Create,
followed by Application.UpdateFormatSettings := False?
It is a service therefore it does not have a main form. Also, this service is required to run on many laguages, so this means that I have no prior knowledge of the locale settings.
You said “Administrator account is entirely separate and unrelated to the Local System account”. But my point is that the Local System Account is not properly recognizing the default locale settings for the host computer in the same way that ANY other account does.
Have you checked the DEFAULT user locale settings? aiui the System Account is unique in that it doesn’t HAVE a specific user account thru which you can set the locale settings.
The System Account – again, aiui – will adopt whatever the default settings are, and you may not have any other user account *using* those “default” settings, since each user account may have their own, specific settings.
All of which is pretty academic if you now have it running with a specific user account, as this gives you the visibility and control to those settings that you need.
I understand what you are saying. The only thing that does not agree with what you are saying is that the service gets proper localization information when it is restarted – “the problem happened only when I booted up the computer and that the problem would fix itself if the service was restarted”.
@Fletch: to your last (long ago reply): if the service is restarted by a logged in user then I’d assume that the restarted service runs within the same locale context as the user and inherits the user’s locale settings.