This isn't Highlights magazine: Sort keys and why they change

Raymond Chen

Some time ago, Ry Jones gave some examples of Quotable Raymond, including the following:

How to make a good doc bug report:

1. Don’t embed pictures. … This isn’t Highlights magazine.

What Ry didn’t realize is that his “…” totally misrepresented the message. There were actually two separate items, but he combined them into one and replaced the missing parts with “…”. I already ranted some time ago about embedding pictures. Today I’ll rant about the second item, which is turning a bug report into the Spot the difference between these two pictures game in Highlights magazine.

A customer reported that the LCMap­String function was returning incorrect results on Windows 7. To illustrate, they included a sample program with the Windows XP and Windows 7 output.

#include <windows.h>
char bad[] = "... a very long string...";
char dest[10000];
int main()
{
    int nChr, i;
    nChr = LCMapStringA(1033,  /* English (US) */
                  LCMAP_SORTKEY,
                  bad,
                  -1,    /* source is NULL terminated */
                  dest,  /* destination */
                  sizeof(dest));  /* dest size */
    /* print out returned number of bytes as hexadecimal */
    for (i = 0; i < nChr; i++)
        printf("%02x ", (unsigned char)dest[i]);
    printf("\n");
}

On Windows XP, we get the correct sort key:

0e 48 0e 7c 0e 8a 0e 21 0e 51 07 02 0e 32 0e 7e 0e 91 0e 9f 0e 51 07 02 0e 1a 0e 7c 0e 48 0e 7c 0e 8a 07 02 0e 91 0e 32 0e 99 07 02 0e 02 0e 51 0e 21 0e 99 07 2f 07 02 0e 0a 0e 7c 0e 70 0e 91 0e 21 0e 0a 0e 99 0e 21 0e 99 0e 9f 0e 8a 07 02 0e 02 0e 1a 0e 32 0e 7e 0e 32 0e 91 0e 32 0e 0a 0e 32 0e 70 0e 25 07 02 0e 21 0e 48 0e 32 0e 99 07 2f 07 02 0e 91 0e 21 0e 1a 07 02 0e 1a 0e 7c 07 02 0e 21 0e 32 0e 9f 0e 91 0e 51 0e 7c 0e 1a 07 02 0e 99 0e 21 0e 51 0e 7e 0e 7c 0e 8a 07 02 0e 32 0e 70 0e 0a 0e 32 0e 1a 0e 32 0e 1a 0e 9f 0e 70 0e 99 07 02 0e 9f 0e 99 07 02 0e 48 0e 02 0e 09 0e 7c 0e 8a 0e 21 07 02 0e 21 0e 99 07 02 0e 1a 0e 7c 0e 48 0e 7c 0e 8a 0e 21 07 02 0e 51 0e 02 0e 25 0e 70 0e 02 07 02 0e 02 0e 48 0e 32 0e 89 0e 9f 0e 02 07 33 07 02 08 14 07 02 0e 9f 0e 99 07 02 0e 21 0e 70 0e 32 0e 51 07 02 0e 02 0e 1a 07 02 0e 51 0e 32 0e 70 0e 32 0e 51 07 02 0e a2 0e 21 0e 70 0e 32 0e 02 0e 51 07 2f 07 02 0e 89 0e 9f 0e 32 0e 91 07 02 0e 70 0e 7c 0e 91 0e 99 0e 8a 0e 9f 0e 1a 07 02 0e 21 0e a6 0e 21 0e 8a 0e 0a 0e 32 0e 99 0e 02 0e 99 0e 32 0e 7c 0e 70 07 02 0e 9f 0e 48 0e 48 0e 02 0e 51 0e 0a 0e 7c 07 02 0e 48 0e 02 0e 09 0e 7c 0e 8a 0e 32 0e 91 07 02 0e 70 0e 32 0e 91 0e 32 07 02 0e 9f 0e 99 07 02 0e 02 0e 48 0e 32 0e 89 0e 9f 0e 32 0e 7e 07 02 0e 21 0e a6 07 02 0e 21 0e 02 07 02 0e 0a 0e 7c 0e 51 0e 51 0e 7c 0e 1a 0e 7c 07 02 0e 0a 0e 7c 0e 70 0e 91 0e 21 0e 89 0e 9f 0e 02 0e 99 07 33 07 02 0e 1a 0e 9f 0e 32 0e 91 07 02 0e 02 0e 9f 0e 99 0e 21 07 02 0e 32 0e 8a 0e 9f 0e 8a 0e 21 07 02 0e 1a 0e 7c 0e 48 0e 7c 0e 8a 07 02 0e 32 0e 70 07 02 0e 8a 0e 21 0e 7e 0e 8a 0e 21 0e 2c 0e 21 0e 70 0e 1a 0e 21 0e 8a 0e 32 0e 99 07 02 0e 32 0e 70 07 02 0e a2 0e 7c 0e 48 0e 9f 0e 7e 0e 99 0e 02 0e 99 0e 21 07 02 0e a2 0e 21 0e 48 0e 32 0e 99 07 02 0e 21 0e 91 0e 91 0e 21 07 02 0e 0a 0e 32 0e 48 0e 48 0e 9f 0e 51 07 02 0e 1a 0e 7c 0e 48 0e 7c 0e 8a 0e 21 07 02 0e 21 0e 9f 07 02 0e 23 0e 9f 0e 25 0e 32 0e 02 0e 99 07 02 0e 70 0e 9f 0e 48 0e 48 0e 02 07 02 0e 7e 0e 02 0e 8a 0e 32 0e 02 0e 99 0e 9f 0e 8a 07 33 07 02 0e 21 0e a6 0e 0a 0e 21 0e 7e 0e 99 0e 21 0e 9f 0e 8a 07 02 0e 91 0e 32 0e 70 0e 99 07 02 0e 7c 0e 0a 0e 0a 0e 02 0e 21 0e 0a 0e 02 0e 99 07 02 0e 0a 0e 9f 0e 7e 0e 32 0e 1a 0e 02 0e 99 0e 02 0e 99 07 02 0e 70 0e 7c 0e 70 07 02 0e 7e 0e 8a 0e 7c 0e 32 0e 1a 0e 21 0e 70 0e 99 07 2f 07 02 0e 91 0e 9f 0e 70 0e 99 07 02 0e 32 0e 70 07 02 0e 0a 0e 9f 0e 48 0e 7e 0e 02 07 02 0e 89 0e 9f 0e 32 07 02 0e 7c 0e 23 0e 23 0e 32 0e 0a 0e 32 0e 02 07 02 0e 1a 0e 21 0e 91 0e 21 0e 8a 0e 9f 0e 70 0e 99 07 02 0e 51 0e 7c 0e 48 0e 48 0e 32 0e 99 07 02 0e 02 0e 70 0e 32 0e 51 07 02 0e 32 0e 1a 07 02 0e 21 0e 91 0e 99 07 02 0e 48 0e 02 0e 09 0e 7c 0e 8a 0e 9f 0e 51 07 33 01 01 12 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 12 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 12 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 12 01 01 81 fb 06 82 00

