home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / BC_502 / PVIEW95.PAK / LISTVIEW.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  24.3 KB  |  772 lines

  1. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  2. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  3. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  4. // PARTICULAR PURPOSE.
  5. //
  6. // Copyright (C) 1993-1995  Microsoft Corporation.  All Rights Reserved.
  7. //
  8. //  MODULE:   listview.c
  9. //
  10. //  PURPOSE:  Handles all listview manipulation.
  11. //
  12. //  FUNCTIONS:
  13. //    CreateListView         - Creates a list view control in report view
  14. //    ListView_InitColumns   - Initializes the list view columns
  15. //    AddProcessItem         - Adds an item to the process list view
  16. //    AddThreadItem          - Adds an item to the thread list view
  17. //    ListView_OnGetDispInfo - Handles the WM_NOTIFY/LV_GETDISPINFO message
  18. //    ListView_OnClick       - Handles the WM_NOTIFY/NM_CLICK message
  19. //    ListView_OnDeleteItem  - Frees memory when an item is deleted
  20. //    ListView_OnColumnClick - Sorts the list view based on the column clicked
  21. //    ListView_CompareProc   - Comparison callback for sorting the list view
  22. //    LV_Subclass            - Subclass procedure for the thread list view
  23.                             
  24. //  COMMENTS:
  25. //
  26.  
  27. #include <windows.h>            // required for all Windows applications
  28. #include <commctrl.h>
  29. #include <string.h>
  30. #include "globals.h"            // prototypes specific to this application
  31. #include "resource.h"
  32. #include "listview.h"
  33. #include "procthrd.h"
  34.  
  35. FARPROC g_lpfnThreadListView;
  36.  
  37. //-------------------------------------------------------------------------
  38. // Useful application-global variables defined here!
  39. APPCOLUMNDEF acdProcess[] = 
  40. {
  41.     {IDS_PROCESS,       100},
  42.     {IDS_PID,           75},
  43.     {IDS_PRIORITY,      75},
  44.     {IDS_THREADCNT,     90},
  45.     {IDS_PROCESSTYPE,   75},
  46.     {IDS_FULLPATH,      250}
  47. };
  48.  
  49. APPCOLUMNDEF acdThread[] = 
  50. {
  51.     {IDS_THREAD,        100},
  52.     {IDS_TPID,          100},
  53.     {IDS_TPRIORITY,     100}
  54. };
  55.      
  56.  
  57. //
  58. //  FUNCTION: CreateListView(HWND, DWORD, UINT, UINT, UINT)
  59. //
  60. //  PURPOSE:  Creates a list view control
  61. //
  62. //  PARAMETERS:
  63. //    hwndParent - Handle of the parent window.
  64. //    dwStyle    - Style flags for listview control
  65. //    idString   - Identifier of the first string table resource entry for
  66. //                 the new control's column titles
  67. //    cColumns   - Number of columns to add            
  68. //    idCtl      - Control identifier
  69. //
  70. //  RETURN VALUE:
  71. //    The window handle of the newly created listview control if successful, 
  72. //    or NULL if a new listview control could not be created.
  73. //
  74. //
  75.  
  76. HWND CreateListView (HWND hwndParent, DWORD dwStyle, APPCOLUMNDEF acd[], UINT cColumns, UINT idCtl)
  77. {
  78.      HWND hwndLV;
  79.     RECT rcClient = {0};
  80.  
  81.     // Make sure the common controls DLL is loaded.
  82.     InitCommonControls();
  83.  
  84.     // Create the control so that it fills the client area of the parent 
  85.     // window.  The size of the control will be updated in the parent's 
  86.     // WM_SIZE message handler
  87.     GetClientRect(hwndParent, &rcClient);
  88.  
  89.     hwndLV = CreateWindow(WC_LISTVIEW, 
  90.                           "", 
  91.                           dwStyle,
  92.                           rcClient.left, 
  93.                           rcClient.top,
  94.                           rcClient.right, 
  95.                           rcClient.bottom,
  96.                           hwndParent, 
  97.                           (HMENU)idCtl, 
  98.                           hInst, 
  99.                           NULL);
  100.     if (hwndLV == NULL)
  101.         return NULL;
  102.  
  103.     // Initialize the image lists and add columns
  104.     if (!ListView_InitColumns(hwndLV, acd, cColumns)) 
  105.     {
  106.         DestroyWindow(hwndLV);
  107.         return NULL;
  108.     }
  109.     return hwndLV;
  110. }
  111.  
  112.  
  113. //
  114. //  FUNCTION: ListView_InitColumns(HWND, UINT, UINT)
  115. //
  116. //  PURPOSE:  Adds columns to the specified list view.
  117. //
  118. //  PARAMETERS:
  119. //    hwndLV    - Handle to the listview control.
  120. //    idString  - ID in the string table where the column names begin
  121. //    cColumns  - Number of columns to add                                                
  122. //
  123. //  RETURN VALUE:
  124. //    TRUE  - Success, all the columns were added          
  125. //    FALSE - Failure, an error occured while adding one of the columns
  126. //
  127. //  COMMENTS:
  128. //
  129. //
  130.  
  131. BOOL WINAPI ListView_InitColumns (HWND hwndLV, APPCOLUMNDEF acd[], UINT cColumns)
  132. {
  133.     LV_COLUMN lvc          = {0};
  134.      UINT      iCol;
  135.     char      szTemp[64];
  136.  
  137.     // Initialize the LV_COLUMN struct
  138.     lvc.mask    = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  139.     lvc.fmt     = LVCFMT_LEFT;
  140.     lvc.pszText = szTemp;             
  141.  
  142.     // Add the columns
  143.     for (iCol=0; iCol < cColumns; iCol++)
  144.     {
  145.         lvc.iSubItem = iCol;
  146.         lvc.cx = acd[iCol].cxColumn;
  147.         LoadString(hInst, acd[iCol].idString, szTemp, sizeof(szTemp));
  148.         if (ListView_InsertColumn(hwndLV, iCol, &lvc) == -1)
  149.             return (FALSE);
  150.     }
  151.     return (TRUE);
  152. }
  153.  
  154.  
  155. //
  156. //  FUNCTION: AddProcessItem(HWND, PINFO pi)
  157. //
  158. //  PURPOSE:  Add an item and subitems to the process list view.
  159. //
  160. //  PARAMETERS:
  161. //    hwndLV  - Handle of the list view control
  162. //    pi      - Application-defined MYITEM structure containing the text
  163. //              of the item and its corresponding subitems
  164. //
  165. //  RETURN VALUE:
  166. //    TRUE if the item is added successfully, FALSE otherwise.
  167. //
  168. //
  169.  
  170. BOOL AddProcessItem(HWND hwndLV, PINFO pi)
  171. {
  172.     LV_ITEM lvi      = {0};
  173.      PPINFO  ppi;
  174.      int     iSubItem;
  175.  
  176.     lvi.mask      = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
  177.     lvi.iItem     = 0;
  178.     lvi.iSubItem  = 0;
  179.     lvi.state     = 0;
  180.     lvi.stateMask = 0;
  181.     lvi.pszText   = LPSTR_TEXTCALLBACK;
  182.     lvi.iImage    = 0;  
  183.  
  184.     // Because we're using the LPSTR_TEXTCALLBACK type for the strings,
  185.     // we need to save the PINFO structure in the lParam of the item. So,
  186.     // here we allocate the memory for the structure, and we free the
  187.     // memory when we get the notification that the item is being deleted.
  188.     ppi = (PPINFO)malloc(sizeof(PINFO));
  189.     if (!ppi)
  190.         return FALSE;
  191.  
  192.     CopyMemory(ppi, &pi, sizeof(PINFO));
  193.  
  194.     lvi.lParam = (LPARAM)ppi;
  195.  
  196.     if (ListView_InsertItem(hwndLV, &lvi) == -1)
  197.         return FALSE;
  198.  
  199.     // set up all the sub items to use LBSTR_TEXTCALLBACK
  200.     for (iSubItem = 1; iSubItem < CPROCESSCOLUMNS; iSubItem++)
  201.         ListView_SetItemText(hwndLV, 0, iSubItem, LPSTR_TEXTCALLBACK);
  202.  
  203.     return TRUE;
  204. }
  205.  
  206.  
  207. //
  208. //  FUNCTION: AddThreadItem(HWND, TINFO ti)
  209. //
  210. //  PURPOSE:  Add an item and subitems to the thread list view.
  211. //
  212. //  PARAMETERS:
  213. //    hwndLV  - Handle of the list view control
  214. //    ti      - Application-defined MYITEM structure containing the text
  215. //              of the item and its corresponding subitems
  216. //
  217. //  RETURN VALUE:
  218. //    TRUE if the item is added successfully, FALSE otherwise.
  219. //
  220. //
  221.  
  222. BOOL AddThreadItem(HWND hwndLV, TINFO ti)
  223. {
  224.     LV_ITEM lvi      = {0};
  225.      PTINFO  pti;
  226.      int     iSubItem;
  227.  
  228.     lvi.mask      = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
  229.     lvi.iItem     = 0;
  230.     lvi.iSubItem  = 0;
  231.     lvi.state     = 0;
  232.     lvi.stateMask = 0;
  233.     lvi.pszText   = LPSTR_TEXTCALLBACK;
  234.     lvi.iImage    = 0;
  235.  
  236.     // Because we're using the LPSTR_TEXTCALLBACK type for the strings,
  237.     // we need to save the PINFO structure in the lParam of the item. So,
  238.     // here we allocate the memory for the structure, and we free the
  239.     // memory when we get the notification that the item is being deleted.
  240.     pti = (PTINFO)malloc(sizeof(TINFO));
  241.     if (!pti)
  242.         return FALSE;
  243.  
  244.     CopyMemory(pti, &ti, sizeof(TINFO));
  245.     lvi.lParam = (LPARAM)pti;
  246.  
  247.     if (ListView_InsertItem(hwndLV, &lvi) == -1)
  248.         return FALSE;
  249.  
  250.     // set up all the sub items to use LPSTR_TEXTCALLBACK as well
  251.     for (iSubItem = 1; iSubItem < CTHREADCOLUMNS; iSubItem++)
  252.         ListView_SetItemText(hwndLV, 0, iSubItem, LPSTR_TEXTCALLBACK);
  253.  
  254.     return TRUE;
  255. }
  256.  
  257.  
  258. //
  259. //  FUNCTION: ListView_OnGetDispInfo(int, LV_DISPINFO *)
  260. //
  261. //  PURPOSE:  Handle the WM_NOTIFY/LV_GETDISPINFO notification by returning
  262. //            the string for the item/subitem being asked for.
  263. //
  264. //  PARAMETERS:
  265. //    idFrom - Identifier of the control this is being asked for
  266. //    plvdi  - Specifies which data is being asked for 
  267. //
  268. //  RETURN VALUE:
  269. //    Always returns 0.
  270. //
  271. //  COMMENTS:
  272. //    The function will return the string in the plvdi->item.pszText field
  273. //
  274.  
  275. LRESULT ListView_OnGetDispInfo(int idFrom, LV_DISPINFO *plvdi)
  276. {
  277. static  char szText[128];
  278.  
  279.     switch (idFrom)
  280.     {
  281.         case IDC_PROCESS:
  282.         {
  283.             PINFO *pi = (PPINFO)(plvdi->item.lParam);
  284.  
  285.             switch (plvdi->item.iSubItem)
  286.             {
  287.                 case 0:                     // module name
  288.                     plvdi->item.pszText = pi->szModName;
  289.                     break;
  290.  
  291.                 case 1:                     // process id
  292.                     wsprintf(szText, "%X", pi->pid);
  293.                     plvdi->item.pszText = szText;
  294.                     break;
  295.  
  296.                 case 2:                     // base priority
  297.  
  298.                     // If the priority is a known value, display a readable
  299.                     // description. Otherwise display the actual numerical 
  300.                     // value
  301.  
  302.                     switch (pi->dwPriorityClass)
  303.                     {
  304.                         case REALTIME_PRIORITY_CLASS:
  305.                             wsprintf(szText, "%d  (%s)", 
  306.                                      pi->pcPriClassBase, 
  307.                                      "Real Time");
  308.                             break;
  309.  
  310.                         case HIGH_PRIORITY_CLASS:
  311.                             wsprintf(szText, "%d  (%s)", 
  312.                                      pi->pcPriClassBase, 
  313.                                      "High");
  314.                             break;
  315.  
  316.                         case NORMAL_PRIORITY_CLASS:
  317.                             wsprintf(szText, "%d  (%s)", 
  318.                                      pi->pcPriClassBase, 
  319.                                      "Normal");
  320.                             break;
  321.  
  322.                         case IDLE_PRIORITY_CLASS:
  323.                             wsprintf(szText, "%d  (%s)", 
  324.                                      pi->pcPriClassBase, 
  325.                                      "Idle");
  326.                             break;
  327.  
  328.                         default:
  329.                             wsprintf(szText, "%d", pi->pcPriClassBase);
  330.                     }
  331.  
  332.                     plvdi->item.pszText = szText;
  333.                     break;
  334.  
  335.                 case 3:                     // thread count
  336.                     wsprintf(szText, "%d", pi->cntThreads);
  337.                     plvdi->item.pszText = szText;
  338.                     break;
  339.  
  340.                 case 4:
  341.                     wsprintf(szText, "%d-Bit", pi->uAppType);
  342.                     plvdi->item.pszText = szText;
  343.                     break;
  344.  
  345.                 case 5:
  346.                     plvdi->item.pszText = pi->szFullPath;
  347.                     break;
  348.  
  349.                 default:
  350.                     break;
  351.             }
  352.             break;
  353.         } // case IDC_PROCESS
  354.  
  355.         case IDC_THREAD:
  356.         {
  357.             PTINFO pti = (PTINFO)(plvdi->item.lParam);
  358.  
  359.             switch (plvdi->item.iSubItem)
  360.             {
  361.                 case 0:                     // thread ID
  362.                     wsprintf(szText, "%X", pti->tid);
  363.                     plvdi->item.pszText = szText;
  364.                     break;
  365.  
  366.                 case 1:                     // owning PID
  367.                     wsprintf(szText, "%X", pti->pidOwner);
  368.                     plvdi->item.pszText = szText;
  369.                     break;
  370.  
  371.                 case 2:                     // thread priority
  372.  
  373.                     // If the priority is a known value, display a readable
  374.                     // description. Otherwise display the actual numerical 
  375.                     // value
  376.                     switch (pti->tpDeltaPri)
  377.                     {
  378.                         case THREAD_PRIORITY_TIME_CRITICAL:
  379.                             wsprintf(szText, "%d  (%s)", 
  380.                                      pti->tpDeltaPri + pti->tpBasePri, 
  381.                                      "Time Critical");
  382.                             break;
  383.  
  384.                         case THREAD_PRIORITY_HIGHEST:
  385.                             wsprintf(szText, "%d  (%s)", 
  386.                                      pti->tpDeltaPri + pti->tpBasePri, 
  387.                                      "Highest");
  388.                             break;
  389.  
  390.                         case THREAD_PRIORITY_ABOVE_NORMAL:
  391.                             wsprintf(szText, "%d  (%s)", 
  392.                                      pti->tpDeltaPri + pti->tpBasePri, 
  393.                                      "Above Normal");
  394.                             break;
  395.  
  396.                         case THREAD_PRIORITY_NORMAL:
  397.                             wsprintf(szText, "%d  (%s)", 
  398.                                      pti->tpDeltaPri + pti->tpBasePri, 
  399.                                      "Normal");
  400.                             break;
  401.  
  402.                         case THREAD_PRIORITY_BELOW_NORMAL:
  403.                             wsprintf(szText, "%d  (%s)", 
  404.                                      pti->tpDeltaPri + pti->tpBasePri, 
  405.                                      "Below Normal");
  406.                             break;
  407.  
  408.                         case THREAD_PRIORITY_LOWEST:
  409.                             wsprintf(szText, "%d  (%s)", 
  410.                                      pti->tpDeltaPri + pti->tpBasePri, 
  411.                                      "Lowest");
  412.                             break;
  413.  
  414.                         case THREAD_PRIORITY_IDLE:
  415.                             wsprintf(szText, "%d  (%s)", 
  416.                                      pti->tpDeltaPri + pti->tpBasePri, 
  417.                                      "Idle");
  418.                             break;
  419.  
  420.                         default:
  421.                             wsprintf(szText, "%d", 
  422.                                      pti->tpDeltaPri + pti->tpBasePri);
  423.                     }
  424.               
  425.                     plvdi->item.pszText = szText;
  426.                     break;
  427.  
  428.                 default:
  429.                     break;
  430.             }
  431.             break;
  432.         } // case IDC_THREAD
  433.     }
  434.     return (0);
  435. }
  436.  
  437.  
  438. //
  439. //  FUNCTION: ListView_OnClick(int, NM_LISTVIEW *)
  440. //
  441. //  PURPOSE:  Handle the WM_NOTIFY/NM_CLICK message by retrieving the 
  442. //            item information for the process item clicked on and 
  443. //            refresh the threads associated with the process item.
  444. //
  445. //  PARAMETERS:
  446. //    idFrom  - Identifier of the control sending this notification
  447. //    pnmlv   - Control specific information about the notification
  448. //
  449. //  RETURN VALUE:
  450. //    TRUE  - Success
  451. //    FALSE - Initialization failed
  452. //
  453. //  COMMENTS:
  454. //
  455. //
  456.  
  457. #pragma argsused
  458. LRESULT ListView_OnClick(int idFrom, NM_LISTVIEW *pnmlv)
  459. {
  460.      LV_HITTESTINFO lvhti;
  461.      LV_ITEM        lvi           = {0};
  462.      int            iItemClicked;
  463.      BOOL           fErr;
  464.      POINT          point         = {0};
  465.  
  466.     // only handle this message if it is sent from the process list view
  467.     if (idFrom != IDC_PROCESS)
  468.         return (0);         
  469.  
  470.     // Find out where the cursor is
  471.     GetCursorPos(&point);
  472.     ScreenToClient(g_hwndProcess, &point);
  473.  
  474.     // Now do a hittest to find out which item this is
  475.     lvhti.pt     = point;
  476.      iItemClicked = ListView_HitTest(g_hwndProcess, &lvhti);
  477.  
  478.     // Sset up the LV_ITEM structure to get the process id
  479.     lvi.iItem    = iItemClicked;
  480.     lvi.iSubItem = 0;
  481.     lvi.mask     = LVIF_PARAM;
  482.  
  483.      fErr = ListView_GetItem(g_hwndProcess, &lvi);
  484.     if (TRUE == fErr)   // If we got the item...
  485.         RefreshThreadList(g_hwndThread, ((PPINFO)(lvi.lParam))->pid);
  486.     
  487.     return (0);
  488. }
  489.  
  490.  
  491. //
  492. //  FUNCTION: ListView_OnDeleteItem(int, NM_LISTVIEW *)
  493. //
  494. //  PURPOSE:  Handle the WM_NOTIFY/LV_DELETEITEM by freeing the structure
  495. //            stored with the item.
  496. //
  497. //  PARAMETERS:
  498. //    idFrom  - Identifier of the control sending the notification
  499. //    pnmlv   - Control specific information about the notification, 
  500. //              specifically which item is being freed.
  501. //
  502. //  RETURN VALUE:
  503. //    Always returns 0  
  504. //
  505. //  COMMENTS:
  506. //
  507.  
  508. #pragma argsused
  509. LRESULT ListView_OnDeleteItem(int idFrom, NM_LISTVIEW *pnmlv)
  510. {
  511.      LV_ITEM lvi  = {0};
  512.      BOOL    fErr;
  513.  
  514.     // set up the LV_ITEM structure to get the pointer stored in the lParam
  515.     lvi.iItem    = pnmlv->iItem;
  516.     lvi.iSubItem = 0;
  517.     lvi.mask     = LVIF_PARAM;
  518.  
  519.     // Get the LV_ITEM structure from the appropriate control 
  520.     fErr = ListView_GetItem(pnmlv->hdr.hwndFrom, &lvi);
  521.     if (TRUE == fErr)                   // If we got the item                                           
  522.         free((VOID *)lvi.lParam);       // free the structure
  523.  
  524.     return (0);
  525. }
  526.  
  527.  
  528. //
  529. //  FUNCTION: ListView_OnColumnClick(int, NM_LISTVIEW *)
  530. //
  531. //  PURPOSE:  Handle the WM_NOTIFY/LVN_COLUMNCLICK notification by sorting
  532. //            the control based on the column clicked
  533. //
  534. //  PARAMETERS:
  535. //    idFrom  - Identifier of the control sending the notification
  536. //    pnmlv   - More information about the notification, specifically which
  537. //              column was clicked on.
  538. //
  539. //  RETURN VALUE:
  540. //    Always returns 0.
  541. //
  542. //  COMMENTS:
  543. //
  544.  
  545. LRESULT ListView_OnColumnClick(int idFrom, NM_LISTVIEW *pnmlv)
  546. {
  547.     SORTINFO si = {0};
  548.  
  549.     si.idFrom   = idFrom;
  550.     si.iSubItem = pnmlv->iSubItem;
  551.  
  552.     ListView_SortItems(pnmlv->hdr.hwndFrom, ListView_CompareProc,
  553.                        (LPARAM)&si);
  554.     return (0);
  555. }
  556.  
  557.  
  558. //
  559. //  FUNCTION: ListView_CompareProc(LPARAM, LPARAM, LPARAM)
  560. //
  561. //  PURPOSE:  Callback used for column sorting in a listview
  562. //
  563. //  PARAMETERS:  
  564. //    lParam1    - lParam of the first item being compared (from LV_ITEM)
  565. //    lParam2    - lParam of the second item being compared (from LV_ITEM)
  566. //    lParamSort - lParam passed in from the ListView_SortItems()
  567. //
  568. //  RETURN VALUE:
  569. //    -1 - lParam1 should come before lParam2
  570. //     0 - lParam1 and lParam2 are the same
  571. //     1 - lParam1 should come after lParam2
  572. //
  573. //  COMMENTS:
  574. //
  575.  
  576. int CALLBACK ListView_CompareProc(LPARAM lParam1, 
  577.                                   LPARAM lParam2, 
  578.                                   LPARAM lParamSort)
  579. {
  580.      PSORTINFO psi          = (PSORTINFO)lParamSort;
  581.     int       iReturn;
  582.     char      szTemp1[32];
  583.     char      szTemp2[32];
  584.  
  585.     if (psi->idFrom == IDC_PROCESS)
  586.     {
  587.         PPINFO ppi1 = (PPINFO)lParam1;
  588.         PPINFO ppi2 = (PPINFO)lParam2;
  589.  
  590.         switch (psi->iSubItem)
  591.         {
  592.             case 0:                         // module name
  593.                 iReturn = lstrcmpi(ppi1->szModName, ppi2->szModName);
  594.                 break;
  595.  
  596.             case 1:                         // process ID
  597.                 wsprintf(szTemp1, "%X", ppi1->pid);
  598.                 wsprintf(szTemp2, "%X", ppi2->pid);
  599.                 iReturn = lstrcmpi(szTemp1, szTemp2);
  600.                 break;
  601.  
  602.             case 2:                         // base priority
  603.                 if (ppi1->pcPriClassBase < ppi2->pcPriClassBase)    
  604.                     iReturn = -1;
  605.                 else
  606.                     if (ppi1->pcPriClassBase > ppi2->pcPriClassBase)
  607.                         iReturn = 1;
  608.                     else                    // same, so fall back on name
  609.                         iReturn = lstrcmpi(ppi1->szModName, 
  610.                                            ppi2->szModName);
  611.                 break;
  612.  
  613.             case 3:                          // thread count
  614.                 if (ppi1->cntThreads < ppi2->cntThreads)    
  615.                     iReturn = -1;
  616.                 else
  617.                     if (ppi1->cntThreads > ppi2->cntThreads)
  618.                         iReturn = 1;
  619.                     else                    // same, so fall back on name
  620.                         iReturn = lstrcmpi(ppi1->szModName, 
  621.                                            ppi2->szModName);
  622.                 break;
  623.             
  624.             case 4:                         // 16 or 32 bit
  625.                 if (ppi1->uAppType < ppi2->uAppType)
  626.                     iReturn = -1;
  627.                 else
  628.                     if (ppi1->uAppType == ppi2->uAppType)
  629.                         iReturn = 0;
  630.                     else
  631.                         iReturn = 1;
  632.                 break;
  633.  
  634.             case 5:                         // full path name
  635.                 iReturn = lstrcmpi(ppi1->szFullPath, ppi2->szFullPath);
  636.                 if (iReturn == 0)
  637.                     iReturn = lstrcmpi(ppi1->szModName, ppi2->szModName);
  638.                 break;                  
  639.  
  640.             default:
  641.                 iReturn = -1;
  642.         }
  643.     } // if(idFrom)
  644.     else
  645.     {
  646.         PTINFO pti1 = (PTINFO)lParam1;
  647.         PTINFO pti2 = (PTINFO)lParam2;
  648.  
  649.         switch (psi->iSubItem)
  650.         {
  651.             case 0:                         // thread id
  652.                 wsprintf(szTemp1, "%X", pti1->tid);
  653.                 wsprintf(szTemp2, "%X", pti2->tid);
  654.                 iReturn = lstrcmpi(szTemp1, szTemp2);
  655.                 break;
  656.  
  657.             case 1:                         // owning pid
  658.                 wsprintf(szTemp1, "%X", pti1->pidOwner);
  659.                 wsprintf(szTemp2, "%X", pti2->pidOwner);
  660.                 iReturn = lstrcmpi(szTemp1, szTemp2);
  661.                 break;
  662.  
  663.             case 2:                         // tpBasePri + tpDeltaPri
  664.                 if ((pti1->tpBasePri + pti1->tpDeltaPri) < 
  665.                     (pti2->tpBasePri + pti2->tpDeltaPri))   
  666.  
  667.                     iReturn = -1;
  668.                 else
  669.                     if ((pti1->tpBasePri + pti1->tpDeltaPri) > 
  670.                         (pti2->tpBasePri + pti2->tpDeltaPri))
  671.  
  672.                         iReturn = 1;
  673.                     else                    // same, so fall back on tid
  674.                     {
  675.                         wsprintf(szTemp1, "%X", pti1->tid);
  676.                         wsprintf(szTemp2, "%X", pti2->tid);
  677.                         iReturn = lstrcmpi(szTemp1, szTemp2);
  678.                     }
  679.                 break;
  680.  
  681.             default:
  682.                 iReturn = -1;
  683.         } 
  684.     } // else
  685.  
  686.     return iReturn;
  687. }
  688.                 
  689.  
  690. //
  691. //  FUNCTION: ListView_GetSelectedPid(HWND, LPSTR, int)
  692. //
  693. //  PURPOSE:  Retrieve the PID for the selected item in the list view             
  694. //
  695. //  PARAMETERS:
  696. //    
  697. //    hwndLV     - handle to the list view control
  698. //     lpszPath  - Buffer to contain full path of selected process's 
  699. //                 executable file
  700. //     cch       - Size in bytes of lpszPath
  701. //
  702. //  RETURN VALUE:
  703. //    The PID of the selected item in the list view control
  704. //
  705. //  COMMENTS:
  706. //
  707.  
  708. DWORD ListView_GetSelectedPid(HWND hwndLV, LPSTR lpszPath, int cch)
  709. {
  710.     int cbPathLen;
  711.     int index;          // index of the selected item
  712.     LV_ITEM lvi;
  713.  
  714.     // get the index of the selected item
  715.     index = ListView_GetNextItem(hwndLV, -1, LVNI_ALL | LVNI_SELECTED);
  716.     if (index == -1)
  717.         return 0;
  718.         
  719.     // fill out the LV_ITEM struct so we can get the PINFO struct stored
  720.     // in the lParam for the selected item
  721.     lvi.iItem = index;
  722.     lvi.iSubItem = 0;
  723.     lvi.mask = LVIF_PARAM;
  724.     ListView_GetItem(hwndLV, &lvi);
  725.  
  726.     cbPathLen = min (cch, sizeof(((PPINFO)(lvi.lParam))->szFullPath));
  727.     CopyMemory(lpszPath, ((PPINFO)(lvi.lParam))->szFullPath, cbPathLen);
  728.  
  729.     // return the PID
  730.     return (DWORD)((PPINFO)(lvi.lParam))->pid;
  731. }
  732.  
  733.  
  734.  
  735. //
  736. //  FUNCTION: LV_Subclass(HWND, UINT, WPARAM, LPARAM)
  737. //
  738. //  PURPOSE:  Subclass procedure so the thread list view can reject the focus
  739. //
  740. //  PARAMETERS:
  741. //
  742. //    hwnd      - Window handle  (Unused)
  743. //    uMessage  - WM_SETFOCUS    
  744. //    wparam    - handle of the window losing focus
  745. //    lparam    - Extra data     (Unused)
  746. //
  747. //  RETURN VALUE:
  748. //
  749. //    return 0 if the message is WM_SETFOCUS, otherwise the message is passed
  750. //    on to the default List view window procedure
  751. //
  752. //  COMMENTS:
  753. //
  754. //
  755.  
  756. LRESULT CALLBACK LV_Subclass(HWND hwnd, UINT uMsg, WPARAM wParam,
  757.         LPARAM lParam)
  758. {
  759.     switch (uMsg)
  760.     {
  761.         case WM_SETFOCUS:
  762.             // set the focus back to the the control losing the focus
  763.             SetFocus((HWND)wParam);
  764.             return 0;
  765.     }
  766.  
  767.     // if this is not the WM_SETFOCUS message, send it to the original
  768.     // window procedure
  769.     return CallWindowProc(g_lpfnThreadListView, hwnd, uMsg, wParam, 
  770.             lParam);
  771. }
  772.