I'm displaying a File ListView
which has the columns Size and Date. The WIN32_FIND_DATA
structure used to find files specifies (1) Size as nFileSizeHigh/nFileSizeLow
, and (2) Date via FILETIME
as dwLowDateTime/dwHighDateTime
.
These are meant to be combined into ULARGE_INTEGER as e.g.
uLargeInteger.LowPart = low;
uLargeInteger.HighPart = high;
// Final value
ULONGLONG final = uLargeInteger.QuadPart;
Once added into the ListView these are strings. (1) The Size is goes into LVITEM
's pszText
as std::towstring(sizeULastInteger.QuadPart
, (2) The Date via SHFormatDate()
.
The ListView will be sorted on these columns.
std::stoi(wstr)
(assuming there won't be any int
issues in modern environments, Windows 10+)SHFormatDate
, is there an easy way to convert back into FILETIME
or a number? I can either maintain a parallel data struct with the underlying ULARGE_INTEGER
, or use C++'s date/time libraries but that assumes a local pattern.Note: The only answers available on Google on this are for WPF and C#.
Yeah, I wouldn't bother trying to reverse SHFormatDate()
— that's strictly for display, and also it is locale-dependent. Same with the file size strings — once you format it, you've lost any real ability to sort on it numerically.
The right way is to keep the actual sort key (e.g. ULARGE_INTEGER
for size, FILETIME
for date) and stash it in the LVITEM::lParam
. then in your compare function you just cast lParam back and compare the raw values. something like:
struct file_item_data {
ULONGLONG size;
FILETIME date;
};
// when inserting
auto* data = new file_item_data{ size_ull, file_time };
LVITEM item = {};
item.mask = LVIF_TEXT | LVIF_PARAM;
item.iItem = index;
item.pszText = formatted_size_string;
item.lParam = reinterpret_cast<LPARAM>(data);
ListView_InsertItem(hwnd_listview, &item);
ListView_SetItemText(hwnd_listview, index, 1, formatted_date_string); // column 1 = date
and then for sorting:
int CALLBACK compare(LPARAM l1, LPARAM l2, LPARAM col) {
auto* a = reinterpret_cast<file_item_data*>(l1);
auto* b = reinterpret_cast<file_item_data*>(l2);
if (col == 0) return a->size < b->size ? -1 : (a->size > b->size ? 1 : 0);
if (col == 1) return CompareFileTime(&a->date, &b->date);
return 0;
}
You call ListView_SortItems(..., compare, col_index)
when the user clicks a header. if you're toggling ascending/descending, pass that in the hiword of the sort param.
Don't forget to free the file_item_data*
structs when you're done — or just track them in a vector and clean them up all at once on exit.