Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

522 lines
17 KiB

  1. /*******************************************************************************
  2. *
  3. * colsort.cpp
  4. *
  5. * Helper functions to sort columns
  6. *
  7. * copyright notice: Copyright 1997, Citrix Systems Inc.
  8. * Copyright (c) 1998 - 1999 Microsoft Corporation
  9. *
  10. * $Author: donm $ Don Messerli
  11. *
  12. * $Log: N:\nt\private\utils\citrix\winutils\tsadmin\VCS\colsort.cpp $
  13. *
  14. * Rev 1.10 19 Feb 1998 17:40:12 donm
  15. * removed latest extension DLL support
  16. *
  17. * Rev 1.7 12 Feb 1998 14:20:50 donm
  18. * missed some State columns
  19. *
  20. * Rev 1.6 12 Feb 1998 12:59:20 donm
  21. * State columns wouldn't sort because they were being treated as numbers
  22. *
  23. * Rev 1.5 10 Nov 1997 14:51:30 donm
  24. * fixed endless recursion in SortTextItems
  25. *
  26. * Rev 1.4 07 Nov 1997 23:06:38 donm
  27. * CompareTCPAddress would trap if ExtServerInfo was NULL
  28. *
  29. * Rev 1.3 03 Nov 1997 15:23:22 donm
  30. * added descending sort/cleanup
  31. *
  32. * Rev 1.2 15 Oct 1997 19:50:34 donm
  33. * update
  34. *
  35. * Rev 1.1 13 Oct 1997 18:39:54 donm
  36. * update
  37. *
  38. * Rev 1.0 30 Jul 1997 17:11:26 butchd
  39. * Initial revision.
  40. *
  41. *******************************************************************************/
  42. #include "stdafx.h"
  43. #include "winadmin.h"
  44. #ifdef _DEBUG
  45. #define new DEBUG_NEW
  46. #undef THIS_FILE
  47. static char THIS_FILE[] = __FILE__;
  48. #endif
  49. // Compare function for columns of WinStations
  50. /* no longer used since we want an alphabetical order
  51. int CALLBACK CompareWinStation(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  52. {
  53. int retval = 0;
  54. if(!lParam1 || !lParam2) return 0;
  55. ULONG sort1 = ((CWinStation*)lParam1)->GetSortOrder();
  56. ULONG sort2 = ((CWinStation*)lParam2)->GetSortOrder();
  57. if(sort1 == sort2) {
  58. SDCLASS pd1 = ((CWinStation*)lParam1)->GetSdClass();
  59. SDCLASS pd2 = ((CWinStation*)lParam2)->GetSdClass();
  60. if(pd1 == pd2) retval = 0;
  61. else if(pd1 < pd2) retval = -1;
  62. else retval = 1;
  63. }
  64. else if(sort1 < sort2) retval = -1;
  65. else retval = 1;
  66. return(lParamSort ? retval : -retval);
  67. }
  68. */
  69. // Compare function for columns of Idle Times
  70. int CALLBACK CompareIdleTime(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  71. {
  72. int retval = 0;
  73. if(!lParam1 || !lParam2) return 0;
  74. ELAPSEDTIME idle1 = ((CWinStation*)lParam1)->GetIdleTime();
  75. ELAPSEDTIME idle2 = ((CWinStation*)lParam2)->GetIdleTime();
  76. // check days first
  77. if(idle1.days < idle2.days) retval = -1;
  78. else if(idle1.days > idle2.days) retval = 1;
  79. // check hours
  80. else if(idle1.hours < idle2.hours) retval = -1;
  81. else if(idle1.hours > idle2.hours) retval = 1;
  82. // check minutes
  83. else if(idle1.minutes < idle2.minutes) retval = -1;
  84. else if(idle1.minutes > idle2.minutes) retval = 1;
  85. // check seconds
  86. else if(idle1.seconds < idle2.seconds) retval = -1;
  87. else if(idle1.seconds > idle2.seconds) retval = 1;
  88. return(lParamSort ? retval : -retval);
  89. }
  90. // Compare function for columns of Logon Times
  91. int CALLBACK CompareLogonTime(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  92. {
  93. int retval = 0;
  94. if(!lParam1 || !lParam2) return 0;
  95. LARGE_INTEGER logon1 = ((CWinStation*)lParam1)->GetLogonTime();
  96. LARGE_INTEGER logon2 = ((CWinStation*)lParam2)->GetLogonTime();
  97. if(logon1.QuadPart == logon2.QuadPart) retval = 0;
  98. else if(logon1.QuadPart < logon2.QuadPart) retval = -1;
  99. else retval = 1;
  100. return(lParamSort ? retval : -retval);
  101. }
  102. // Compare function for columns of TCP/IP Addresses
  103. int CALLBACK CompareTcpAddress(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  104. {
  105. int retval = 0;
  106. if(!lParam1 || !lParam2) return 0;
  107. ExtServerInfo *ex1 = (ExtServerInfo*)((CServer*)lParam1)->GetExtendedInfo();
  108. ExtServerInfo *ex2 = (ExtServerInfo*)((CServer*)lParam2)->GetExtendedInfo();
  109. if(!ex1 && !ex2) retval = 0;
  110. else if(ex1 && !ex2) retval = 1;
  111. else if(!ex1 && ex2) retval = -1;
  112. else {
  113. ULONG tcp1 = ex1->RawTcpAddress;
  114. ULONG tcp2 = ex2->RawTcpAddress;
  115. if(tcp1 == tcp2) retval = 0;
  116. else if(tcp1 < tcp2) retval = -1;
  117. else retval = 1;
  118. }
  119. return(lParamSort ? retval : -retval);
  120. }
  121. // Compare function for columns of Module dates
  122. int CALLBACK CompareModuleDate(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  123. {
  124. int retval = 0;
  125. if(!lParam1 || !lParam2) return 0;
  126. // Compare the dates first
  127. USHORT date1 = ((ExtModuleInfo*)lParam1)->Date;
  128. USHORT date2 = ((ExtModuleInfo*)lParam2)->Date;
  129. if(date1 < date2) retval = -1;
  130. else if(date1 > date2) retval = 1;
  131. // Dates are the same, compare the times
  132. else {
  133. USHORT time1 = ((ExtModuleInfo*)lParam1)->Time;
  134. USHORT time2 = ((ExtModuleInfo*)lParam2)->Time;
  135. if(time1 == time2) retval = 0;
  136. else if(time1 < time2) retval = -1;
  137. else retval = 1;
  138. }
  139. return(lParamSort ? retval : -retval);
  140. }
  141. // Compare function for columns of Module versions
  142. int CALLBACK CompareModuleVersions(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  143. {
  144. int retval = 0;
  145. if(!lParam1 || !lParam2) return 0;
  146. // Compare the low versions first
  147. BYTE lowversion1 = ((ExtModuleInfo*)lParam1)->LowVersion;
  148. BYTE lowversion2 = ((ExtModuleInfo*)lParam2)->LowVersion;
  149. if(lowversion1 < lowversion2) retval = -1;
  150. else if(lowversion1 > lowversion2) retval = 1;
  151. // Low versions are the same, compare high version
  152. else {
  153. BYTE highversion1 = ((ExtModuleInfo*)lParam1)->HighVersion;
  154. BYTE highversion2 = ((ExtModuleInfo*)lParam2)->HighVersion;
  155. if(highversion1 == highversion2) retval = 0;
  156. else if(highversion1 < highversion2) retval = -1;
  157. else retval = 1;
  158. }
  159. return(lParamSort ? retval : -retval);
  160. }
  161. // SortTextItems - Sort the list based on column text
  162. // Returns - Returns true for success
  163. // nCol - column that contains the text to be sorted
  164. // bAscending - indicate sort order
  165. // low - row to start scanning from - default row is 0
  166. // high - row to end scan. -1 indicates last row
  167. BOOL SortTextItems( CListCtrl *pList, int nCol, BOOL bAscending,
  168. int low /*= 0*/, int high /*= -1*/ ){
  169. if( nCol >= ((CHeaderCtrl*)pList->GetDlgItem(0))->GetItemCount() )
  170. return FALSE;
  171. if( high == -1 ) high = pList->GetItemCount() - 1;
  172. int lo = low;
  173. int hi = high;
  174. CString midItem;
  175. if( hi <= lo ) return FALSE;
  176. midItem = pList->GetItemText( (lo+hi)/2, nCol );
  177. // loop through the list until indices cross
  178. while( lo <= hi ) {
  179. // rowText will hold all column text for one row
  180. CStringArray rowText;
  181. // find the first element that is greater than or equal to�
  182. // the partition element starting from the left Index.
  183. if( bAscending )
  184. while( ( lo < high ) && ( pList->GetItemText(lo, nCol) < midItem ) )
  185. ++lo;
  186. else
  187. while( ( lo < high ) && ( pList->GetItemText(lo, nCol) > midItem ) )
  188. ++lo;
  189. // find an element that is smaller than or equal to�
  190. // the partition element starting from the right Index.
  191. if( bAscending )
  192. while( ( hi > low ) && ( pList->GetItemText(hi, nCol) > midItem ) )
  193. --hi;
  194. else
  195. while( ( hi > low ) && ( pList->GetItemText(hi, nCol) < midItem ) )
  196. --hi;
  197. // if the indexes have not crossed, swap
  198. // and if the items are not equal
  199. if( lo <= hi )
  200. {
  201. // swap only if the items are not equal
  202. if( pList->GetItemText(lo, nCol) != pList->GetItemText(hi, nCol))
  203. {
  204. // swap the rows
  205. LV_ITEM lvitemlo, lvitemhi;
  206. int nColCount =
  207. ((CHeaderCtrl*)pList->GetDlgItem(0))->GetItemCount();
  208. rowText.SetSize( nColCount );
  209. int i;
  210. for( i=0; i<nColCount; i++)
  211. rowText[i] = pList->GetItemText(lo, i);
  212. lvitemlo.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
  213. lvitemlo.iItem = lo;
  214. lvitemlo.iSubItem = 0;
  215. lvitemlo.stateMask = LVIS_CUT | LVIS_DROPHILITED |
  216. LVIS_FOCUSED | LVIS_SELECTED |
  217. LVIS_OVERLAYMASK | LVIS_STATEIMAGEMASK;
  218. lvitemhi = lvitemlo;
  219. lvitemhi.iItem = hi;
  220. pList->GetItem( &lvitemlo );
  221. pList->GetItem( &lvitemhi );
  222. for( i=0; i<nColCount; i++)
  223. pList->SetItemText(lo, i, pList->GetItemText(hi, i));
  224. lvitemhi.iItem = lo;
  225. pList->SetItem( &lvitemhi );
  226. for( i=0; i<nColCount; i++)
  227. pList->SetItemText(hi, i, rowText[i]);
  228. lvitemlo.iItem = hi;
  229. pList->SetItem( &lvitemlo );
  230. }
  231. ++lo;
  232. --hi;
  233. }
  234. }
  235. // If the right index has not reached the left side of array
  236. // must now sort the left partition.
  237. if( low < hi )
  238. SortTextItems( pList, nCol, bAscending , low, hi);
  239. // If the left index has not reached the right side of array
  240. // must now sort the right partition.
  241. if( lo < high )
  242. SortTextItems( pList, nCol, bAscending , lo, high );
  243. return TRUE;
  244. }
  245. long myatol(CString sTemp)
  246. {
  247. return((long)wcstoul(sTemp.GetBuffer(0), NULL, 10));
  248. }
  249. BOOL SortNumericItems( CListCtrl *pList, int nCol, BOOL bAscending,long low, long high)
  250. {
  251. if( nCol >= ((CHeaderCtrl*)pList->GetDlgItem(0))->GetItemCount() )
  252. return FALSE;
  253. if( high == -1 ) high = pList->GetItemCount() - 1;
  254. long lo = low;
  255. long hi = high;
  256. long midItem;
  257. if( hi <= lo ) return FALSE;
  258. midItem = myatol(pList->GetItemText( (lo+hi)/2, nCol ));
  259. // loop through the list until indices cross
  260. while( lo <= hi )
  261. {
  262. // rowText will hold all column text for one row
  263. CStringArray rowText;
  264. // find the first element that is greater than or equal to
  265. // the partition element starting from the left Index.
  266. if( bAscending )
  267. while( ( lo < high ) && (myatol(pList->GetItemText(lo, nCol)) < midItem ) )
  268. ++lo;
  269. else
  270. while( ( lo < high ) && (myatol(pList->GetItemText(lo, nCol)) > midItem ) )
  271. ++lo;
  272. // find an element that is smaller than or equal to
  273. // the partition element starting from the right Index.
  274. if( bAscending )
  275. while( ( hi > low ) && (myatol(pList->GetItemText(hi, nCol)) > midItem ) )
  276. --hi;
  277. else
  278. while( ( hi > low ) && (myatol(pList->GetItemText(hi, nCol)) < midItem ) )
  279. --hi;
  280. // if the indexes have not crossed, swap
  281. // and if the items are not equal
  282. if( lo <= hi )
  283. {
  284. // swap only if the items are not equal
  285. if(myatol(pList->GetItemText(lo, nCol)) != myatol(pList->GetItemText(hi, nCol)) )
  286. {
  287. // swap the rows
  288. LV_ITEM lvitemlo, lvitemhi;
  289. int nColCount =
  290. ((CHeaderCtrl*)pList->GetDlgItem(0))->GetItemCount();
  291. rowText.SetSize( nColCount );
  292. int i;
  293. for( i=0; i < nColCount; i++)
  294. rowText[i] = pList->GetItemText(lo, i);
  295. lvitemlo.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
  296. lvitemlo.iItem = lo;
  297. lvitemlo.iSubItem = 0;
  298. lvitemlo.stateMask = LVIS_CUT | LVIS_DROPHILITED |
  299. LVIS_FOCUSED | LVIS_SELECTED |
  300. LVIS_OVERLAYMASK | LVIS_STATEIMAGEMASK;
  301. lvitemhi = lvitemlo;
  302. lvitemhi.iItem = hi;
  303. pList->GetItem( &lvitemlo );
  304. pList->GetItem( &lvitemhi );
  305. for( i=0; i< nColCount; i++)
  306. pList->SetItemText(lo, i, pList->GetItemText(hi, i) );
  307. lvitemhi.iItem = lo;
  308. pList->SetItem( &lvitemhi );
  309. for( i=0; i< nColCount; i++)
  310. pList->SetItemText(hi, i, rowText[i]);
  311. lvitemlo.iItem = hi;
  312. pList->SetItem( &lvitemlo );
  313. }
  314. ++lo;
  315. --hi;
  316. }
  317. }
  318. // If the right index has not reached the left side of array
  319. // must now sort the left partition.
  320. if( low < hi )
  321. SortNumericItems( pList, nCol, bAscending , low, hi);
  322. // If the left index has not reached the right side of array
  323. // must now sort the right partition.
  324. if( lo < high )
  325. SortNumericItems( pList, nCol, bAscending , lo, high );
  326. return TRUE;
  327. }
  328. // Our lookup table has structures of this type
  329. typedef struct _ColumnLookup {
  330. int View; // The view the page is in
  331. int Page; // Page that needs to be sorted
  332. int ColumnNumber; // Column that need to be sorted
  333. int (CALLBACK *CompareFunc)(LPARAM,LPARAM,LPARAM); // Callback to send to CListCtrl.SortItems
  334. } ColumnLookup;
  335. // This table only includes structures for columns that aren't sorted
  336. // using the SortTextItems() function
  337. // NULL for the CompareFunc means that SortNumericItems() should be called
  338. ColumnLookup ColumnTable[] = {
  339. // Server User's Page - CWinStation
  340. { VIEW_SERVER, PAGE_USERS, USERS_COL_ID, NULL },
  341. { VIEW_SERVER, PAGE_USERS, USERS_COL_IDLETIME, CompareIdleTime },
  342. { VIEW_SERVER, PAGE_USERS, USERS_COL_LOGONTIME, CompareLogonTime },
  343. // Server WinStation's Page - CWinStation
  344. // { VIEW_SERVER, PAGE_WINSTATIONS, WS_COL_WINSTATION, CompareWinStation },
  345. { VIEW_SERVER, PAGE_WINSTATIONS, WS_COL_ID, NULL },
  346. { VIEW_SERVER, PAGE_WINSTATIONS, WS_COL_IDLETIME, CompareIdleTime },
  347. { VIEW_SERVER, PAGE_WINSTATIONS, WS_COL_LOGONTIME, CompareLogonTime },
  348. // Server Processes' columns - CProcess
  349. { VIEW_SERVER, PAGE_PROCESSES, PROC_COL_ID, NULL },
  350. { VIEW_SERVER, PAGE_PROCESSES, PROC_COL_PID, NULL },
  351. // Server Info (Hotfix) columns - CHotfix
  352. { VIEW_SERVER, PAGE_INFO, HOTFIX_COL_INSTALLEDON, NULL },
  353. // WinStation Processes' columns - CProcess
  354. { VIEW_WINSTATION, PAGE_WS_PROCESSES, WS_PROC_COL_ID, NULL },
  355. { VIEW_WINSTATION, PAGE_WS_PROCESSES, WS_PROC_COL_PID, NULL },
  356. // WinStation Modules columns - CModule
  357. { VIEW_WINSTATION, PAGE_WS_MODULES, MODULES_COL_FILEDATETIME, CompareModuleDate },
  358. { VIEW_WINSTATION, PAGE_WS_MODULES, MODULES_COL_SIZE, NULL },
  359. { VIEW_WINSTATION, PAGE_WS_MODULES, MODULES_COL_VERSIONS, CompareModuleVersions },
  360. // All Server Servers columns - CServer
  361. { VIEW_ALL_SERVERS, PAGE_AS_SERVERS, SERVERS_COL_TCPADDRESS, CompareTcpAddress },
  362. { VIEW_ALL_SERVERS, PAGE_AS_SERVERS, SERVERS_COL_NUMWINSTATIONS, NULL },
  363. // All Server Users columns - CWinStation
  364. { VIEW_ALL_SERVERS, PAGE_AS_USERS, AS_USERS_COL_ID, NULL },
  365. { VIEW_ALL_SERVERS, PAGE_AS_USERS, AS_USERS_COL_IDLETIME, CompareIdleTime },
  366. { VIEW_ALL_SERVERS, PAGE_AS_USERS, AS_USERS_COL_LOGONTIME, CompareLogonTime },
  367. // All Server WinStations columns - CWinStation
  368. // { VIEW_ALL_SERVERS, PAGE_AS_WINSTATIONS, AS_WS_COL_WINSTATION, CompareWinStation },
  369. { VIEW_ALL_SERVERS, PAGE_AS_WINSTATIONS, AS_WS_COL_ID, NULL },
  370. { VIEW_ALL_SERVERS, PAGE_AS_WINSTATIONS, AS_WS_COL_IDLETIME, CompareIdleTime },
  371. { VIEW_ALL_SERVERS, PAGE_AS_WINSTATIONS, AS_WS_COL_LOGONTIME, CompareLogonTime },
  372. // All Server Processes columns - CProcess
  373. { VIEW_ALL_SERVERS, PAGE_AS_PROCESSES, AS_PROC_COL_ID, NULL },
  374. { VIEW_ALL_SERVERS, PAGE_AS_PROCESSES, AS_PROC_COL_PID, NULL },
  375. // All Server Licenses columns - CLicense
  376. { VIEW_ALL_SERVERS, PAGE_AS_LICENSES, AS_LICENSE_COL_USERCOUNT, NULL },
  377. { VIEW_ALL_SERVERS, PAGE_AS_LICENSES, AS_LICENSE_COL_POOLCOUNT, NULL },
  378. // Domain Servers columns - CServer
  379. { VIEW_DOMAIN, PAGE_DOMAIN_SERVERS, SERVERS_COL_TCPADDRESS, CompareTcpAddress },
  380. { VIEW_DOMAIN, PAGE_DOMAIN_SERVERS, SERVERS_COL_NUMWINSTATIONS, NULL },
  381. // Domain Users columns - CWinStation
  382. { VIEW_DOMAIN, PAGE_DOMAIN_USERS, AS_USERS_COL_ID, NULL },
  383. { VIEW_DOMAIN, PAGE_DOMAIN_USERS, AS_USERS_COL_IDLETIME, CompareIdleTime },
  384. { VIEW_DOMAIN, PAGE_DOMAIN_USERS, AS_USERS_COL_LOGONTIME, CompareLogonTime },
  385. // Domain WinStations columns - CWinStation
  386. // { VIEW_DOMAIN, PAGE_DOMAIN_WINSTATIONS, AS_WS_COL_WINSTATION, CompareWinStation },
  387. { VIEW_DOMAIN, PAGE_DOMAIN_WINSTATIONS, AS_WS_COL_ID, NULL },
  388. { VIEW_DOMAIN, PAGE_DOMAIN_WINSTATIONS, AS_WS_COL_IDLETIME, CompareIdleTime },
  389. { VIEW_DOMAIN, PAGE_DOMAIN_WINSTATIONS, AS_WS_COL_LOGONTIME, CompareLogonTime },
  390. // Domain Processes columns - CProcess
  391. { VIEW_DOMAIN, PAGE_DOMAIN_PROCESSES, AS_PROC_COL_ID, NULL },
  392. { VIEW_DOMAIN, PAGE_DOMAIN_PROCESSES, AS_PROC_COL_PID, NULL },
  393. // Domain Licenses columns - CLicense
  394. { VIEW_DOMAIN, PAGE_DOMAIN_LICENSES, AS_LICENSE_COL_USERCOUNT, NULL },
  395. { VIEW_DOMAIN, PAGE_DOMAIN_LICENSES, AS_LICENSE_COL_POOLCOUNT, NULL },
  396. };
  397. /////////////////////////////////////////////////////////////////////////////
  398. // SortByColumn
  399. //
  400. // Page - page to be sorted
  401. // List - pointer to list control to call ->SortItems member function of
  402. // ColumnNumber - which column is to be sorted on
  403. // bAscending - TRUE if ascending, FALSE if descending
  404. //
  405. static int insort = 0;
  406. void SortByColumn(int View, int Page, CListCtrl *List, int ColumnNumber, BOOL bAscending)
  407. {
  408. if(insort) return;
  409. insort = 1;
  410. BOOL found = FALSE;
  411. // Look up the type of column from the ColumnNumber in our table
  412. int TableSize = sizeof(ColumnTable) / sizeof(ColumnLookup);
  413. for(int i = 0; i < TableSize; i++) {
  414. if(ColumnTable[i].View == View &&
  415. ColumnTable[i].Page == Page &&
  416. ColumnTable[i].ColumnNumber == ColumnNumber) {
  417. if(ColumnTable[i].CompareFunc)
  418. List->SortItems(ColumnTable[i].CompareFunc, bAscending);
  419. else
  420. SortNumericItems(List, ColumnNumber, bAscending, 0, -1);
  421. found = TRUE;
  422. break;
  423. }
  424. }
  425. if(!found) SortTextItems( List, ColumnNumber, bAscending, 0, -1);
  426. insort = 0;
  427. } // end SortByColumn