I added this to the msdn wiki for collation, but I'll blog about it here too. 

Occasionally we change the sorting behavior because new code points are added to Unicode, or we find out betterer data or made a mistake (never!) or whatever.  Unfortunately if you built an index (like for a binary search), then when you use CompareStringEx it might not find what you're looking for if the sort (collation) order has changed.

To help work around that we provide the GetNLSVersionEx() function which can tell the version of the sort your using.  Then when you use the data you can check that the sort hasn't changed.  If it has, then you need to reindex your data.

To prepare for this step you need to remember what version your data is indexed with, so when indexing:

  1. Use GetNLSVersionEx() to retrieve an NLSVERSIONINFOEX structure when doing the original indexing of your data.
  2. Store the following properties with your index to identify the version:
    • NLSVERSIONINFOEX.dwNLSVersion - This specifies the version of the sorting table you're using.
    • NLSVERSIONINFOEX.dwEffectiveId - This specifies the effective locale of your sort.  A custom locale will point to an in-box locale's sort.
    • NLSVERSIONINFOEX.guidCustomVersion - This is a GUID specifying a specific custom sort for custom locales that have them.

Then when you use your data (probably just the first time when you run your app since people are unlikely to upgrade windows while your app is running :)):

  1. When using the index use GetNlsVersionEx() to discover the version of your data.
  2. If any of the three properties has changed, the sorting data you're using could return different results and any indexing you have may fail to find records.
  3. If you KNOW that your data doesn't contain invalid Unicode code points (ie: all of your strings passed a call to IsNLSDefineString()) then you may consider them the same if ONLY the low byte of dwNLSVersion changed (the minor version described in MSDN http://msdn2.microsoft.com/en-us/library/ms776402.aspx).

So if the versions are differrent, then you need to reindex before you try to use the index.

Note that sometimes codepoints are merely added to Unicode and the existing code points don't change their orders.  In this case the "minor" version is updated but the rest stays the same.  If you know that your app didn't index anything not supported (ie: all of your strings passed a call to IsNLSDefinedString()), then you don't have to reindex just for the minor version change.

The specific fields of the NLSVERSIONINFOEX structure used for sort versioning are below.  Remember that when you ask for the version you pass in a locale name (ie: en-US or fj-FJ), so the data isn't the same for all locales.

dwNLSVersion
The version number of the collation in the form 0xRRMMMMmm, where R equals Reserved, M equals major, and m equals minor.
dwDefinedVersion
Unicode defined version. This value is used to track changes in the repertoire of Unicode code points. This goes up when Unicode adds more code points, but isn't very interesting for collation versioning, the NLS version could still go up if this stays the same.
dwEffectiveId
Identifier of the sort order used for the input locale for the represented version. This would be 0409 for en-US, but for a custom locale en-Mine that uses 0809 for a sort order identifier, this member contains "0809". If this member specifies a "real" sort, guidCustomVersion is set to an empty GUID.
guidCustomVersion
Unique GUID for the behavior of a custom sort used by the custom locale for the represented dwNLSversion.

Notice that for "built-in" locales like en-US, de-DE, ja-JP, etc, you'll get a version number and probably the same ID in the effective ID.  For custom locales however you may have differing effective ID's, or even GUIDs for differing behavior.  For example, I may install a custom fj-FJ locale that used an 0409 sort, but in the future that could change to an 080c sort if I discovered that sort was more appropriate. 

Hope that helps, Shawn