How the @#%&*! does CBS_SORT choose to sort it all out?

by Michael S. Kaplan, published on 2008/10/29 10:01 -04:00, original URI: http://blogs.msdn.com/b/michkap/archive/2008/10/29/9022296.aspx


The question was an interesting one:

My customer has a tree control with nodes sorted using CString::Compare(). In another part of the application he has the same list of names in a combo box that has the CBS_SORT style set. He wants names to appear in both controls in the same order. Currently they do not. We've tried changing the sort algorithm used in the tree to CString::Collate() and tried a few variations of ::CompareString(), but none of those match the ordering used internally with CBS_SORT set (particularly when names have hyphens or numbers).

The customer does not want to make the combo box owner-draw to override sorting because it will lose accessibility functionality based on this logic:

Thus, to achieve the task, he expects to know the algorithm used by CBS_SORT inside Combo Box. Is it allowed? If it’s not, is there any other workarounds that can help the customer?

Many thanks in advance

This question is interesting on multiple levels, actually.

First of all, it is about collation, which is always interesting to me. :-)

Then second it is interesting for the solution, which is of course to take the already sorted list and add it to the Combo Box without the CBS_SORT style, so that it will just be in that order. This way they match and there is nothing else to worry about.

well, other than the fact that the CString:::Compare (actually CStringT::Compare) order is actually the _tcscmp order, which is basically a binary type if order that is not terribly useful to give to users. They'd almost certainly be happier with just about any kind of linguistic result and probably don't need or want to be exposed to an internal ordering that wouldn't be helpful for them.

Think of the precedent we have in file names -- the order which NTFS uses to do sorting internally is nothing to do with the order that Explorer uses to sort them when they are being viewed. That order would just confuse any normal, sane person! :-)

Then of course the question is fascinating for the uestion in the title -- what the hell is the sort order of a Com Box with the CBS_SORT style on it?

The documentation in this case claims:

Automatically sorts strings entered into the list box.

which is not terribly helpful for us, is it?

There is a good hint in the CB_SETLOCALE message documentation:

An application sends a CB_SETLOCALE message to set the current locale of the combo box. If the combo box has the CBS_SORT style and strings are added using CB_ADDSTRING, the locale of a combo box affects how list items are sorted.

Now we're getting somewhere!

If the order is locale-based, it really suggests a CompareString type thing, doesn't it?

Of course StrCmpLogical is CompareString-based (ref: What is up with number sorting?), but neither function's ordering matches the CBS_SORT ordering.

The key is know what is the difference in this case.

The answer was provided by Jay Krell, who I have mentioned before in the same context (tracking down problems!):

Reading the code suggests it is roughly equivalent to CompareStringW(ignore case), except that it treats initial left square brackets differently (seriously)....
 
But if it isn't documented, don't depend on it, of course. (unless you can convince the owners to document it..)

And no, this is unlikely to ever be documented explicitly -- and no, writing about it here doesn't count as documentation! :-)

Probably not worth duplicating, but the logic, which I suspect is quite old, has an illuminating comment at the top of the function that describes the thinking:

* This is a version of lstrcmpi() specifically used for listboxes
* This gives more weight to '[' characters than alpha-numerics;
* The US version of lstrcmpi() and lstrcmp() are similar as far as
* non-alphanumerals are concerned; All non-alphanumerals get sorted
* before alphanumerals; This means that subdirectory strings that start
* with '[' will get sorted before; But we don't want that; So, this
* function takes care of it;

And then as we all know, lstrcmpi is just a nice thin wrapper around CompareString. And there we go.

Not such a bad order, really. Though to be honest it looks like a real corner case to me (if one cares about one symbol -- even negatively -- one probably cares about others, so a simple NORM_IGNORESYMBOL probably would have made more sense in the end. But then that's just me. :-)

The final answer -- you can user CBS_SORT , or choose an ordering you like better. And just go from there....

 

This blog brought to you by [ (U+005b, aka LEFT SQUARE BRACKET)


Ted. on 9 Nov 2008 9:26 AM:

From memory, I believe the left square bracket exception stuff comes from the old Win 3.0 drives dropdowns in the file open dialogs. e.g.

[-a-]

[-c-]

etc.

see

http://www.guidebookgallery.org/pics/gui/interface/dialogs/openfile/win30.png

carlos on 7 Aug 2009 10:57 AM:

Oddly, system list boxes sort as described (with '[' at the end) but .Net list boxes sort with '[' at the start.  I guess the latter uses the default sort.

Michael S. Kaplan on 7 Aug 2009 11:31 AM:

Not that odd, carlos -- .NET does its own sorting, probably because they didn't want document this strange ordering (not just the brackets, but the OS linguistic sort isn't the same as the .NET one)....


go to newer or older post, or back to index or month or day