|
|
/*******************************************************************************
* * colsort.cpp * * Helper functions to sort columns * * copyright notice: Copyright 1997, Citrix Systems Inc. * Copyright (c) 1998 - 1999 Microsoft Corporation * * $Author: donm $ Don Messerli * * $Log: N:\nt\private\utils\citrix\winutils\tsadmin\VCS\colsort.cpp $ * * Rev 1.10 19 Feb 1998 17:40:12 donm * removed latest extension DLL support * * Rev 1.7 12 Feb 1998 14:20:50 donm * missed some State columns * * Rev 1.6 12 Feb 1998 12:59:20 donm * State columns wouldn't sort because they were being treated as numbers * * Rev 1.5 10 Nov 1997 14:51:30 donm * fixed endless recursion in SortTextItems * * Rev 1.4 07 Nov 1997 23:06:38 donm * CompareTCPAddress would trap if ExtServerInfo was NULL * * Rev 1.3 03 Nov 1997 15:23:22 donm * added descending sort/cleanup * * Rev 1.2 15 Oct 1997 19:50:34 donm * update * * Rev 1.1 13 Oct 1997 18:39:54 donm * update * * Rev 1.0 30 Jul 1997 17:11:26 butchd * Initial revision. * *******************************************************************************/
#include "stdafx.h"
#include "winadmin.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__; #endif
// Compare function for columns of WinStations
/* no longer used since we want an alphabetical order
int CALLBACK CompareWinStation(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { int retval = 0;
if(!lParam1 || !lParam2) return 0;
ULONG sort1 = ((CWinStation*)lParam1)->GetSortOrder(); ULONG sort2 = ((CWinStation*)lParam2)->GetSortOrder(); if(sort1 == sort2) { SDCLASS pd1 = ((CWinStation*)lParam1)->GetSdClass(); SDCLASS pd2 = ((CWinStation*)lParam2)->GetSdClass(); if(pd1 == pd2) retval = 0; else if(pd1 < pd2) retval = -1; else retval = 1; } else if(sort1 < sort2) retval = -1; else retval = 1;
return(lParamSort ? retval : -retval); } */
// Compare function for columns of Idle Times
int CALLBACK CompareIdleTime(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { int retval = 0;
if(!lParam1 || !lParam2) return 0; ELAPSEDTIME idle1 = ((CWinStation*)lParam1)->GetIdleTime(); ELAPSEDTIME idle2 = ((CWinStation*)lParam2)->GetIdleTime(); // check days first
if(idle1.days < idle2.days) retval = -1; else if(idle1.days > idle2.days) retval = 1; // check hours
else if(idle1.hours < idle2.hours) retval = -1; else if(idle1.hours > idle2.hours) retval = 1; // check minutes
else if(idle1.minutes < idle2.minutes) retval = -1; else if(idle1.minutes > idle2.minutes) retval = 1; // check seconds
else if(idle1.seconds < idle2.seconds) retval = -1; else if(idle1.seconds > idle2.seconds) retval = 1;
return(lParamSort ? retval : -retval); }
// Compare function for columns of Logon Times
int CALLBACK CompareLogonTime(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { int retval = 0;
if(!lParam1 || !lParam2) return 0;
LARGE_INTEGER logon1 = ((CWinStation*)lParam1)->GetLogonTime(); LARGE_INTEGER logon2 = ((CWinStation*)lParam2)->GetLogonTime();
if(logon1.QuadPart == logon2.QuadPart) retval = 0; else if(logon1.QuadPart < logon2.QuadPart) retval = -1; else retval = 1;
return(lParamSort ? retval : -retval); }
// Compare function for columns of TCP/IP Addresses
int CALLBACK CompareTcpAddress(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { int retval = 0;
if(!lParam1 || !lParam2) return 0;
ExtServerInfo *ex1 = (ExtServerInfo*)((CServer*)lParam1)->GetExtendedInfo(); ExtServerInfo *ex2 = (ExtServerInfo*)((CServer*)lParam2)->GetExtendedInfo();
if(!ex1 && !ex2) retval = 0; else if(ex1 && !ex2) retval = 1; else if(!ex1 && ex2) retval = -1; else { ULONG tcp1 = ex1->RawTcpAddress; ULONG tcp2 = ex2->RawTcpAddress;
if(tcp1 == tcp2) retval = 0; else if(tcp1 < tcp2) retval = -1; else retval = 1; }
return(lParamSort ? retval : -retval); }
// Compare function for columns of Module dates
int CALLBACK CompareModuleDate(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { int retval = 0;
if(!lParam1 || !lParam2) return 0;
// Compare the dates first
USHORT date1 = ((ExtModuleInfo*)lParam1)->Date; USHORT date2 = ((ExtModuleInfo*)lParam2)->Date;
if(date1 < date2) retval = -1; else if(date1 > date2) retval = 1; // Dates are the same, compare the times
else { USHORT time1 = ((ExtModuleInfo*)lParam1)->Time; USHORT time2 = ((ExtModuleInfo*)lParam2)->Time; if(time1 == time2) retval = 0; else if(time1 < time2) retval = -1; else retval = 1; }
return(lParamSort ? retval : -retval); }
// Compare function for columns of Module versions
int CALLBACK CompareModuleVersions(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { int retval = 0;
if(!lParam1 || !lParam2) return 0;
// Compare the low versions first
BYTE lowversion1 = ((ExtModuleInfo*)lParam1)->LowVersion; BYTE lowversion2 = ((ExtModuleInfo*)lParam2)->LowVersion;
if(lowversion1 < lowversion2) retval = -1; else if(lowversion1 > lowversion2) retval = 1; // Low versions are the same, compare high version
else { BYTE highversion1 = ((ExtModuleInfo*)lParam1)->HighVersion; BYTE highversion2 = ((ExtModuleInfo*)lParam2)->HighVersion; if(highversion1 == highversion2) retval = 0; else if(highversion1 < highversion2) retval = -1; else retval = 1; }
return(lParamSort ? retval : -retval); }
// SortTextItems - Sort the list based on column text
// Returns - Returns true for success
// nCol - column that contains the text to be sorted
// bAscending - indicate sort order
// low - row to start scanning from - default row is 0
// high - row to end scan. -1 indicates last row
BOOL SortTextItems( CListCtrl *pList, int nCol, BOOL bAscending, int low /*= 0*/, int high /*= -1*/ ){ if( nCol >= ((CHeaderCtrl*)pList->GetDlgItem(0))->GetItemCount() ) return FALSE;
if( high == -1 ) high = pList->GetItemCount() - 1;
int lo = low; int hi = high; CString midItem; if( hi <= lo ) return FALSE;
midItem = pList->GetItemText( (lo+hi)/2, nCol );
// loop through the list until indices cross
while( lo <= hi ) {
// rowText will hold all column text for one row
CStringArray rowText;
// find the first element that is greater than or equal to�
// the partition element starting from the left Index.
if( bAscending ) while( ( lo < high ) && ( pList->GetItemText(lo, nCol) < midItem ) ) ++lo; else while( ( lo < high ) && ( pList->GetItemText(lo, nCol) > midItem ) ) ++lo;
// find an element that is smaller than or equal to�
// the partition element starting from the right Index.
if( bAscending ) while( ( hi > low ) && ( pList->GetItemText(hi, nCol) > midItem ) ) --hi; else while( ( hi > low ) && ( pList->GetItemText(hi, nCol) < midItem ) ) --hi;
// if the indexes have not crossed, swap
// and if the items are not equal
if( lo <= hi ) { // swap only if the items are not equal
if( pList->GetItemText(lo, nCol) != pList->GetItemText(hi, nCol)) { // swap the rows
LV_ITEM lvitemlo, lvitemhi; int nColCount = ((CHeaderCtrl*)pList->GetDlgItem(0))->GetItemCount(); rowText.SetSize( nColCount ); int i; for( i=0; i<nColCount; i++) rowText[i] = pList->GetItemText(lo, i); lvitemlo.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_STATE; lvitemlo.iItem = lo; lvitemlo.iSubItem = 0; lvitemlo.stateMask = LVIS_CUT | LVIS_DROPHILITED | LVIS_FOCUSED | LVIS_SELECTED | LVIS_OVERLAYMASK | LVIS_STATEIMAGEMASK; lvitemhi = lvitemlo; lvitemhi.iItem = hi;
pList->GetItem( &lvitemlo ); pList->GetItem( &lvitemhi );
for( i=0; i<nColCount; i++) pList->SetItemText(lo, i, pList->GetItemText(hi, i));
lvitemhi.iItem = lo; pList->SetItem( &lvitemhi ); for( i=0; i<nColCount; i++) pList->SetItemText(hi, i, rowText[i]); lvitemlo.iItem = hi; pList->SetItem( &lvitemlo ); } ++lo; --hi; } }
// If the right index has not reached the left side of array
// must now sort the left partition.
if( low < hi ) SortTextItems( pList, nCol, bAscending , low, hi);
// If the left index has not reached the right side of array
// must now sort the right partition.
if( lo < high ) SortTextItems( pList, nCol, bAscending , lo, high );
return TRUE; }
long myatol(CString sTemp) {
return((long)wcstoul(sTemp.GetBuffer(0), NULL, 10)); }
BOOL SortNumericItems( CListCtrl *pList, int nCol, BOOL bAscending,long low, long high) { if( nCol >= ((CHeaderCtrl*)pList->GetDlgItem(0))->GetItemCount() ) return FALSE;
if( high == -1 ) high = pList->GetItemCount() - 1; long lo = low; long hi = high;
long midItem;
if( hi <= lo ) return FALSE;
midItem = myatol(pList->GetItemText( (lo+hi)/2, nCol )); // loop through the list until indices cross
while( lo <= hi ) { // rowText will hold all column text for one row
CStringArray rowText;
// find the first element that is greater than or equal to
// the partition element starting from the left Index.
if( bAscending ) while( ( lo < high ) && (myatol(pList->GetItemText(lo, nCol)) < midItem ) ) ++lo; else while( ( lo < high ) && (myatol(pList->GetItemText(lo, nCol)) > midItem ) ) ++lo; // find an element that is smaller than or equal to
// the partition element starting from the right Index.
if( bAscending ) while( ( hi > low ) && (myatol(pList->GetItemText(hi, nCol)) > midItem ) ) --hi; else while( ( hi > low ) && (myatol(pList->GetItemText(hi, nCol)) < midItem ) ) --hi; // if the indexes have not crossed, swap
// and if the items are not equal
if( lo <= hi ) { // swap only if the items are not equal
if(myatol(pList->GetItemText(lo, nCol)) != myatol(pList->GetItemText(hi, nCol)) ) { // swap the rows
LV_ITEM lvitemlo, lvitemhi; int nColCount = ((CHeaderCtrl*)pList->GetDlgItem(0))->GetItemCount();
rowText.SetSize( nColCount );
int i; for( i=0; i < nColCount; i++) rowText[i] = pList->GetItemText(lo, i);
lvitemlo.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_STATE; lvitemlo.iItem = lo; lvitemlo.iSubItem = 0; lvitemlo.stateMask = LVIS_CUT | LVIS_DROPHILITED | LVIS_FOCUSED | LVIS_SELECTED | LVIS_OVERLAYMASK | LVIS_STATEIMAGEMASK; lvitemhi = lvitemlo; lvitemhi.iItem = hi; pList->GetItem( &lvitemlo ); pList->GetItem( &lvitemhi );
for( i=0; i< nColCount; i++) pList->SetItemText(lo, i, pList->GetItemText(hi, i) );
lvitemhi.iItem = lo; pList->SetItem( &lvitemhi );
for( i=0; i< nColCount; i++) pList->SetItemText(hi, i, rowText[i]);
lvitemlo.iItem = hi; pList->SetItem( &lvitemlo ); } ++lo; --hi; } } // If the right index has not reached the left side of array
// must now sort the left partition.
if( low < hi ) SortNumericItems( pList, nCol, bAscending , low, hi);
// If the left index has not reached the right side of array
// must now sort the right partition.
if( lo < high ) SortNumericItems( pList, nCol, bAscending , lo, high );
return TRUE; }
// Our lookup table has structures of this type
typedef struct _ColumnLookup { int View; // The view the page is in
int Page; // Page that needs to be sorted
int ColumnNumber; // Column that need to be sorted
int (CALLBACK *CompareFunc)(LPARAM,LPARAM,LPARAM); // Callback to send to CListCtrl.SortItems
} ColumnLookup;
// This table only includes structures for columns that aren't sorted
// using the SortTextItems() function
// NULL for the CompareFunc means that SortNumericItems() should be called
ColumnLookup ColumnTable[] = { // Server User's Page - CWinStation
{ VIEW_SERVER, PAGE_USERS, USERS_COL_ID, NULL }, { VIEW_SERVER, PAGE_USERS, USERS_COL_IDLETIME, CompareIdleTime }, { VIEW_SERVER, PAGE_USERS, USERS_COL_LOGONTIME, CompareLogonTime }, // Server WinStation's Page - CWinStation
// { VIEW_SERVER, PAGE_WINSTATIONS, WS_COL_WINSTATION, CompareWinStation },
{ VIEW_SERVER, PAGE_WINSTATIONS, WS_COL_ID, NULL }, { VIEW_SERVER, PAGE_WINSTATIONS, WS_COL_IDLETIME, CompareIdleTime }, { VIEW_SERVER, PAGE_WINSTATIONS, WS_COL_LOGONTIME, CompareLogonTime }, // Server Processes' columns - CProcess
{ VIEW_SERVER, PAGE_PROCESSES, PROC_COL_ID, NULL }, { VIEW_SERVER, PAGE_PROCESSES, PROC_COL_PID, NULL }, // Server Info (Hotfix) columns - CHotfix
{ VIEW_SERVER, PAGE_INFO, HOTFIX_COL_INSTALLEDON, NULL }, // WinStation Processes' columns - CProcess
{ VIEW_WINSTATION, PAGE_WS_PROCESSES, WS_PROC_COL_ID, NULL }, { VIEW_WINSTATION, PAGE_WS_PROCESSES, WS_PROC_COL_PID, NULL }, // WinStation Modules columns - CModule
{ VIEW_WINSTATION, PAGE_WS_MODULES, MODULES_COL_FILEDATETIME, CompareModuleDate }, { VIEW_WINSTATION, PAGE_WS_MODULES, MODULES_COL_SIZE, NULL }, { VIEW_WINSTATION, PAGE_WS_MODULES, MODULES_COL_VERSIONS, CompareModuleVersions }, // All Server Servers columns - CServer
{ VIEW_ALL_SERVERS, PAGE_AS_SERVERS, SERVERS_COL_TCPADDRESS, CompareTcpAddress }, { VIEW_ALL_SERVERS, PAGE_AS_SERVERS, SERVERS_COL_NUMWINSTATIONS, NULL }, // All Server Users columns - CWinStation
{ VIEW_ALL_SERVERS, PAGE_AS_USERS, AS_USERS_COL_ID, NULL }, { VIEW_ALL_SERVERS, PAGE_AS_USERS, AS_USERS_COL_IDLETIME, CompareIdleTime }, { VIEW_ALL_SERVERS, PAGE_AS_USERS, AS_USERS_COL_LOGONTIME, CompareLogonTime }, // All Server WinStations columns - CWinStation
// { VIEW_ALL_SERVERS, PAGE_AS_WINSTATIONS, AS_WS_COL_WINSTATION, CompareWinStation },
{ VIEW_ALL_SERVERS, PAGE_AS_WINSTATIONS, AS_WS_COL_ID, NULL }, { VIEW_ALL_SERVERS, PAGE_AS_WINSTATIONS, AS_WS_COL_IDLETIME, CompareIdleTime }, { VIEW_ALL_SERVERS, PAGE_AS_WINSTATIONS, AS_WS_COL_LOGONTIME, CompareLogonTime }, // All Server Processes columns - CProcess
{ VIEW_ALL_SERVERS, PAGE_AS_PROCESSES, AS_PROC_COL_ID, NULL }, { VIEW_ALL_SERVERS, PAGE_AS_PROCESSES, AS_PROC_COL_PID, NULL }, // All Server Licenses columns - CLicense
{ VIEW_ALL_SERVERS, PAGE_AS_LICENSES, AS_LICENSE_COL_USERCOUNT, NULL }, { VIEW_ALL_SERVERS, PAGE_AS_LICENSES, AS_LICENSE_COL_POOLCOUNT, NULL }, // Domain Servers columns - CServer
{ VIEW_DOMAIN, PAGE_DOMAIN_SERVERS, SERVERS_COL_TCPADDRESS, CompareTcpAddress }, { VIEW_DOMAIN, PAGE_DOMAIN_SERVERS, SERVERS_COL_NUMWINSTATIONS, NULL }, // Domain Users columns - CWinStation
{ VIEW_DOMAIN, PAGE_DOMAIN_USERS, AS_USERS_COL_ID, NULL }, { VIEW_DOMAIN, PAGE_DOMAIN_USERS, AS_USERS_COL_IDLETIME, CompareIdleTime }, { VIEW_DOMAIN, PAGE_DOMAIN_USERS, AS_USERS_COL_LOGONTIME, CompareLogonTime }, // Domain WinStations columns - CWinStation
// { VIEW_DOMAIN, PAGE_DOMAIN_WINSTATIONS, AS_WS_COL_WINSTATION, CompareWinStation },
{ VIEW_DOMAIN, PAGE_DOMAIN_WINSTATIONS, AS_WS_COL_ID, NULL }, { VIEW_DOMAIN, PAGE_DOMAIN_WINSTATIONS, AS_WS_COL_IDLETIME, CompareIdleTime }, { VIEW_DOMAIN, PAGE_DOMAIN_WINSTATIONS, AS_WS_COL_LOGONTIME, CompareLogonTime }, // Domain Processes columns - CProcess
{ VIEW_DOMAIN, PAGE_DOMAIN_PROCESSES, AS_PROC_COL_ID, NULL }, { VIEW_DOMAIN, PAGE_DOMAIN_PROCESSES, AS_PROC_COL_PID, NULL }, // Domain Licenses columns - CLicense
{ VIEW_DOMAIN, PAGE_DOMAIN_LICENSES, AS_LICENSE_COL_USERCOUNT, NULL }, { VIEW_DOMAIN, PAGE_DOMAIN_LICENSES, AS_LICENSE_COL_POOLCOUNT, NULL }, };
/////////////////////////////////////////////////////////////////////////////
// SortByColumn
//
// Page - page to be sorted
// List - pointer to list control to call ->SortItems member function of
// ColumnNumber - which column is to be sorted on
// bAscending - TRUE if ascending, FALSE if descending
//
static int insort = 0; void SortByColumn(int View, int Page, CListCtrl *List, int ColumnNumber, BOOL bAscending) { if(insort) return;
insort = 1; BOOL found = FALSE;
// Look up the type of column from the ColumnNumber in our table
int TableSize = sizeof(ColumnTable) / sizeof(ColumnLookup);
for(int i = 0; i < TableSize; i++) { if(ColumnTable[i].View == View && ColumnTable[i].Page == Page && ColumnTable[i].ColumnNumber == ColumnNumber) { if(ColumnTable[i].CompareFunc) List->SortItems(ColumnTable[i].CompareFunc, bAscending); else SortNumericItems(List, ColumnNumber, bAscending, 0, -1); found = TRUE; break; } }
if(!found) SortTextItems( List, ColumnNumber, bAscending, 0, -1);
insort = 0;
} // end SortByColumn
|