////////////////////////////////////////////////////////////////////////  

////////

// by Max Poliashenko - rewritten version of class proposed by Iuri Applonio

// This class will sort a List control by a column of text, integer, float or

// date/time type. It could be easily extended for other data types.

// February 11, 1998

//

class CSortClass

{

public:

enum EDataType {dtNULL, dtINT, dtSTRING, dtDATETIME, dtDEC};

CSortClass(CListCtrl * _pWnd, const int _iCol);

virtual ~CSortClass();

void Sort(bool bAsc, EDataType _dtype);

protected:

CListCtrl * pWnd;

static int CALLBACK Compare(LPARAM lParam1, LPARAM lParam2, LPARAM 

lParamSort);

struct CSortItem

{

CSortItem(const DWORD _dw, const CString &_txt);

DWORD dw; 

CString txt;

};

};

////////////////////////////////////////////////////////////////////////  

/////

// CSortClass

CSortClass::CSortClass(CListCtrl * _pWnd, const int _iCol)

{

pWnd = _pWnd;

ASSERT(pWnd);

int max = pWnd->GetItemCount();

DWORD dw;

CString txt;

// replace Item data with pointer to CSortItem structure

for (int t = 0; t < max; t++)

{

dw = pWnd->GetItemData(t); // save current data to restore it later

txt = pWnd->GetItemText(t, _iCol); 

pWnd->SetItemData(t, (DWORD) new CSortItem(dw, txt));

}

}

CSortClass::~CSortClass()

{

ASSERT(pWnd);

int max = pWnd->GetItemCount();

CSortItem * pItem;

for (int t = 0; t < max; t++)

{

pItem = (CSortItem *) pWnd->GetItemData(t);

ASSERT(pItem);

pWnd->SetItemData(t, pItem->dw);

delete pItem;

}

}

void CSortClass::Sort(bool _bAsc, EDataType _dtype)

{

long lParamSort = _dtype;

// if lParamSort positive - ascending sort order, negative - descending

if (!_bAsc)

lParamSort *= -1; 

pWnd->SortItems(Compare, lParamSort);

}

int CALLBACK CSortClass::Compare(LPARAM lParam1, LPARAM lParam2, LPARAM 

 lParamSort)

{

CSortItem * item1 = (CSortItem *) lParam1;

CSortItem * item2 = (CSortItem *) lParam2;

ASSERT(item1 && item2);

// restore data type and sort order from lParamSort

// if lParamSort positive - ascending sort order, negative - descending

short   sOrder = lParamSort < 0 ? -1 : 1; 

EDataType dType  = (EDataType) (lParamSort * sOrder); // get rid of sign

// declare typed buffers

COleDateTime t1, t2;

switch (dType)

{

case  EDataType::dtINT:

return (atol(item1->txt) - atol(item2->txt))*sOrder;

case  EDataType::dtDEC:

return (atof(item1->txt) < atof(item2->txt) ? -1 : 1)*sOrder;

case  EDataType::dtDATETIME:

if (t1.ParseDateTime(item1->txt) && t2.ParseDateTime(item2->txt))

return (t1 < t2 ? -1 : 1 )*sOrder;

else

return 0;

case  EDataType::dtSTRING:

return item1->txt.CompareNoCase(item2->txt)*sOrder;

default:

ASSERT("Error: attempt to sort a column without type.");

return 0;

}

}

CSortClass::CSortItem::CSortItem(const DWORD _dw, const CString & _txt)

{

dw  = _dw;

txt = _txt;

}

========================================================================== 

Here is its usage: 

void CMyDlg::OnHeaderClicked(NMHDR* pNMHDR, LRESULT* pResult)

{

static int  nSortedCol = -1;

static bool bSortAscending = true; 

HD_NOTIFY *phdn = (HD_NOTIFY *) pNMHDR;

if( phdn->iButton == 0 )

{

// User clicked on header using left mouse button

if( phdn->iItem == nSortedCol )

bSortAscending = !bSortAscending;

else

bSortAscending = TRUE;

nSortedCol = phdn->iItem;

CSortClass csc(&m_List, nSortedCol);

csc.Sort(bSortAscending, (CSortClass::EDataType) 

m_arrColType[nSortedCol]); 

}

*pResult = 0;

}