but on Windows 7 the output is wrong:

0e 48 0e 7c 0e 8a 0e 21 0e 51 07 02 0e 32 0e 7e 0e 91 0e 9f 0e 51 07 02 0e 1a 0e 7c 0e 48 0e 7c 0e 8a 07 02 0e 91 0e 32 0e 99 07 02 0e 02 0e 51 0e 21 0e 99 07 2f 07 02 0e 0a 0e 7c 0e 70 0e 91 0e 21 0e 0a 0e 99 0e 21 0e 99 0e 9f 0e 8a 07 02 0e 02 0e 1a 0e 32 0e 7e 0e 32 0e 91 0e 32 0e 0a 0e 32 0e 70 0e 25 07 02 0e 21 0e 48 0e 32 0e 99 07 2f 07 02 0e 91 0e 21 0e 1a 07 02 0e 1a 0e 7c 07 02 0e 21 0e 32 0e 9f 0e 91 0e 51 0e 7c 0e 1a 07 02 0e 99 0e 21 0e 51 0e 7e 0e 7c 0e 8a 07 02 0e 32 0e 70 0e 0a 0e 32 0e 1a 0e 32 0e 1a 0e 9f 0e 70 0e 99 07 02 0e 9f 0e 99 07 02 0e 48 0e 02 0e 09 0e 7c 0e 8a 0e 21 07 02 0e 21 0e 99 07 02 0e 1a 0e 7c 0e 48 0e 7c 0e 8a 0e 21 07 02 0e 51 0e 02 0e 25 0e 70 0e 02 07 02 0e 02 0e 48 0e 32 0e 89 0e 9f 0e 02 07 33 07 02 08 14 07 02 0e 9f 0e 99 07 02 0e 21 0e 70 0e 32 0e 51 07 02 0e 02 0e 1a 07 02 0e 51 0e 32 0e 70 0e 32 0e 51 07 02 0e a2 0e 21 0e 70 0e 32 0e 02 0e 51 07 2f 07 02 0e 89 0e 9f 0e 32 0e 91 07 02 0e 70 0e 7c 0e 91 0e 99 0e 8a 0e 9f 0e 1a 07 02 0e 21 0e a6 0e 21 0e 8a 0e 0a 0e 32 0e 99 0e 02 0e 99 0e 32 0e 7c 0e 70 07 02 0e 9f 0e 48 0e 48 0e 02 0e 51 0e 0a 0e 7c 07 02 0e 48 0e 02 0e 09 0e 7c 0e 8a 0e 32 0e 91 07 02 0e 70 0e 32 0e 91 0e 32 07 02 0e 9f 0e 99 07 02 0e 02 0e 48 0e 32 0e 89 0e 9f 0e 32 0e 7e 07 02 0e 21 0e a6 07 02 0e 21 0e 02 07 02 0e 0a 0e 7c 0e 51 0e 51 0e 7c 0e 1a 0e 7c 07 02 0e 0a 0e 7c 0e 70 0e 91 0e 21 0e 89 0e 9f 0e 02 0e 99 07 33 07 02 0e 1a 0e 9f 0e 32 0e 91 07 02 0e 02 0e 9f 0e 99 0e 21 07 02 0e 32 0e 8a 0e 9f 0e 8a 0e 21 07 02 0e 1a 0e 7c 0e 48 0e 7c 0e 8a 07 02 0e 32 0e 70 07 02 0e 8a 0e 21 0e 7e 0e 8a 0e 21 0e 2c 0e 21 0e 70 0e 1a 0e 21 0e 8a 0e 32 0e 99 07 02 0e 32 0e 70 07 02 0e a2 0e 7c 0e 48 0e 9f 0e 7e 0e 99 0e 02 0e 99 0e 21 07 02 0e a2 0e 21 0e 48 0e 32 0e 99 07 02 0e 21 0e 91 0e 91 0e 21 07 02 0e 0a 0e 32 0e 48 0e 48 0e 9f 0e 51 07 02 0e 1a 0e 7c 0e 48 0e 7c 0e 8a 0e 21 07 02 0e 21 0e 9f 07 02 0e 23 0e 9f 0e 25 0e 32 0e 02 0e 99 07 02 0e 70 0e 9f 0e 48 0e 48 0e 02 07 02 0e 7e 0e 02 0e 8a 0e 32 0e 02 0e 99 0e 9f 0e 8a 07 33 07 02 0e 21 0e a6 0e 0a 0e 21 0e 7e 0e 99 0e 21 0e 9f 0e 8a 07 02 0e 91 0e 32 0e 70 0e 99 07 02 0e 7c 0e 0a 0e 0a 0e 02 0e 21 0e 0a 0e 02 0e 99 07 02 0e 0a 0e 9f 0e 7e 0e 32 0e 1a 0e 02 0e 99 0e 02 0e 99 07 02 0e 70 0e 7c 0e 70 07 02 0e 7e 0e 8a 0e 7c 0e 32 0e 1a 0e 21 0e 70 0e 99 07 2f 07 02 0e 91 0e 9f 0e 70 0e 99 07 02 0e 32 0e 70 07 02 0e 0a 0e 9f 0e 48 0e 7e 0e 02 07 02 0e 89 0e 9f 0e 32 07 02 0e 7c 0e 23 0e 23 0e 32 0e 0a 0e 32 0e 02 07 02 0e 1a 0e 21 0e 91 0e 21 0e 8a 0e 9f 0e 70 0e 99 07 02 0e 51 0e 7c 0e 48 0e 48 0e 32 0e 99 07 02 0e 02 0e 70 0e 32 0e 51 07 02 0e 32 0e 1a 07 02 0e 21 0e 91 0e 99 07 02 0e 48 0e 02 0e 09 0e 7c 0e 8a 0e 9f 0e 51 07 33 01 01 12 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 12 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 12 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 12 01 01 ff 82 82 12 00

