home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / PROCS.ZIP / PROCS.C < prev    next >
Text File  |  1992-08-22  |  30KB  |  689 lines

  1. /**********************************************************************
  2.  * MODULE NAME :  procs.c                AUTHOR:  Rick Fishman        *
  3.  * DATE WRITTEN:  05-30-92                                            *
  4.  *                                                                    *
  5.  * DESCRIPTION:                                                       *
  6.  *                                                                    *
  7.  *  This program lists all running processes under OS/2 2.0. It uses  *
  8.  *  the undocumented API DosQProcStatus to get a buffer filled with   *
  9.  *  information related to the current state of the system. It then   *
  10.  *  performs the following using the buffer:                          *
  11.  *                                                                    *
  12.  *  1. Get the relevant process information for all active pids into  *
  13.  *     an array.                                                      *
  14.  *  2. Go thru the module information table. For each module found,   *
  15.  *     compare its module reference number against all module         *
  16.  *     reference numbers associated with the active pids. If any      *
  17.  *     match, add the module name to the active pid array.            *
  18.  *  3. Print the process names that were found.                       *
  19.  *                                                                    *
  20.  * UPDATES:                                                           *
  21.  *                                                                    *
  22.  *   6/06/92 - Sort by process id within process name.                *
  23.  *   6/06/92 - Add /f option for fully qualified process names.       *
  24.  *   7/06/92 - Get DOS program title from tasklist and print it.      *
  25.  *             Version 2.1 now.                                       *
  26.  *   7/17/92 - Add /i option to sort by process ID, combine hex and   *
  27.  *             decimal PID display. Up buffer size to 64k according   *
  28.  *             to advice from IBM doc. Get tasklist title more        *
  29.  *             efficiently. Version 2.2 now.                          *
  30.  *   8/22/92 - Change all characters less than 0x10 to blanks in a    *
  31.  *             DOS program's title. Version 2.21 now.                 *
  32.  *                                                                    *
  33.  **********************************************************************/
  34.  
  35.  
  36. /*********************************************************************/
  37. /*------- Include relevant sections of the OS/2 header files --------*/
  38. /*********************************************************************/
  39.  
  40. #define INCL_DOSERRORS
  41. #define INCL_DOSPROCESS
  42. #define INCL_VIO
  43. #define INCL_WINSWITCHLIST
  44.  
  45. /**********************************************************************/
  46. /*----------------------------- INCLUDES -----------------------------*/
  47. /**********************************************************************/
  48.  
  49. #include <os2.h>
  50. #include <conio.h>
  51. #include <ctype.h>
  52. #include <process.h>
  53. #include <stdarg.h>
  54. #include <stdio.h>
  55. #include <string.h>
  56. #include <stdlib.h>
  57. #include "procstat.h"
  58.  
  59. /*********************************************************************/
  60. /*------------------- APPLICATION DEFINITIONS -----------------------*/
  61. /*********************************************************************/
  62.  
  63. #define BUFFER_SIZE         0xFFFF
  64.  
  65. #define SCREEN_LINE_OVERHD  3
  66. #define DEF_SCREEN_LINES    25
  67.  
  68.                                 // COMMAND-LINE OPTIONS
  69. #define SUPPRESSMORE        'S' // Suppress More [Y,N] messages
  70. #define FULLNAMES           'F' // Fully qualify the process names
  71. #define SORTBYPID           'I' // Sort process by process Id
  72.  
  73. #define DOS_PROGRAM_IDENT   "SYSINIT" // Identifies a DOS program
  74.  
  75. #define OUT_OF_MEMORY_MSG   "\nOut of memory!\n"
  76.  
  77. #define COPYRIGHT_INFO      "Procs.exe, 32-bit, Version 2.21\n"                \
  78.                             "Copyright (c) Code Blazers, Inc. 1991-1992. "     \
  79.                             "All rights reserved.\n"
  80.  
  81. #define USAGE_INFO          "\nusage: procs StartingPoint [ /f /i /s ]\n "     \
  82.                             "\n    StartingPoint is a string that indicates "  \
  83.                             "\n    a ProcessName or partial ProcessName after" \
  84.                             "\n    which to start listing running processes"   \
  85.                             "\n    (not applicable with /i)"                   \
  86.                             "\n"                                               \
  87.                             "\n    /f - Fully qualify the process names"       \
  88.                             "\n    /i - Sort by process Id"                    \
  89.                             "\n    /s - Suppress More [Y,N] displays"          \
  90.                             "\n\n"
  91.  
  92. /**********************************************************************/
  93. /*---------------------------- STRUCTURES ----------------------------*/
  94. /**********************************************************************/
  95.  
  96. typedef struct _ACTIVEPID           // INFO ON AN ACTIVE PROCESS
  97. {
  98.     USHORT  hModRef;                // It's module reference handle
  99.     PID     pid;                    // It's Process Id
  100.     PSZ     szFullProcName;         // It's fully-qualified process name
  101.     PSZ     szProcess;              // It's non-fully qualified name
  102.  
  103. } ACTIVEPID, *PACTIVEPID;
  104.  
  105. /**********************************************************************/
  106. /*----------------------- FUNCTION PROTOTYPES ------------------------*/
  107. /**********************************************************************/
  108.  
  109. INT   main               ( INT argc, PSZ szArg[] );
  110. BOOL  Init               ( INT argc, PSZ szArg[] );
  111. BOOL  BuildActivePidTbl  ( PPROCESSINFO ppi );
  112. INT   CompareActivePids  ( const void *pActivePid1, const void *pActivePid2 );
  113. VOID  Procs              ( PSZ szStartingPoint );
  114. BOOL  StoreProcessName   ( PMODINFO pmi );
  115. INT   CompareProcessNames( const void *pActivePid1, const void *pActivePid2 );
  116. VOID  PrintReport        ( PSZ szStartingPoint );
  117. VOID  PrintDosPgmName    ( PID pid );
  118. VOID  Term               ( VOID );
  119.  
  120. /**********************************************************************/
  121. /*------------------------ GLOBAL VARIABLES --------------------------*/
  122. /**********************************************************************/
  123.  
  124. BOOL        fFullNames,             // Fully qualify process names or not
  125.             fSortByPid,             // Sort by process Id
  126.             fSuppressMore;          // Suppress More [Y,N] messages or not
  127.  
  128. INT         iStartingPoint;         // Index of argv array of print start point
  129.  
  130. USHORT      usActiveProcesses,      // Number of active processes
  131.             usScreenLines,          // Number of lines in current screen mode
  132.             usProcsToPrint,         // Number of processes that will be printed
  133.             usTaskItems;            // Number of items in tasklist
  134.  
  135. ACTIVEPID   *aActivePid;            // Array of active processes
  136.  
  137. PBUFFHEADER pbh;                    // Pointer to buffer header structure
  138.  
  139. /**********************************************************************/
  140. /*------------------------------ MAIN --------------------------------*/
  141. /*                                                                    */
  142. /*  MAIN DRIVER FOR PROGRAM.                                          */
  143. /*                                                                    */
  144. /*  INPUT: number of command-line arguments,                          */
  145. /*         command-line argument array                                */
  146. /*                                                                    */
  147. /*  1. Perform program initialization which will issue the            */
  148. /*     DosQProcStatus call and obtain the buffer of information.      */
  149. /*  2. If a starting point was given on the commandline, pass that    */
  150. /*     to the Procs function that will list running processes. If not,*/
  151. /*     pass a NULL address to the Procs function.                     */
  152. /*  3. Perform program termination.                                   */
  153. /*                                                                    */
  154. /*  OUTPUT: nothing                                                   */
  155. /*--------------------------------------------------------------------*/
  156. /**********************************************************************/
  157. INT main( INT argc, PSZ szArg[] )
  158. {
  159.     if( Init( argc, szArg ) )
  160.         if( iStartingPoint )
  161.             Procs( szArg[ iStartingPoint ] );
  162.         else
  163.             Procs( NULL );
  164.  
  165.     Term();
  166.  
  167.     return 0;
  168. }
  169.  
  170. /**********************************************************************/
  171. /*------------------------------ Init --------------------------------*/
  172. /*                                                                    */
  173. /*  PERFORM PROGRAM INITIALIZATION.                                   */
  174. /*                                                                    */
  175. /*  INPUT: number of command-line arguments,                          */
  176. /*         command-line argument array                                */
  177. /*                                                                    */
  178. /*  1. Print copyright notice.                                        */
  179. /*  2. If too many commandline parms, exit with usage info.           */
  180. /*  3. Process commandline options:                                   */
  181. /*     A. If FULLNAMES option is found, set the appropriate flag.     */
  182. /*     B. If SORTBYPID option is found, set the appropriate flag.     */
  183. /*     C. If SUPPRESSMORE option is found, set the appropriate flag.  */
  184. /*     D. If an invalid option, exit with usage info.                 */
  185. /*     E. If a starting point was specified, store the index into     */
  186. /*        the argv array for later use.                               */
  187. /*  4. Alocate memory for the output from DosQProcStatus.             */
  188. /*  5. Make the DosQProcStatus call.                                  */
  189. /*  6. Build an array of information related to active processes.     */
  190. /*  7. Get the number of screen lines supported by the window we are  */
  191. /*     running under.                                                 */
  192. /*                                                                    */
  193. /*  OUTPUT: TRUE or FALSE if successful or not                        */
  194. /*                                                                    */
  195. /*--------------------------------------------------------------------*/
  196. /**********************************************************************/
  197. BOOL Init( INT argc, PSZ szArg[] )
  198. {
  199.     SHORT   sIndex;
  200.     USHORT  usRetCode;
  201.     BOOL    fSuccess = TRUE;
  202.  
  203.     printf( COPYRIGHT_INFO );
  204.  
  205.     for( sIndex = 1; fSuccess && sIndex < argc; sIndex++ )
  206.     {
  207.         if( szArg[ sIndex ][ 0 ] == '/' || szArg[ sIndex ][ 0 ] == '-' )
  208.         {
  209.             switch( toupper( szArg[ sIndex ][ 1 ] ) )
  210.             {
  211.                 case FULLNAMES:
  212.                     fFullNames = TRUE;
  213.  
  214.                     break;
  215.  
  216.                 case SORTBYPID:
  217.                     fSortByPid = TRUE;
  218.  
  219.                     break;
  220.  
  221.                 case SUPPRESSMORE:
  222.                     fSuppressMore = TRUE;
  223.  
  224.                     break;
  225.  
  226.                 default:
  227.                     (void) printf( USAGE_INFO );
  228.  
  229.                     fSuccess = FALSE;
  230.             }
  231.         }
  232.         else if( !iStartingPoint )
  233.             iStartingPoint = sIndex;
  234.         else
  235.         {
  236.             (void) printf( USAGE_INFO );
  237.  
  238.             fSuccess = FALSE;
  239.         }
  240.     }
  241.  
  242.     if( fSuccess && !(pbh = malloc( BUFFER_SIZE )) )
  243.     {
  244.         printf( OUT_OF_MEMORY_MSG );
  245.  
  246.         fSuccess = FALSE;
  247.     }
  248.  
  249.     if( fSuccess )
  250.     {
  251.         usRetCode = DosQProcStatus( pbh, BUFFER_SIZE );
  252.  
  253.         if( usRetCode )
  254.         {
  255.             printf( "\nDosQProcStatus failed. RC: %u.", usRetCode );
  256.  
  257.             fSuccess = FALSE;
  258.         }
  259.         else
  260.             fSuccess = BuildActivePidTbl( pbh->ppi );
  261.     }
  262.  
  263.     if( fSuccess )
  264.     {
  265.         VIOMODEINFO vmi;
  266.  
  267.         vmi.cb = sizeof( VIOMODEINFO );
  268.  
  269.         usRetCode = VioGetMode( &vmi, 0 );
  270.  
  271.         if( usRetCode )
  272.             usScreenLines = DEF_SCREEN_LINES - SCREEN_LINE_OVERHD;
  273.         else
  274.             usScreenLines = vmi.row - SCREEN_LINE_OVERHD;
  275.     }
  276.  
  277.     return fSuccess;
  278. }
  279.  
  280. /**********************************************************************/
  281. /*------------------------ BuildActivePidTbl -------------------------*/
  282. /*                                                                    */
  283. /*  BUILD AN ARRAY OF ACTIVE PROCESSES USING THE PROCESS INFO SECTION */
  284. /*  OF THE DosQProcStatus BUFFER.                                     */
  285. /*                                                                    */
  286. /*  INPUT: pointer to ProcessInfo section of buffer                   */
  287. /*                                                                    */
  288. /*  1. Get a count of active processes.                               */
  289. /*  2. Allocate memory for the ActiveProcess table.                   */
  290. /*  3. Store information about each active process in the table.      */
  291. /*  4. Sort the table in ascending module number order.               */
  292. /*                                                                    */
  293. /*  OUTPUT: exit code                                                 */
  294. /*                                                                    */
  295. /*--------------------------------------------------------------------*/
  296. /**********************************************************************/
  297. BOOL BuildActivePidTbl( PPROCESSINFO ppi )
  298. {
  299.     PPROCESSINFO ppiLocal = ppi;
  300.     BOOL         fSuccess = TRUE;
  301.  
  302.     // Count the number of processes in the process info section. The process
  303.     // count in the summary record is not reliable (2/17/92 - version 6.177)
  304.  
  305.     usActiveProcesses = 0;
  306.  
  307.     while( ppiLocal->ulEndIndicator != PROCESS_END_INDICATOR )
  308.     {
  309.         usActiveProcesses++;
  310.  
  311.         // Next PROCESSINFO struct found by taking the address of the first
  312.         // thread control block of the current PROCESSINFO structure and
  313.         // adding the size of a THREADINFO structure times the number of
  314.         // threads
  315.  
  316.         ppiLocal = (PPROCESSINFO) (ppiLocal->ptiFirst+ppiLocal->usThreadCount );
  317.     }
  318.  
  319.     if( !(aActivePid = malloc( usActiveProcesses * sizeof( ACTIVEPID ) )) )
  320.     {
  321.         printf( OUT_OF_MEMORY_MSG );
  322.  
  323.         fSuccess = FALSE;
  324.     }
  325.     else
  326.     {
  327.         INT i;
  328.  
  329.         memset( aActivePid, 0, usActiveProcesses * sizeof( ACTIVEPID ) );
  330.  
  331.         for( i = 0; i < usActiveProcesses; i++ )
  332.         {
  333.             aActivePid[ i ].hModRef = ppi->hModRef;
  334.  
  335.             aActivePid[ i ].pid = (PID) ppi->pid;
  336.  
  337.             ppi = (PPROCESSINFO) (ppi->ptiFirst + ppi->usThreadCount);
  338.         }
  339.  
  340.         qsort( aActivePid, usActiveProcesses, sizeof( ACTIVEPID ),
  341.                CompareActivePids );
  342.     }
  343.  
  344.     return fSuccess;
  345. }
  346.  
  347. /**********************************************************************/
  348. /*------------------------ CompareActivePids -------------------------*/
  349. /*                                                                    */
  350. /*  COMPARE FUNCTION FOR THE QSORT OF THE ACTIVE PID ARRAY. SORTS     */
  351. /*  THE ARRAY IN MODULE HANDLE ORDER.                                 */
  352. /*                                                                    */
  353. /*  INPUT: pointer to first element for compare,                      */
  354. /*         pointer to second element of compare                       */
  355. /*                                                                    */
  356. /*  1. Do the compare.                                                */
  357. /*                                                                    */
  358. /*  OUTPUT: < 0 means first < second                                  */
  359. /*          = 0 means first = second                                  */
  360. /*          > 0 means first > second                                  */
  361. /*                                                                    */
  362. /*--------------------------------------------------------------------*/
  363. /**********************************************************************/
  364. INT CompareActivePids( const void *pActivePid1, const void *pActivePid2 )
  365. {
  366.     if( ((PACTIVEPID)pActivePid1)->hModRef < ((PACTIVEPID)pActivePid2)->hModRef )
  367.         return -1;
  368.     else
  369.     if( ((PACTIVEPID)pActivePid1)->hModRef > ((PACTIVEPID)pActivePid2)->hModRef )
  370.         return +1;
  371.     else
  372.         return 0;
  373. }
  374.  
  375. /**********************************************************************/
  376. /*------------------------------ Procs -------------------------------*/
  377. /*                                                                    */
  378. /*  LIST ALL RUNNING PROCESSES.                                       */
  379. /*                                                                    */
  380. /*  INPUT: starting point of report                                   */
  381. /*                                                                    */
  382. /*  1. Print the titles for the report.                               */
  383. /*  2. Store the process names in the ActivePid array.                */
  384. /*  3. Sort the ActivePid array by process name.                      */
  385. /*  4. Print the report.                                              */
  386. /*                                                                    */
  387. /*  OUTPUT: nothing                                                   */
  388. /*                                                                    */
  389. /*--------------------------------------------------------------------*/
  390. /**********************************************************************/
  391. VOID Procs( PSZ szStartingPoint )
  392. {
  393.     PMODINFO pmi = pbh->pmi;
  394.     BOOL     fSuccess = TRUE;
  395.  
  396.     while( pmi )
  397.     {
  398.         if( !StoreProcessName( pmi ) )
  399.         {
  400.             fSuccess = FALSE;
  401.  
  402.             break;
  403.         }
  404.  
  405.         pmi = pmi->pNext;
  406.     }
  407.  
  408.     if( fSuccess )
  409.     {
  410.         qsort( aActivePid, usActiveProcesses, sizeof( ACTIVEPID ),
  411.                CompareProcessNames );
  412.  
  413.         PrintReport( szStartingPoint );
  414.     }
  415. }
  416.  
  417. /**********************************************************************/
  418. /*------------------------- StoreProcessName -------------------------*/
  419. /*                                                                    */
  420. /*  STORE THE PROCESS NAME FOR LATER PRINTING.                        */
  421. /*                                                                    */
  422. /*  INPUT: pointer to MODINFO structure                               */
  423. /*                                                                    */
  424. /*  1. Go thru each entry in the ActivePid array:                     */
  425. /*     A. If the module reference handle in the array is greater      */
  426. /*        than the one passed here, we could not find a match         */
  427. /*        because at this point the ActivePid array is sorted in      */
  428. /*        module reference handle order.                              */
  429. /*     B. If we find a match:                                         */
  430. /*        1. Set a pointer to the beginning of the process name.      */
  431. /*        2. If the user doesn't want fully qualified process names,  */
  432. /*           set the pointer to the name minus the directory info.    */
  433. /*        3. Allocate memory for the process name in the ActivePid    */
  434. /*           array element.                                           */
  435. /*        4. Copy the process name into the allocated memory.         */
  436. /*                                                                    */
  437. /*  OUTPUT: TRUE or FALSE if successful or not                        */
  438. /*--------------------------------------------------------------------*/
  439. /**********************************************************************/
  440. BOOL StoreProcessName( PMODINFO pmi )
  441. {
  442.     INT  i;
  443.     PSZ  szProcess;
  444.     BOOL fSuccess = TRUE;
  445.  
  446.     for( i = 0; (fSuccess && i < usActiveProcesses); i++ )
  447.     {
  448.         if( aActivePid[ i ].hModRef > pmi->hMod )
  449.             break;
  450.  
  451.         if( aActivePid[ i ].hModRef == pmi->hMod )
  452.         {
  453.             szProcess = pmi->szModName;
  454.  
  455.             aActivePid[ i ].szFullProcName = malloc( strlen( szProcess ) + 1 );
  456.  
  457.             if( aActivePid[ i ].szFullProcName )
  458.             {
  459.                 strcpy( aActivePid[ i ].szFullProcName, szProcess );
  460.  
  461.                 szProcess = strrchr( aActivePid[ i ].szFullProcName, '\\' );
  462.  
  463.                 if( szProcess )
  464.                     szProcess++;
  465.                 else
  466.                     szProcess = aActivePid[ i ].szFullProcName;
  467.  
  468.                 aActivePid[ i ].szProcess = szProcess;
  469.  
  470.                 usProcsToPrint++;
  471.             }
  472.             else
  473.             {
  474.                 (void) printf( OUT_OF_MEMORY_MSG );
  475.  
  476.                 fSuccess = FALSE;
  477.             }
  478.         }
  479.     }
  480.  
  481.     return fSuccess;
  482. }
  483.  
  484. /**********************************************************************/
  485. /*----------------------- CompareProcessNames ------------------------*/
  486. /*                                                                    */
  487. /*  COMPARE FUNCTION FOR THE QSORT OF THE ACTIVE PID ARRAY. SORTS     */
  488. /*  THE ARRAY IN PROCESS NAME ORDER.                                  */
  489. /*                                                                    */
  490. /*  INPUT: pointer to first element for compare,                      */
  491. /*         pointer to second element of compare                       */
  492. /*                                                                    */
  493. /*  1. Do the compare. If the process names are equal, sort within    */
  494. /*     process name by pid. If we are to sort by pid, don't worry     */
  495. /*     about process name.                                            */
  496. /*                                                                    */
  497. /*  OUTPUT: return from stricmp                                       */
  498. /*                                                                    */
  499. /*--------------------------------------------------------------------*/
  500. /**********************************************************************/
  501. INT CompareProcessNames( const void *pActivePid1, const void *pActivePid2 )
  502. {
  503.     PACTIVEPID pActPid1 = (PACTIVEPID) pActivePid1;
  504.     PACTIVEPID pActPid2 = (PACTIVEPID) pActivePid2;
  505.     INT        iResult;
  506.  
  507.     if( !fSortByPid )
  508.         iResult = stricmp( pActPid1->szProcess, pActPid2->szProcess );
  509.  
  510.     if( fSortByPid || !iResult )
  511.         if( pActPid1->pid < pActPid2->pid )
  512.             iResult = -1;
  513.         else
  514.         if( pActPid1->pid > pActPid2->pid )
  515.             iResult = +1;
  516.         else
  517.             iResult = 0;
  518.  
  519.     return iResult;
  520. }
  521.  
  522. /**********************************************************************/
  523. /*--------------------------- PrintReport ----------------------------*/
  524. /*                                                                    */
  525. /*  PRINT INFO ABOUT EACH PROCESS.                                    */
  526. /*                                                                    */
  527. /*  INPUT: starting point to begin report                             */
  528. /*                                                                    */
  529. /*  1. For each element in the ActivePid array:                       */
  530. /*     A. If we are passed the starting point specified on            */
  531. /*        the commandline, get the next element (unless we are sorting*/
  532. /*        by PID in which case starting point does not apply).        */
  533. /*     B. If we have exceeeded the screen lines for the window        */
  534. /*        that we are running under and the user has not specified    */
  535. /*        to suppress the More [Y,N] messages, display that message   */
  536. /*        and wait on a key. If the user wants more displayed,        */
  537. /*        continue, else exit.                                        */
  538. /*     C. Print information about the process.                        */
  539. /*                                                                    */
  540. /*  OUTPUT: nothing                                                   */
  541. /*--------------------------------------------------------------------*/
  542. /**********************************************************************/
  543. VOID PrintReport( PSZ szStartingPoint )
  544. {
  545.     INT     i, KbdChar;
  546.     USHORT  usLines = 0;
  547.     CHAR    szProcessNameDesc[ 64 ];
  548.     PSZ     szProcessName;
  549.  
  550.     strcpy( szProcessNameDesc, "Process Name " );
  551.  
  552.     if( !fFullNames )
  553.         strcat( szProcessNameDesc, "(use /f for fully qualified names)" );
  554.  
  555.     printf( "\n%-12.12s %-63.63s",
  556.             "PID(hex/dec)", szProcessNameDesc );
  557.  
  558.     printf( "\n%-12.12s %-63.63s",
  559.             "────────────",
  560.             "───────────────────────────────────────────────────────────────" );
  561.  
  562.     for( i = 0; i < usActiveProcesses; i++ )
  563.     {
  564.         if( !fSortByPid &&
  565.             szStartingPoint &&
  566.             stricmp( szStartingPoint, aActivePid[ i ].szProcess ) > 0 )
  567.             continue;
  568.  
  569.         if( !fSuppressMore && ++usLines > usScreenLines )
  570.         {
  571.             printf( "\nMore [Y,N]?" );
  572.  
  573.             fflush( stdout );
  574.  
  575.             KbdChar = getch();
  576.  
  577.             printf( "\r           \r" );
  578.  
  579.             fflush( stdout );
  580.  
  581.             if( toupper( KbdChar ) == 'N' )
  582.                 return;
  583.  
  584.             usLines = 0;
  585.         }
  586.         else
  587.             printf( "\n" );
  588.  
  589.         if( fFullNames )
  590.             szProcessName = aActivePid[ i ].szFullProcName;
  591.         else
  592.             szProcessName = aActivePid[ i ].szProcess;
  593.  
  594.         printf( "%3x     %3u  %s", aActivePid[ i ].pid, aActivePid[ i ].pid,
  595.                 szProcessName );
  596.  
  597.         if( !stricmp( szProcessName, DOS_PROGRAM_IDENT ) )
  598.             PrintDosPgmName( aActivePid[ i ].pid );
  599.     }
  600. }
  601.  
  602. /*~********************************************************************/
  603. /*------------------------- PrintDosPgmName --------------------------*/
  604. /*                                                                    */
  605. /*  FIND THE DOS PROGRAM NAME IN THE TASKLIST.                        */
  606. /*                                                                    */
  607. /*  INPUT: process id of dos program                                  */
  608. /*                                                                    */
  609. /*  1. Get the switch list entry for the DOS program using its PID.   */
  610. /*  2. Get rid of any carraige return/line feeds (or any other char   */
  611. /*     less than 0x10).                                               */
  612. /*  3. Print the title.                                               */
  613. /*                                                                    */
  614. /*  OUTPUT: nothing                                                   */
  615. /*                                                                    */
  616. /*--------------------------------------------------------------------*/
  617. /********************************************************************~*/
  618. VOID PrintDosPgmName( PID pid )
  619. {
  620.     HSWITCH hs;
  621.     SWCNTRL swctl;
  622.     PCH     pch;
  623.  
  624.     hs = WinQuerySwitchHandle( 0, pid );
  625.  
  626.     if( hs )
  627.     {
  628.         WinQuerySwitchEntry( hs, &swctl );
  629.  
  630.         pch = swctl.szSwtitle;
  631.  
  632.         while( *pch )
  633.         {
  634.             if( *pch < 0x10 )
  635.                 if( pch != swctl.szSwtitle && *(pch - 1) == 0x20 )
  636.                     memmove( pch, pch + 1, strlen( pch ) );
  637.                 else
  638.                 {
  639.                     *pch = 0x20;
  640.  
  641.                     pch++;
  642.                 }
  643.             else
  644.                 pch++;
  645.         }
  646.  
  647.         printf( "( %s )", swctl.szSwtitle );
  648.     }
  649. }
  650.  
  651. /**********************************************************************/
  652. /*------------------------------ Term --------------------------------*/
  653. /*                                                                    */
  654. /*  PERFORM PROGRAM TERMINATION                                       */
  655. /*                                                                    */
  656. /*  INPUT: nothing                                                    */
  657. /*                                                                    */
  658. /*  1. Free the ActiveProcess array. First free the memory for the    */
  659. /*     process name associated with each element of the array.        */
  660. /*  2. Free the buffer allocated for the DosQProcStatus output.       */
  661. /*  3. Return to the operating system.                                */
  662. /*                                                                    */
  663. /*  OUTPUT: nothing                                                   */
  664. /*                                                                    */
  665. /*--------------------------------------------------------------------*/
  666. /**********************************************************************/
  667. VOID Term()
  668. {
  669.     if( aActivePid )
  670.     {
  671.         INT i;
  672.  
  673.         for( i = 0; i < usActiveProcesses; i++ )
  674.             if( aActivePid[ i ].szFullProcName )
  675.                 free( aActivePid[ i ].szFullProcName );
  676.  
  677.         free( aActivePid );
  678.     }
  679.  
  680.     if( pbh )
  681.         free( pbh );
  682.  
  683.     DosExit( EXIT_PROCESS, 0 );
  684. }
  685.  
  686. /**********************************************************************
  687.  *                       END OF SOURCE CODE                           *
  688.  **********************************************************************/
  689.