惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

B
Blog
量子位
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Last Week in AI
Last Week in AI
酷 壳 – CoolShell
酷 壳 – CoolShell
人人都是产品经理
人人都是产品经理
Jina AI
Jina AI
雷峰网
雷峰网
博客园_首页
WordPress大学
WordPress大学
博客园 - 司徒正美
爱范儿
爱范儿
博客园 - 聂微东
IT之家
IT之家
美团技术团队
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 三生石上(FineUI控件)
有赞技术团队
有赞技术团队
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
T
Tailwind CSS Blog
博客园 - Franky
V
V2EX
GbyAI
GbyAI
阮一峰的网络日志
阮一峰的网络日志

The Old New Thing

Why is the x86 undefined instruction called ud2? Why 2? - The Old New Thing What algorithm did Windows XP use to choose your initial user picture? - The Old New Thing A sample use of the winstart.bat file in Windows 95 - The Old New Thing Why don't we allow stacks to be sparse, instead of forcing them to be contiguous? - The Old New Thing What happens if you change a window class's GCL_CB­WND­EXTRA? - The Old New Thing The case of the progress callback that never got called when progress happened - The Old New Thing The perils of binding to value types in XAML - The Old New Thing Microspeak: Funded / unfunded - The Old New Thing AWE does not require PAE, though PAE makes it much more useful - The Old New Thing On forcing all derived classes to implement a specific non-virtual method, part 2 - The Old New Thing On forcing all derived classes to implement a specific non-virtual method, part 1 - The Old New Thing In the product end game, every change carries significant risk, episode 2 - The Old New Thing Why didn't the Windows Entertainment Pack just run the MS-DOS version inside an emulator? - The Old New Thing Comparing the two holograms on the Windows 95 box - The Old New Thing Reducing C++ template bloat by factoring out the type-dependent portions of the function, practical exam - The Old New Thing Reducing C++ template bloat by factoring out the type-dependent portions of the function - The Old New Thing On wrapping a callable in a lambda that just calls it with the same parameters - The Old New Thing Why did the Microsoft Entertainment Pack for Windows have a special sticker announcing that it also had Tetris? - The Old New Thing How do functions like alloca allocate memory from the stack? - The Old New Thing How do functions like alloca allocate memory from the stack? - The Old New Thing Forcing an ARM64X executable to run as a specific architecture - The Old New Thing A little helper class for managing LPPROC_THREAD_ATTRIBUTE_LISTs - The Old New Thing The comments that go into code versus those that go into the pull request description - The Old New Thing The little-known winstart.bat batch file - The Old New Thing How can I perform a Copy­File&shy in unbuffered mode? - The Old New Thing Creating a fake agile wrapper that is technically agile but is not useful outside its home apartment, part 5 - The Old New Thing Creating a fake agile wrapper that is technically agile but is not useful outside its home apartment, part 4 - The Old New Thing Creating a fake agile wrapper that is technically agile but is not useful outside its home apartment, part 3 - The Old New Thing Creating a fake agile wrapper that is technically agile but is not useful outside its home apartment, part 2 - The Old New Thing Creating a fake agile wrapper that is technically agile but is not useful outside its home apartment, part 1 - The Old New Thing
The classic TreeView control lets me sort by name or by l...
Raymond Chen · 2026-05-20 · via The Old New Thing

The Win32 TreeView control in the common controls library provides two ways of sorting elements.

  • TVM_SORTCHILDREN: Sorts children alphabetically by name.
  • TVM_SORTCHILDRENCB: Sorts children via custmm callback.

The custom callback is provided the lParam of the two tree items being compared. But what if you want to sort by a combination of both the text and the lParam? How do you get both?

There are two general designs for using UI controls that represent collections.

One model is for the UI control to be the data repository. Everything you need to know about the item resides in the UI control, somewhere in its name, its check state, its selection state, whatever. If you need to know something about an item, you ask the UI control for the information.

The second model is for the data repository to be some sort of object that itself does not have any UI. (This is known in the biz as a “data model”.) You then construct UI elements to be the representation of those objects.

Windows controls generally lean toward the data model approach because there is usually a lot of information about an item that is not present in its UI representation. The data model approach also allows for optimizations in which where very large collections of items create UI elements only for the items that are visible on screen. You can see this in the XAML ListView control as well as in the classic Win32 ListView control when placed into owner-data mode.

For the controls in the common controls library, the general pattern is to provide a place to store a pointer-sized value that is not shown in the UI, typically called “item data” or just lParam. Here is where you store a pointer to the data model object that the UI object represents.

Okay, so let’s look at the TreeView sort methods again.

The TVM_SORTCHILDRENCB message takes a callback which is passed the lParams of two items to compare. The theory is that these lParams are pointers to larger data structures that describe the item, and you use those larger data structures to decide the ordering of the two items.

The TVM_SORTCHILDREN message doesn’t take a callback. It is a convenience method for the case where you are just sorting by name, so it uses the already-available name assigned to the item.

The case where you would need both is the case where the lParam is not enough to recover the name, either because it’s a pointer to a structure that doesn’t include a name, or because it’s not a pointer at all.

I can imagine running into this case if the only information you need to track for each TreeView item is its name and a pointer-sized piece of data. You put the name in the TreeView item text and the other data in the lParam. This plan works great until you need to sort the items, and your sort comparison function wants access to both pieces of data.

The solution is to switch to a data model pattern. Allocate a structure for each TreeView item and put the string and additional data in that structure. (Alternatively, you could just be sneaky and have the structure be the HTREEITEM and the additional data. Then you can recover the string by using the TVM_GETITEM message.)

Bonus chatter: In theory, the TVM_SORTCHILDRENCB could have passed the HTREEITEMs to the callback. The callback could then use the HTREEITEM to obtain both the string and the lParam. I suspect this didn’t happen because most callback functions would just ask for the lParam from the HTREEITEM, TVM_SORTCHILDRENCB is doing you a favor and saving you a bunch of work by giving you the thing you probably wanted in the first place.

Category

Topics

Author

Raymond Chen

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.