View Issue Details

IDProjectCategoryView StatusLast Update
0005060JEDI VCL00 JVCL Componentspublic2012-09-10 14:15
ReporterSteffenSchmAssigned Toobones 
PrioritynormalSeveritymajorReproducibilityalways
Status resolvedResolutionfixed 
Product Version3.39 
Target VersionFixed in Version3.46 
Summary0005060: Wrong Display and Return of Float Values by TJvValidateEdit
DescriptionTJvValidateEdit converts Float to String by using the normal Delphi function StrToFloat. This function uses ThousandSeparator and DecimalSeparator loaded from SysUtils by calling:
GetLocalChar(GetThreadLocale,....)

To convert from String to Float TJvValidateEdit calls JvSafeStrToFloat from the JVCL unit JvJCLUtils. This function loads own Chars for ThousandSeparator and DecimalSeparator by calling:
GetLocalChar(LOCALE_SYSTEM_DEFAULT,....)

Not for all but for some of our computers the ThousandSeparator and DecimalSeparator used for Float to String conversion are different from these used for String to Float conversion.

This causes a lot of trouble and makes the component unusable.
Additional Information
I changed the function JvSafeStrToFloat to use the ThousandSeparator and DecimalSeparator from SysUtils. This solves my problem.
TagsNo tags attached.

Relationships

related to 0005385 resolvedobones TJvValidateEdit has a bug in DecimalSeparator handling. 
has duplicate 0005774 resolvedobones Values by TJvValidateEdit multiplied by 10^NumberOfDecimals 
related to 0005579 resolvedobones TJvValidateEdit: Issues with DisplayFormat of dfFloat with DecimalPlaces on x64 PT 

Activities

obones

2009-12-28 16:42

administrator   ~0017033

Do you happen to change the value of ThousandSeparator and DecimalSeparator while the program is running?

SteffenSchm

2009-12-29 12:58

reporter   ~0017044

No I did not change any of these values while the program is running

obones

2010-06-07 13:54

administrator   ~0017460

Could you please provide the zipped sources of a sample application showing this?

2010-07-26 18:08

 

JvValidateEdit Bug.zip (8,768 bytes)

jkelley

2010-07-26 18:12

reporter   ~0017542

I can confirm the bug. My PC is a Windows 7 English (U.S.) installation, so GetLocalChar(LOCALE_SYSTEM_DEFAULT,....) returns English (U.S.) settings. I set my per-user locale to Portuguese (Brazil) while testing an internationalization problem for one of our customers, so the LOCALE_USER_DEFAULT and GetThreadLocale return Portuguese (Brazil) settings. (In response to your earlier question, this change was NOT made while the program was running.)

The result is that, as SteffenSchm reported, TJvValidateEdit sometimes tries to use commas and sometimes tries to use decimals. In my sample project, if I assign a value of 500 to JvValidateEdit1->Value, it's formatted as 500,0000, then the comma is discarded because it doesn't match LOCALE_SYSTEM_DEFAULT, so JvValidateEdit1->Value ends up being 5000000,0000.

2010-08-20 16:05

 

Project2.zip (5,152 bytes)

2010-08-20 16:05

 

Pic1.JPG (22,533 bytes)
Pic1.JPG (22,533 bytes)

2010-08-20 16:06

 

Pic2.JPG (23,137 bytes)
Pic2.JPG (23,137 bytes)

SteffenSchm

2010-08-20 16:18

reporter   ~0017612