This is what I meant by the Spot the difference between these two pictures game. Who wants to sit there and compare two 900-byte sequences byte-by-byte? (On top of that, the customer liaison forwarded the question to an internal peer-to-peer discussion group. Peer-to-peer discussion groups do not come with a service level agreement, and if you ask a question which makes heavy demands on the reader just to understand the question, don’t be surprised if nobody answers.)

If you want an explanation of why two things are different, you need to point out where the difference is. This often happens with screen shots, where a customer includes two different screen shots and asks for an explanation of why they are different, without indicating where the difference is. Are they complaining that the font is different? That ClearType is enabled in one screen shot but not the other? The hard drive in the first screen shot has more free space than the one in the second screen shot?

Anyway, back to the sort keys. (As a refresher, you can read Michael Kaplan’s explanation of sort keys.) The documentation for LCMap­String says

dwMapFlags [in]

Flags specifying the type of transformation to use during string mapping or the type of sort key to generate. For detailed definitions, see the dwMapFlags parameter of LCMapStringEx.

If you follow the instructions and consult the dwMapFlags parameter of the LCMapStringEx function, you find

LCMAP_SORTKEY Produce a normalized sort key. If the LCMAP_SORTKEY flag is not specified, the function performs string mapping. For details of sort key generation and string mapping, see the Remarks section.

