by Michael S. Kaplan, published on 2005/12/15 05:01 -05:00, original URI: http://blogs.msdn.com/b/michkap/archive/2005/12/15/503493.aspx
Back in September I talked about the article Cathy and I had written entitled Extend Your Code's Global Reach With New Features In The .NET Framework 2.0.
One of the many new globalization features in the .NET Framework that it talked about was "Windows only" cultures.
From the article:
The .NET Framework was released at an interesting point in the history of Windows: after Windows XP was released, but before Windows Server™ 2003. As a result, the list of cultures available in the .NET Framework matched the locales included in Windows XP (and provided a superset of the locales included in previous versions of Windows). Developers didn't have to consider the consequences of new locales on Windows. There would be no issue with how these new Windows locales would interact with a version of the .NET Framework that tries to, for example, base its culture settings on the choices available in the operating system. The .NET Framework has always maintained its own data so that it could return the same results on all possible platforms, and until Windows XP SP2, this had never caused any difficulties.
The globalization development team had to address this problem, however, after Windows XP SP2 shipped with 25 new locales. For a listing of the new locales for SP2 only, see New Locale and Language Features in Windows XP. Imagine our surprise when one of our testers discovered that you could not even start a managed application when installing an early build of SP2 and using one of those new locales as the default user locale! This was clearly an issue we needed to address immediately in earlier versions of the .NET Framework, and fix more fully in the .NET Framework 2.0.
Future Windows service packs may include additional locales. Windows Vista™ (formerly codenamed "Longhorn") is expected to ship with additional locales above and beyond what have been supported to date; so that presents a very possible situation where an installed version of Windows could include locales that are not recognized cultures in the .NET Framework. Therefore, it's imperative that the .NET Framework gracefully handle Windows locales in a managed environment. Figure 3 shows Francois Liger's Culture Explorer (available for download from www.gotdotnet.com), which illustrates how the .NET Framework 2.0 picks up the new locales in Windows Vista through the Windows-only cultures.
The .NET Framework can now handle previously unidentified Windows locales by using the Win32® API to synthesize a CultureInfo object any time a locale supported in Windows has no corresponding culture in the .NET Framework. These cultures can be created either by name or by LCID, just like any other culture. The following code illustrates how to create a culture by name (new cultures on Windows XP SP2 include mt-MT, bs-BA-Latn, smn-FI, smj-NO, smj-SE, sms-FI, sma-NO, sma-SE, quz-BO, quz-EC, quz-PE, ml-IN, bn-IN, cy-GB, and more):
' Visual Basic
For Each ci As CultureInfo In CultureInfo.GetCultures( _
foreach(CultureInfo culture in CultureInfo.GetCultures(
This is obviously a break from the typical practice in the .NET Framework of giving the same results independent of the platform. However, given the choice between failing completely and succeeding when there is a way to retrieve the data, the option of handling Windows-only cultures successfully provides a better solution for developers who expect some type of culture data returned by the .NET Framework for these Windows-only locales.
Now although the principle behind these cultures is easy to state, the actual work to support them was quite extensive.
For example -- you know that FindNLSString function that I am always talking about? One of the big reasons for its inclusion was better support for the .NET CompareInfo class and its IsPrefix, IsSuffix, IndexOf, and LastIndexOf methods in Windows only cultures!
Now we get to that bug I was talking about....
The CompareInfo.IndexOf method (and the more commonly called String.IndexOf method that calls it) has several overloads, many of which take a startIndex parameter. Unfortunately, CompareInfo.IndexOf is not adding that value to the result when the underlying call to FindNLSString succeeds. For example, if a call is done on Windows Vista with the new Occitan (France) locale that helps to support the Occitan (France) Windows only culture:
int idx = CompareInfo.GetCompareInfo("oc-FR").IndexOf("ABCDEFGHIJ", "J", 5)
will return 4 rather than 9, since the startIndex of 5 is not being taken into account after the FindNLSString call returns 4.
Of course the bug will be fixed, and for now it is mentioned here in this blog and maybe it will end up in an MSKB article, too.
Perhaps it could even be considered a useful object lesson in the hazards of writing code that cannot be fully tested when the code is being integrated (.NET 2.0 of course had a very different ship cycle from Vista -- the original code could not even be tested until long after it was written!).
But it is still one of those kinds of bugs you wish you'd found. Or to be more accurate, that I wish I'd found.
One thing for sure, it definitely makes you more careful the next time!
This post brought to you by "ử" (U+1eed, a.k.a. LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE)
go to newer or older post, or back to index or month or day