Please find enclosed the source code of a asmple application. But the error can not be reproduced at any computer.
At one of my two laptops GetLocalChars returns different results depending on which parameters is used (LOCALE_SYSTEM_DEFAULT, GetThreadLocale or GetSystemDefaultLCID. This is shown on Pic1.jpg. By pressung the Button1 in the sample application the values in all JvValidateEdits are read and rewritten by the following code:
JvValidateEdit1.Value:=JvValidateEdit1.Value;
This results in wrong values shown in Pic2.jpg.
This is exactly the reaction described also by jkelley.

I solved the problem for my project by changing the following lines in the function _JvSafeStrToFloat of the unit JvJCLUtils

  FormatSettings.ThousandSeparator := GetLocaleChar(LOCALE_SYSTEM_DEFAULT, LOCALE_STHOUSAND, '.');
  FormatSettings.DecimalSeparator := GetLocaleChar(LOCALE_SYSTEM_DEFAULT, LOCALE_SDECIMAL, '.');

by the following:

  FormatSettings.ThousandSeparator:= ThousandSeparator;
  FormatSettings.DecimalSeparator := DecimalSeparator;

This can also be used to fix the problem generally.

obones

2010-10-08 16:23

administrator   ~0017820

Changing this has other consequences on codes that use JvSafeStrToFloat.
Wouldn't it be cleaner to have always the same function be called, and preferably the JVCL one?
If yes, could you propose the changes here?

obones

2011-06-07 17:25

administrator   ~0018568

Any news?

cguser

2011-06-07 18:13

reporter   ~0018642

As I mentioned on 0005579, I didn't touch on _JvSafeStrToFloat.

Instead, just passing the third argument of JvSafeStrToFloatDef as
{$IFDEF RTL220_UP}FormatSettings.{$ENDIF RTL220_UP}DecimalSeparator
did solve it.

That seems the most correct usage of that function.

ThomasC

2011-09-16 14:44

reporter   ~0018894

JvJCLUtils.pas, line 7013:
{$IFDEF RTL150_UP}
FormatSettings.ThousandSeparator := GetLocaleChar(LOCALE_SYSTEM_DEFAULT, LOCALE_STHOUSAND, '.');
  FormatSettings.DecimalSeparator := GetLocaleChar(LOCALE_SYSTEM_DEFAULT, LOCALE_SDECIMAL, '.');
{$ELSE}
FormatSettings.DecimalSeparator := DecimalSeparator;
{$ENDIF RTL150_UP}

The above code will load the default decimal and thousand separators for the current system. If the user changed these settings the conversion will fail. This prevents JvValidateEdit from working correctly.

Proposed fix: replace "LOCALE_SYSTEM_DEFAULT" with "GetThreadLocale" to load the currently used decimal and thousand separators. I tested a number of scenarios and everything worked fine.

obones

2011-09-21 14:46

administrator   ~0018960

Have you seen this:

http://stackoverflow.com/questions/1767946/getthreadlocale-returns-different-value-than-getuserdefaultlcid

Seems like GetThreadLocale is not such a good idea after all

ThomasC

2011-09-21 16:35

reporter   ~0018965

We are able to reproduce the Problem on Windows Vista Business 32 and Windows 7 Business 64. The screenshots below show the dialogs used to change these settings.

Steps:
- Change your format settings to "German (Germany)"
  http://1.bp.blogspot.com/-05cWKX7SVUE/Ti7hPCJfI7I/AAAAAAAAAEg/gBcS-u7l3eQ/s1600/Changing+Time+Format+Windows+7.png
- Change your system locale to "English (USA)"
  (http://www.sisulizer.de/_img/codepage-problems/w7-region-and-language-administrative.jpg)

Your DecimalSeparator will now be "," according to Windows. Entering floating point numbers in TJvValidateEdit will now fail. E.g entering "1,23" will be converted into "123,00". Notice how you can enter "," bot not ".".

The underlying problem seems to be that JvValidateEdit uses different methods of obtaining DecimalSeparator.

(1) TJvCustomValidateEdit.IsValidChar in JvValidateEdit.pas uses "{$IFDEF RTL220_UP}FormatSettings.{$ENDIF RTL220_UP}DecimalSeparator".

(2) Several other methods in this unit use JvSafeStrToFloatDef from JvJCLUtils.pas which calls _JvSafeStrToFloat in JvJCLUtils.pas. Ultimately "GetLocaleChar(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, '.')" is called.

(1) always returned the correct value in our tests. In the above scenario "," is returned which corresponds the chosen format setting "German (Germany)".
(2) seems to return values corresponding to chosen system locale. In the above scenario this is "." for "English (USA)".

Obviously both can't be right at the same time. Windows seems to give precedence to format settings which are per user settings. (2) can be changed to return these user settings rather than the system settings.

Proposed fix: replace "LOCALE_SYSTEM_DEFAULT" with "LOCALE_USER_DEFAULT" in JvJCLUtils.pas (lines 7014 and 7015). This also avoids using "GetThreadLocale" which seems to have problems of its own.

ThomasC

2011-09-21 16:39

reporter   ~0018967

Sorry, the parenthesis broke the second link. Here is a working link:
http://www.sisulizer.de/_img/codepage-problems/w7-region-and-language-administrative.jpg

obones

2011-09-22 11:34

administrator   ~0018971

Fair enough, thanks for the pointers

ArnoBrinkman

2012-01-19 16:07

reporter   ~0019319

Please change in JvJCLUtils the function _JvSafeStrToFloat() the next lines

-----------------------------------------------------------------------
  { Locale Handling logic October 2008 supercedes former StrToFloatUS functionality. }
  {$IFDEF RTL150_UP}
  LocalFormatSettings.ThousandSeparator := GetLocaleChar(LOCALE_SYSTEM_DEFAULT, LOCALE_STHOUSAND, '.');
  LocalFormatSettings.DecimalSeparator := GetLocaleChar(LOCALE_SYSTEM_DEFAULT, LOCALE_SDECIMAL, '.');
  {$ELSE}
-----------------------------------------------------------------------

to these lines:

-----------------------------------------------------------------------
  { Locale Handling logic October 2008 supercedes former StrToFloatUS functionality. }
  {$IFDEF RTL150_UP}
  LocalFormatSettings.ThousandSeparator := GetLocaleChar(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, '.');
  LocalFormatSettings.DecimalSeparator := GetLocaleChar(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, '.');
  {$ELSE}
-----------------------------------------------------------------------


This fucking bug caused us a headache and lot of time, because in our application the values were multiplied by 10^x (where x = number of decimals) everywhere the TJvValidateEdit is used. You can image which dramatic effects this has :(

Mainly on Terminal Systems we see this, because the DecimalSeparator in LOCALE_SYSTEM_DEFAULT is totally different from the LOCALE_USER_DEFAULT one.

cguser

2012-01-19 16:32

reporter   ~0019320

Arno,

I've come with a different fix that didn't touched JvJCLUtils, just check case 0005579.

ArnoBrinkman

2012-01-19 17:29

reporter   ~0019321

@cguser,

I see your fix more as a workaround, i think the JvSafeStrToFloat() should behave correctly for the users regional settings.
Probably this function is also used by other components/functions and will fail therefor also.

cguser

2012-01-19 17:43

reporter   ~0019322

Arno,

Likely so. I do not have the details fresh on my memory anymore, so I won't comment on the technical details. It does puzzle me, however, that for such a serious (and visible) issue, no clean solution has been applied after this long.

I still need to mind to manually patch this each and every time Jedi components are updated. Every now and then, some coleague gets bitten by this.

ArnoBrinkman

2012-01-19 18:26

reporter   ~0019323

I see indeed this issue is hurting many people already since 2009/2010.
We upgraded recently to latest version, because we slowly start migrating everything to Delphi XE2. While we were using a very old version we were not bitten by it earlier.

HOW CAN IT BE THIS BUG IS STILL ALIVE??

Please, somebody with commit rights fix this.

SteffenSchm

2012-01-19 18:35

reporter   ~0019324

I started this topic in 2009 and solved the problem for my application by the fix descriped 2010-08-10.

I am not a advanced programmer and do not understand in common why the jvl needs to read the chars for Decimal and ThousandSeparator again. Why not using the constants already defined by Delphi?

obones

2012-02-24 11:56

administrator   ~0019528

This is now fixed in SVN

Issue History

Date Modified Username Field Change
2009-12-21 17:30 SteffenSchm New Issue
2009-12-28 16:42 obones Note Added: 0017033
2009-12-28 16:42 obones Status new => feedback
2009-12-29 12:58 SteffenSchm Note Added: 0017044
2010-06-07 13:54 obones Note Added: 0017460
2010-07-26 18:08 jkelley File Added: JvValidateEdit Bug.zip
2010-07-26 18:12 jkelley Note Added: 0017542
2010-08-20 16:05 SteffenSchm File Added: Project2.zip
2010-08-20 16:05 SteffenSchm File Added: Pic1.JPG
2010-08-20 16:06 SteffenSchm File Added: Pic2.JPG
2010-08-20 16:18 SteffenSchm Note Added: 0017612
2010-10-08 16:23 obones Note Added: 0017820
2011-06-07 17:25 obones Note Added: 0018568
2011-06-07 18:01 obones Relationship added related to 0005579
2011-06-07 18:01 obones Relationship added related to 0005385
2011-06-07 18:13 cguser Note Added: 0018642
2011-09-16 14:44 ThomasC Note Added: 0018894
2011-09-21 14:46 obones Note Added: 0018960
2011-09-21 16:35 ThomasC Note Added: 0018965
2011-09-21 16:39 ThomasC Note Added: 0018967
2011-09-22 11:34 obones Note Added: 0018971
2011-09-22 11:34 obones Status feedback => acknowledged
2012-01-19 16:07 ArnoBrinkman Note Added: 0019319
2012-01-19 16:32 cguser Note Added: 0019320
2012-01-19 17:29 ArnoBrinkman Note Added: 0019321
2012-01-19 17:43 cguser Note Added: 0019322
2012-01-19 18:26 ArnoBrinkman Note Added: 0019323
2012-01-19 18:35 SteffenSchm Note Added: 0019324
2012-02-24 11:56 obones Note Added: 0019528
2012-02-24 11:56 obones Status acknowledged => resolved
2012-02-24 11:56 obones Fixed in Version => Daily / SVN
2012-02-24 11:56 obones Resolution open => fixed
2012-02-24 11:56 obones Assigned To => obones
2012-02-24 17:37 obones Relationship added related to 0005774
2012-02-24 17:37 obones Relationship replaced has duplicate 0005774
2012-09-10 14:15 obones Fixed in Version Daily / SVN => 3.46