| 10643 | |
| 10644 | |
| 10645 | int 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 |
nothing calls this directly
no outgoing calls
no test coverage detected