MCPcopy Create free account
hub / github.com/AutoHotkey/AutoHotkey / LV_GeneralSort

Function LV_GeneralSort

source/script_gui.cpp:10645–10738  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

10643
10644
10645int CALLBACK LV_GeneralSort(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
10646// ListView sorting by field's text or something derived from the text for each call.
10647{
10648 LV_SortType &lvs = *(LV_SortType *)lParamSort;
10649
10650 // v1.0.44.12: Testing shows that LVM_GETITEMW automatically converts the ANSI contents of our ListView
10651 // into Unicode, which is nice because it avoids the overhead and code size of having to call
10652 // ToWideChar(), along with the extra/temp buffers it requires to receive the wide version.
10653 UINT msg_lvm_getitem = (lvs.col.case_sensitive == SCS_INSENSITIVE_LOGICAL && lvs.col.type == LV_COL_TEXT)
10654 ? LVM_GETITEMW : LVM_GETITEM; // Both items above are checked so that SCS_INSENSITIVE_LOGICAL can be effect even for non-text columns because it allows a column to be later changed to TEXT and retain its "logical-sort" setting.
10655 // NOTE: It's safe to send a LVITEM struct rather than an LVITEMW with the LVM_GETITEMW message because
10656 // the only difference between them is the type "LPWSTR pszText", which is no problem as long as caller
10657 // has properly halved cchTextMax to reflect that wide-chars are twice as wide as 8-bit characters.
10658
10659 // MSDN: "During the sorting process, the list-view contents are unstable. If the [ListView_SortItems]
10660 // callback function sends any messages to the list-view control, the results are unpredictable (aside
10661 // from LVM_GETITEM, which is allowed by ListView_SortItemsEx but not ListView_SortItems)."
10662 // Since SortItemsEx has become so much more common/available, the doubt about whether the non-Ex
10663 // ListView_SortItems actually allows LVM_GETITEM (which it probably does in spite of not being
10664 // documented) much less of a concern.
10665 // Older: It seems hard to believe that you shouldn't send ANY kind of message because how could you
10666 // ever use ListView_SortItems() without either having LVS_OWNERDATA or allocating temp memory for the
10667 // entire column (to whose rows lParam would point)?
10668 // UPDATE: The following seems to be one alternative:
10669 // Do a "virtual qsort" on this column's contents by having qsort() sort an array of row numbers according
10670 // to the contents of each particular row's field in that column (i.e. qsort's callback would call LV_GETITEM).
10671 // In other words, the array would start off in order (1,2,3) but afterward would contain the proper sort
10672 // (e.g. 3,1,2). Next, traverse the array and store the correct "order number" in the corresponding row's
10673 // special "lParam container" (for example, 3,1,2 would store 1 in row 3, 2 in row 1, and 3 in row 2, and 4 in...).
10674 // Then the ListView can be sorted via a method like the high performance LV_Int32Sort.
10675 // However, since the above would require TWO SORTS, it would probably be slower (though the second sort would
10676 // require only a tiny fraction of the time of the first).
10677 lvs.lvi.pszText = lvs.buf1; // lvi's other members were already set by the caller.
10678 if (lvs.incoming_is_index) // Serves to avoid the potentially high performance overhead of ListView_FindItem() where possible.
10679 {
10680 lvs.lvi.iItem = (int)lParam1;
10681 SendMessage(lvs.hwnd, msg_lvm_getitem, 0, (LPARAM)&lvs.lvi); // Use LVM_GETITEM vs. LVM_GETITEMTEXT because MSDN says that only LVM_GETITEM is safe during the sort.
10682 }
10683 else
10684 {
10685 // Unfortunately, lParam cannot be used as the index itself because apparently, the sorting
10686 // process puts the item indices into a state of flux. In other words, the indices are
10687 // changing while the sort progresses, so it's not possible to use an item's original index
10688 // as a way to uniquely identify it.
10689 lvs.lvfi.lParam = lParam1;
10690 lvs.lvi.iItem = ListView_FindItem(lvs.hwnd, -1, &lvs.lvfi);
10691 if (lvs.lvi.iItem < 0) // Not found. Impossible if caller set the LParam to a unique value.
10692 *lvs.buf1 = '\0';
10693 else
10694 SendMessage(lvs.hwnd, msg_lvm_getitem, 0, (LPARAM)&lvs.lvi);
10695 }
10696
10697 // Must use lvi.pszText vs. buf because MSDN says (for LVM_GETITEM, but it might also apply to
10698 // LVM_GETITEMTEXT even though it isn't documented): "Applications should not assume that the text will
10699 // necessarily be placed in the specified buffer. The control may instead change the pszText member
10700 // of the structure to point to the new text rather than place it in the buffer."
10701 LPTSTR field1 = lvs.lvi.pszText; // Save value of pszText in case it no longer points to lvs.buf1.
10702

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected