https://bugs.winehq.org/show_bug.cgi?id=46842
Anastasius Focht focht@gmx.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Ever confirmed|0 |1 Status|UNCONFIRMED |NEW Component|-unknown |kernel32 Keywords| |source
--- Comment #10 from Anastasius Focht focht@gmx.net --- Hello IanS,
confirming now - so I can sleep well again ;-)
The culprit seems to be .NET Framework 4.x and Windows version set to at least 'Windows 7' (default in new WINEPREFIXes). If you change it to Windows Vista or lower (Windows XP) it works.
My WINEPREFIX was kept at 'Windows XP' due to winetricks recipe which is not necessary anymore. .NET Framework 4.x CLR uses different ways on Windows 7+ to determine various culture/localization information (GetLocaleInfoEx vs. registry)
Suspecting this, I found some example code to test this here:
https://docs.microsoft.com/en-us/dotnet/api/system.globalization.numberforma...
I adapted it to build with lower .NET Frameworks/SDK and get rid of unneeded stuff:
'numberformatinfo.cs'
--- snip --- using System; using System.Collections; using System.Globalization; using System.Reflection;
namespace Example { public class NumberFormatInfoExample { public static void Main() { NumberFormatInfo nfi = CultureInfo.CurrentCulture.NumberFormat; Console.WriteLine("Properties of NumberFormat.CurrentInfo object:"); PropertyInfo[] props = nfi.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); foreach (PropertyInfo prop in props) { if (prop.PropertyType.IsArray) { Array arr = prop.GetValue(nfi, null) as Array; Console.Write(String.Format(" {0}: ", prop.Name) + "{ "); int ctr = 0; foreach (object item in arr) { Console.Write("{0}{1}", item, ctr == arr.Length - 1 ?" }" : ", "); ctr++; } Console.WriteLine(); } else { Console.WriteLine(" {0}: {1}", prop.Name, prop.GetValue(nfi, null)); } } } } } --- snip ---
You can use LC_ALL to override/check for specific locales.
Running the test app with 'Windows XP' setting:
--- snip --- $ LC_ALL="en_US.utf8" wine ./numberformatinfo.exe
Properties of NumberFormat.CurrentInfo object: CurrencyDecimalDigits: 2 CurrencyDecimalSeparator: . IsReadOnly: True CurrencyGroupSizes: { 3 } NumberGroupSizes: { 3 } PercentGroupSizes: { 3 } CurrencyGroupSeparator: , CurrencySymbol: $ NaNSymbol: NaN CurrencyNegativePattern: 0 NumberNegativePattern: 1 PercentPositivePattern: 0 PercentNegativePattern: 0 NegativeInfinitySymbol: -Infinity NegativeSign: - NumberDecimalDigits: 2 NumberDecimalSeparator: . NumberGroupSeparator: , CurrencyPositivePattern: 0 PositiveInfinitySymbol: Infinity PositiveSign: + PercentDecimalDigits: 2 PercentDecimalSeparator: . PercentGroupSeparator: , PercentSymbol: % PerMilleSymbol: % NativeDigits: { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } DigitSubstitution: None --- snip ---
With 'Windows 7' setting:
--- snip --- $ LC_ALL="en_US.utf8" wine ./numberformatinfo.exe
Properties of NumberFormat.CurrentInfo object: CurrencyDecimalDigits: 2 CurrencyDecimalSeparator: , IsReadOnly: True CurrencyGroupSizes: { 3 } NumberGroupSizes: { 3 } PercentGroupSizes: { 3 } CurrencyGroupSeparator: . CurrencySymbol: ? NaNSymbol: NaN CurrencyNegativePattern: 8 NumberNegativePattern: 1 PercentPositivePattern: 0 PercentNegativePattern: 0 NegativeInfinitySymbol: NegativeSign: - NumberDecimalDigits: 2 NumberDecimalSeparator: , NumberGroupSeparator: . CurrencyPositivePattern: 3 PositiveInfinitySymbol: PositiveSign: + PercentDecimalDigits: 2 PercentDecimalSeparator: , PercentGroupSeparator: . PercentSymbol: PerMilleSymbol: NativeDigits: { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } DigitSubstitution: None --- snip ---
There are various number format properties missing/incorrect.
For reference .NET Core:
https://github.com/dotnet/corefx/blob/1f7c6362d3ad7cebeb748aabfc7e8303b703ed...
https://github.com/dotnet/corefx/blob/1f7c6362d3ad7cebeb748aabfc7e8303b703ed...
.NET number parsing code relies on it.
https://github.com/dotnet/corefx/blob/v2.2.3/src/Common/src/CoreLib/System/N...
I also did some debugging of JIT code using cordbg - not for the faint hearted ;-) Just for reference, the simple C# example app already shows it.
--- snip --- $ wine "c:\Program Files\Debugging Tools for Windows (x86)\cdb.exe" ./bug46842.exe ... 0:000> sxe ld clrjit
0:000> g
0:000> .loadby sos clr
0:000> !name2ee *!System.Double.TryParse
Module: 79881000 Assembly: mscorlib.dll Token: 06000b97 MethodDesc: 798f5440 Name: System.Double.TryParse(System.String, Double ByRef) JITTED Code Address: 79b22cb0 ----------------------- Token: 06000b98 MethodDesc: 798f544c Name: System.Double.TryParse(System.String, System.Globalization.NumberStyles, System.IFormatProvider, Double ByRef) JITTED Code Address: 79ac767c ----------------------- Token: 06000bab MethodDesc: 798f55ac Name: System.Double.TryParse(System.String, System.Globalization.NumberStyles, System.Globalization.NumberFormatInfo, Double ByRef) JITTED Code Address: 79ac76b4 -------------------------------------- Module: 00372e9c Assembly: bug46842.exe
0:000> bp 79b22cb0
0:000> g ...
0:000> g Unable to parse '123AE6'. Breakpoint 0 hit
0:000> g Unable to parse ''. Breakpoint 0 hit
... 0:000> l+t
... 0:000> t
...
0:000> !IP2MD @eip MethodDesc: 799b71d8 Method Name: System.Number.ParseNumber(Char* ByRef, System.Globalization.NumberStyles, NumberBuffer ByRef, System.Text.StringBuilder, System.Globalization.NumberFormatInfo, Boolean) Class: 798dc1e4 MethodTable: 79ba6a48 mdToken: 06000e20 Module: 79881000 IsJitted: yes CodeAddr: 79ac5db0 Transparency: Critical
0:000> !clrstack OS Thread Id: 0x30 (0) Child SP IP Call Site 0032f1a0 79ac5db0 System.Number.ParseNumber(Char* ByRef, System.Globalization.NumberStyles, NumberBuffer ByRef, System.Text.StringBuilder, System.Globalization.NumberFormatInfo, Boolean) 0032f1b4 79ac6394 System.Number.TryStringToNumber(System.String, System.Globalization.NumberStyles, NumberBuffer ByRef, System.Text.StringBuilder, System.Globalization.NumberFormatInfo, Boolean) 0032f1e0 79b11f12 System.Number.TryParseDouble(System.String, System.Globalization.NumberStyles, System.Globalization.NumberFormatInfo, Double ByRef) 0032f2a4 79ac76d3 System.Double.TryParse(System.String, System.Globalization.NumberStyles, System.Globalization.NumberFormatInfo, Double ByRef) 0032f2c0 79b22ccc System.Double.TryParse(System.String, Double ByRef) 0032f2d0 003b0182 Example.Main() 0032f538 791421db [GCFrame: 0032f538]
0:000> !DumpIL 799b71d8 ilAddr = 79c1fd28 IL_0000: ldarg.2 IL_0001: ldc.i4.0 IL_0002: stfld NumberBuffer::scale IL_0007: ldarg.2 IL_0008: ldc.i4.0 IL_0009: stfld NumberBuffer::sign IL_000e: ldnull IL_000f: stloc.2 IL_0010: ldnull IL_0011: stloc.3 IL_0012: ldnull IL_0013: stloc.s VAR OR ARG 4 IL_0015: ldnull IL_0016: stloc.s VAR OR ARG 5 IL_0018: ldc.i4.0 IL_0019: stloc.s VAR OR ARG 6 IL_001b: ldarg.1 IL_001c: ldc.i4 256 IL_0021: and IL_0022: brfalse.s IL_0064 IL_0024: ldarg.s VAR OR ARG 4 IL_0026: callvirt System.Globalization.NumberFormatInfo::get_CurrencySymbol IL_002b: stloc.2 IL_002c: ldarg.s VAR OR ARG 4 IL_002e: ldfld System.Globalization.NumberFormatInfo::ansiCurrencySymbol IL_0033: brfalse.s IL_003d IL_0035: ldarg.s VAR OR ARG 4 IL_0037: ldfld System.Globalization.NumberFormatInfo::ansiCurrencySymbol IL_003c: stloc.3 IL_003d: ldarg.s VAR OR ARG 4 IL_003f: callvirt System.Globalization.NumberFormatInfo::get_NumberDecimalSeparator IL_0044: stloc.s VAR OR ARG 4 IL_0046: ldarg.s VAR OR ARG 4 IL_0048: callvirt System.Globalization.NumberFormatInfo::get_NumberGroupSeparator IL_004d: stloc.s VAR OR ARG 5 IL_004f: ldarg.s VAR OR ARG 4 IL_0051: callvirt System.Globalization.NumberFormatInfo::get_CurrencyDecimalSeparator IL_0056: stloc.0 IL_0057: ldarg.s VAR OR ARG 4 IL_0059: callvirt System.Globalization.NumberFormatInfo::get_CurrencyGroupSeparator IL_005e: stloc.1 IL_005f: ldc.i4.1 IL_0060: stloc.s VAR OR ARG 6 IL_0062: br.s IL_0074 IL_0064: ldarg.s VAR OR ARG 4 IL_0066: callvirt System.Globalization.NumberFormatInfo::get_NumberDecimalSeparator IL_006b: stloc.0 IL_006c: ldarg.s VAR OR ARG 4 IL_006e: callvirt System.Globalization.NumberFormatInfo::get_NumberGroupSeparator IL_0073: stloc.1 IL_0074: ldc.i4.0 IL_0075: stloc.s VAR OR ARG 7 IL_0077: ldc.i4.0 IL_0078: stloc.s VAR OR ARG 8
...
0:000> !clrstack -a OS Thread Id: 0x30 (0) Child SP IP Call Site 0032f150 79ac6260 System.Number.MatchChars(Char*, System.String) PARAMETERS: p (<CLR reg>) = 0x00c91230 str (<CLR reg>) = 0x00c91748 LOCALS: <no data> <no data> <no data>
0032f154 79ac5e7d System.Number.ParseNumber(Char* ByRef, System.Globalization.NumberStyles, NumberBuffer ByRef, System.Text.StringBuilder, System.Globalization.NumberFormatInfo, Boolean) PARAMETERS: str (0x0032f16c) = 0x0032f1b8 options (0x0032f18c) = 0x000000e7 number (0x0032f1b0) = 0x0032f270 sb (0x0032f1ac) = 0x00000000 numfmt (0x0032f1a8) = 0x00c9b584 parseDecimal (0x0032f1a4) = 0x00000000 LOCALS: 0x0032f168 = 0x00c9b6a0 0x0032f164 = 0x00c9b6b0 0x0032f160 = 0x00000000 0x0032f15c = 0x00000000 0x0032f158 = 0x00000000 0x0032f154 = 0x00000000 0x0032f188 = 0x00000000 <CLR reg> = 0x00000000 <CLR reg> = 0x00000001 0x0032f184 = 0x00000000 0x0032f180 = 0x00000000 <no data> 0x0032f17c = 0x00c91230 <CLR reg> = 0x00000000 <no data> <no data> <no data> <no data> <no data> <no data>
...
0:000> !do 0x00c91748 Name: System.String MethodTable: 79b9f9ac EEClass: 798d8bb0 Size: 16(0x10) bytes File: C:\windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll String: + Fields: MT Field Offset Type VT Attr Value Name 79ba2978 40000ed 4 System.Int32 1 instance 1 m_stringLength 79ba1dc8 40000ee 8 System.Char 1 instance 2b m_firstChar 79b9f9ac 40000ef 8 System.String 0 shared static Empty >> Domain:Value 001430c0:00c91228 << --- snip ---
$ wine --version wine-4.4
Regards