If you follow the instructions and go to the Remarks section looking for LCMAP_SORTKEY, you find

The application can use LCMapString or LCMapStringEx to generate a sort key. To do this, the application specifies LCMAP_SORTKEY for the dwMapFlags parameter. For more information, see Handling Sorting in Your Applications.

(A link to Handling Sorting in Your Applications also exists on the LCMapString page, but let’s say you didn’t see that.)

If you follow the instructions and read the Handling Sorting in Your Applications page,

Use Sort Versioning

A sorting table has two numbers that identify its version: the defined version and the NLS version. Both numbers are DWORD values, composed of a major value and a minor value. …

Note For a major version, one or more code points are changed so that the application must re-index all data for comparisons to be valid. For a minor version, nothing is moved but code points are added. For this type of version, the application only has to re-index strings with previously unsortable values.

And there you have your answer. Sort keys generated by different major versions are not compatible. I don’t know what NLS version for English was included with Windows XP, though I did check that on Windows Vista SP2 it is major version 0x0405 (minor version 0) and on Windows 7 it is major version 0x601 (minor version 1). So whatever it was on Windows XP, it was presumably less than or equal to 0x0405, which means that it’s definitely different from the major version on Windows 7.

And like the documentation says, when the major version changes, you need to regenerate your sort keys because sort keys from different major versions are not compatible.

Michael Kaplan discussed other issues arising from changing the major version as well as various changes to the sort keys over time.

If you find yourself using a program that relies on sort keys remaining stable even across major versions, you can try applying the EmulateSorting compatibility fix.

0 comments

Discussion is closed.

Feedback usabilla icon