tsrlist.c
上传用户:xiaoan1112
上传日期:2013-04-11
资源大小:19621k
文件大小:29k
源码类别:

操作系统开发

开发平台:

Visual C++

  1. /*********************************************************************
  2.  * Microsoft Diagnostics Version 2.0
  3.  *
  4.  * A diagnostic utility to detect as much useful information about a
  5.  *   customer's computer system as is possible.
  6.  *
  7.  * Microsoft Diagnostics:  We detect the World.
  8.  *
  9.  * TSRLIST.C - TSR Program detection routines.
  10.  *********************************************************************/
  11. /* Include Files */
  12. #include "msd.h"
  13. /* Made global to this file.  This prevents filling the structure with */
  14. /*   more TSR info than was previously allocated (on the extremely odd */
  15. /*   case of finding more TSRs when we actually get the driver info    */
  16. /*   than when we counted up how many there were.  Under multitasking  */
  17. /*   systems, the addition of a new TSR installing while this program  */
  18. /*   is running is a rare, though potential, possibility.              */
  19. WORD wTsrCount = 0;        /* The number of TSRs installed in memory */
  20. /*********************************************************************
  21.  * GetTsrInfoSize - Gets number of bytes required to store the data
  22.  *                  about the TSRs installed in the system.
  23.  *
  24.  * Returns:  The bytes required for the structure.
  25.  *********************************************************************/
  26. WORD GetTsrInfoSize (VOID)
  27. {
  28.   CHAR FAR * fpMcbHeader    = NULL;   /* Pointer to the MCB header         */
  29.   CHAR FAR * fpDeviceMemory = NULL;   /* Pointer into device driver memory */
  30.   DWORD      dwNextDeviceMemory = 0;  /* Pointer into next device driver   */
  31.                                       /*   memory                          */
  32.   DWORD      dwNextMcbHeader = 0;     /* Pointer to next MCB header        */
  33.   WORD FAR * fwWordPointer  = NULL;   /* WORD pointer to obtain WORD data  */
  34.                                       /*   from the MCB.                   */
  35.   WORD wMcbParagraphs = 0;            /* Size of the MCB in paragraphs     */
  36.   BOOL fEndOfList = FALSE;            /* TRUE when last MCB accounted for  */
  37.   /* Zero out the TSR count */
  38.   wTsrCount = 0;
  39.   /* Add the UMB chain to the DOS MCB chain */
  40.   LinkUmbToDosChain (TRUE);
  41.   /* Point to the first MCB */
  42.   fpMcbHeader = FindFirstMcbHeader();
  43.   /* Count MCBs until the MCB type is 'Z'  */
  44.   /*   ('Z' signifies the end of the list) */
  45.   while (fEndOfList == FALSE)
  46.     {
  47.       ++wTsrCount;
  48.       /* Get the size of the MCB */
  49.       fwWordPointer  = (WORD FAR *) (fpMcbHeader + 1);
  50.       wMcbParagraphs = fwWordPointer[1];
  51.       /* Determine if this was the last MCB */
  52.       if (*fpMcbHeader == 'Z')
  53.         fEndOfList = TRUE;
  54.       else
  55.         {
  56.           /* Determine if there are device drivers in this list */
  57.           if (wDosMajor >= 4 && wDosMajor < 10 &&
  58.               fpMcbHeader[8] == 'S' && fpMcbHeader[9] == 'D')
  59.             {
  60.               fpDeviceMemory = (CHAR FAR *)
  61.                              ((((DWORD) FP_SEG (fpMcbHeader) + 1) << 16) + 0);
  62.               /* Is this a valid DOS data area subsegment control block */
  63.               while (strchr ("DEIFXCBLS", fpDeviceMemory[0]))
  64.                 {
  65.                   /* If this is one we are interested in, */
  66.                   /*   bump the TSR count                 */
  67.                   /* if (fpDeviceMemory[0] == 'D' || fpDeviceMemory[0] == 'I') */
  68.                     ++wTsrCount;
  69.                   /* Point to the next device */
  70.                   fwWordPointer      = (WORD FAR *) (fpDeviceMemory + 1);
  71.                   dwNextDeviceMemory = *fwWordPointer;
  72.                   fwWordPointer      = (WORD FAR *) (fpDeviceMemory + 3);
  73.                   dwNextDeviceMemory += *fwWordPointer;
  74.                   fpDeviceMemory     = (CHAR FAR *) (dwNextDeviceMemory << 16);
  75.                 }
  76.             }
  77.           /* Point to the next MCB */
  78.           dwNextMcbHeader = (DWORD) fpMcbHeader +
  79.                             ((DWORD) (wMcbParagraphs + 1) << 16);
  80.           fpMcbHeader     = (CHAR FAR *) dwNextMcbHeader;
  81.         }
  82.     }
  83.   /* Account for the zeroed out TSR record at the end of the struct */
  84.   ++wTsrCount;
  85.   /* Set the UMB/DOS MCB chain back to normal */
  86.   LinkUmbToDosChain (FALSE);
  87.   /* Return the number of bytes required to store the structure */
  88.   return (wTsrCount * sizeof (TSR_PROGRAMS_STRUCT));
  89. }
  90. /*********************************************************************
  91.  * GetTsrInfo - Fills the TSR_PROGRAMS_STRUCT with information about
  92.  *              the TSR programs installed in the system.
  93.  *
  94.  * Returns:  The bytes required for the structure.
  95.  *********************************************************************/
  96. BOOL GetTsrInfo (TSR_PROGRAMS_STRUCT *pTsrStruct, BOOL fMinimumInfo)
  97. {
  98.   CHAR FAR * fpMcbHeader     = NULL;  /* Pointer to the MCB header         */
  99.   DWORD      dwNextMcbHeader = 0;     /* Pointer to next MCB header        */
  100.   CHAR FAR * fpPspAddress    = NULL;  /* Address of the MCB's PSP          */
  101.   CHAR FAR * fpParentPspAddress = NULL; /* Address of parent's PSP         */
  102.   CHAR FAR * fpTsrName       = NULL;  /* Points to TSR program's name      */
  103.                                       /*   environment (for program name)  */
  104.   CHAR FAR * fpCommandLine   = NULL;  /* Command line parameters           */
  105.   WORD wMcbParagraphs        = 0;     /* Size of the MCB in paragraphs     */
  106.   CHAR FAR * fpDeviceMemory  = NULL;  /* Pointer into device driver subMCB */
  107.   CHAR FAR * fpDeviceStruct  = NULL;  /* Pointer to device driver itself   */
  108.   DWORD      dwNextDeviceMemory = 0;  /* Pointer into next device driver   */
  109.                                       /*   memory                          */
  110.   WORD FAR * fwWordPointer   = NULL;  /* WORD pointer to obtain WORD data  */
  111.                                       /*   from the MCB.                   */
  112.   WORD i = 0;                         /* Looping variable                  */
  113.   WORD wIndex;                        /* Index to structure                */
  114.   BOOL fEndOfList = FALSE;            /* TRUE when last MCB accounted for  */
  115.   WORD wCharCount = 0;                /* Number of characters in the       */
  116.                                       /*   command line.                   */
  117.   /* There is no minimum info to return from this routine */
  118.   if (fMinimumInfo)
  119.     return (FALSE);
  120.   /* Add the UMB chain to the DOS MCB chain */
  121.   LinkUmbToDosChain (TRUE);
  122.   /* Point to the first MCB */
  123.   fpMcbHeader = FindFirstMcbHeader();
  124.   /* Count MCBs until the MCB type is 'Z'  */
  125.   /*   ('Z' signifies the end of the list) */
  126.   for (wIndex = 0; wIndex < wTsrCount - 1 && fEndOfList == FALSE; ++wIndex)
  127.     {
  128.       /* Store the address of the MCB */
  129.       pTsrStruct[wIndex].wAddress = FP_SEG (fpMcbHeader);
  130.       /* Get the size of the MCB */
  131.       fwWordPointer  = (WORD FAR *) (fpMcbHeader + 1);
  132.       wMcbParagraphs = fwWordPointer[1];
  133.       pTsrStruct[wIndex].dwBlockSize = (DWORD) wMcbParagraphs << 4;
  134.       /* Caluclate PSP and parent's PSP */
  135.       fpPspAddress  = (CHAR FAR *) ((DWORD) fwWordPointer[0] << 16);
  136.       fwWordPointer = (WORD FAR *) (fpPspAddress + 16);
  137.       fpParentPspAddress = (CHAR FAR *) ((DWORD) *fwWordPointer << 16);
  138.       /* Get the MCB's Owner's name */
  139.       /* If the PSP Segment is 0000H it's free,     */
  140.       /*   if it's 0008H, it's the DOS System Area. */
  141.       if (FP_SEG (fpPspAddress) == 0x0000)
  142.         {
  143.           strcpy (pTsrStruct[wIndex].szTsrName, pszFreeMemory);
  144.           pTsrStruct[wIndex].szParameters[0] = '';
  145.         }
  146.       else if (FP_SEG (fpPspAddress) == 0x0008)
  147.         {
  148.           /* Determine if it is the device driver area, etc */
  149.           if (wDosMajor >= 4 && wDosMajor < 10)
  150.             {
  151.               /* "SC" is System Code / Locked out UMBs */
  152.               if (wDosMajor >= 5 &&
  153.                   fpMcbHeader[8] == 'S' && fpMcbHeader[9] == 'C')
  154.                 {
  155.                   /* If the address + block size > A0000, it's */
  156.                   /*   a locked out region.                    */
  157.                   if (((DWORD) (pTsrStruct[wIndex].wAddress) << 4) +
  158.                       pTsrStruct[wIndex].dwBlockSize > 0xA0000)
  159.                     strcpy (pTsrStruct[wIndex].szTsrName, pszExcludedUmbArea);
  160.                   else
  161.                     strcpy (pTsrStruct[wIndex].szTsrName, pszDosSystemCode);
  162.                   pTsrStruct[wIndex].szParameters[0] = '';
  163.                 }
  164.               /* "SD" is System Data / Device Drivers, etc */
  165.               else if (wDosMajor == 4 || (wDosMajor >= 5 &&
  166.                        fpMcbHeader[8] == 'S' && fpMcbHeader[9] == 'D'))
  167.                 {
  168.                   strcpy (pTsrStruct[wIndex].szTsrName, pszDosSystemData);
  169.                   pTsrStruct[wIndex].szParameters[0] = '';
  170.                   fpDeviceMemory = (CHAR FAR *)
  171.                                  ((((DWORD) FP_SEG (fpMcbHeader) + 1) << 16) + 0);
  172.                   /* Is this a valid DOS data area subsegment control block */
  173.                   for (++wIndex;
  174.                        strchr ("DEIFXCBLS", fpDeviceMemory[0]) &&
  175.                        wIndex < wTsrCount - 1 && fEndOfList == FALSE;
  176.                        ++wIndex)
  177.                     {
  178.                       pTsrStruct[wIndex].szParameters[0] = '';
  179.                       switch (fpDeviceMemory[0])
  180.                         {
  181.                           case 'D':
  182.                           case 'I':
  183.                             /* If this is a device driver or installable */
  184.                             /*   file system, put the device name and    */
  185.                             /*   device filename into the structure.     */
  186.                             /* Address */
  187.                             fwWordPointer = (WORD FAR *) (fpDeviceMemory + 1);
  188.                             pTsrStruct[wIndex].wAddress = *fwWordPointer;
  189.                             /* Point to the Device Name */
  190.                             fpDeviceStruct = (CHAR FAR *)
  191.                                              (((DWORD) (*fwWordPointer)) << 16);
  192.                             /* Size */
  193.                             fwWordPointer = (WORD FAR *) (fpDeviceMemory + 3);
  194.                             pTsrStruct[wIndex].dwBlockSize =
  195.                                 ((DWORD) (*fwWordPointer)) << 4;
  196.                             /* Device Filename */
  197.                             pTsrStruct[wIndex].szTsrName[0] = ' ';
  198.                             pTsrStruct[wIndex].szTsrName[1] = ' ';
  199.                             _fmemcpy (&(pTsrStruct[wIndex].szTsrName[2]),
  200.                                       &fpDeviceMemory[8], 8);
  201.                             pTsrStruct[wIndex].szTsrName[10] = '';
  202.                             /* Device Name */
  203.                             fwWordPointer = (WORD FAR *) (fpDeviceStruct + 4);
  204.                             if (*fwWordPointer & 0x8000)
  205.                               {
  206.                                 /* Character Device */
  207.                                 _fmemcpy (pTsrStruct[wIndex].szParameters,
  208.                                           &fpDeviceStruct[10], 8);
  209.                                 pTsrStruct[wIndex].szParameters[8] = '';
  210.                               }
  211.                             else
  212.                               {
  213.                                 /* Block Device */
  214.                                 strcpy (pTsrStruct[wIndex].szParameters,
  215.                                         pszBlockDevice);
  216.                               }
  217.                             break;
  218.                           case 'E':
  219.                             strcpy (pTsrStruct[wIndex].szTsrName,
  220.                                     pszDeviceAppenage);
  221.                             /* Address */
  222.                             fwWordPointer = (WORD FAR *) (fpDeviceMemory + 1);
  223.                             pTsrStruct[wIndex].wAddress = *fwWordPointer;
  224.                             /* Size */
  225.                             fwWordPointer = (WORD FAR *) (fpDeviceMemory + 3);
  226.                             pTsrStruct[wIndex].dwBlockSize =
  227.                                 ((DWORD) (*fwWordPointer)) << 4;
  228.                             break;
  229.                           case 'F':
  230.                             strcpy (pTsrStruct[wIndex].szTsrName,
  231.                                     pszFileHandles);
  232.                             /* Address */
  233.                             fwWordPointer = (WORD FAR *) (fpDeviceMemory + 1);
  234.                             pTsrStruct[wIndex].wAddress = *fwWordPointer;
  235.                             /* Size */
  236.                             fwWordPointer = (WORD FAR *) (fpDeviceMemory + 3);
  237.                             pTsrStruct[wIndex].dwBlockSize =
  238.                                 ((DWORD) (*fwWordPointer)) << 4;
  239.                             break;
  240.                           case 'X':
  241.                             strcpy (pTsrStruct[wIndex].szTsrName,
  242.                                     pszFCBS);
  243.                             /* Address */
  244.                             fwWordPointer = (WORD FAR *) (fpDeviceMemory + 1);
  245.                             pTsrStruct[wIndex].wAddress = *fwWordPointer;
  246.                             /* Size */
  247.                             fwWordPointer = (WORD FAR *) (fpDeviceMemory + 3);
  248.                             pTsrStruct[wIndex].dwBlockSize =
  249.                                 ((DWORD) (*fwWordPointer)) << 4;
  250.                             break;
  251.                           case 'C':
  252.                           case 'B':
  253.                             strcpy (pTsrStruct[wIndex].szTsrName,
  254.                                     pszBuffers);
  255.                             /* Address */
  256.                             fwWordPointer = (WORD FAR *) (fpDeviceMemory + 1);
  257.                             pTsrStruct[wIndex].wAddress = *fwWordPointer;
  258.                             /* Size */
  259.                             fwWordPointer = (WORD FAR *) (fpDeviceMemory + 3);
  260.                             pTsrStruct[wIndex].dwBlockSize =
  261.                                 ((DWORD) (*fwWordPointer)) << 4;
  262.                             break;
  263.                           case 'L':
  264.                             strcpy (pTsrStruct[wIndex].szTsrName,
  265.                                     pszDirectories);
  266.                             /* Address */
  267.                             fwWordPointer = (WORD FAR *) (fpDeviceMemory + 1);
  268.                             pTsrStruct[wIndex].wAddress = *fwWordPointer;
  269.                             /* Size */
  270.                             fwWordPointer = (WORD FAR *) (fpDeviceMemory + 3);
  271.                             pTsrStruct[wIndex].dwBlockSize =
  272.                                 ((DWORD) (*fwWordPointer)) << 4;
  273.                             break;
  274.                           case 'S':
  275.                             strcpy (pTsrStruct[wIndex].szTsrName,
  276.                                     pszStacksArea);
  277.                             /* Address */
  278.                             fwWordPointer = (WORD FAR *) (fpDeviceMemory + 1);
  279.                             pTsrStruct[wIndex].wAddress = *fwWordPointer;
  280.                             /* Size */
  281.                             fwWordPointer = (WORD FAR *) (fpDeviceMemory + 3);
  282.                             pTsrStruct[wIndex].dwBlockSize =
  283.                                 ((DWORD) (*fwWordPointer)) << 4;
  284.                             break;
  285.                         }
  286.                       /* Point to the next device */
  287.                       fwWordPointer      = (WORD FAR *) (fpDeviceMemory + 1);
  288.                       dwNextDeviceMemory = *fwWordPointer;
  289.                       fwWordPointer      = (WORD FAR *) (fpDeviceMemory + 3);
  290.                       dwNextDeviceMemory += *fwWordPointer;
  291.                       fpDeviceMemory     = (CHAR FAR *) (dwNextDeviceMemory << 16);
  292.                     }
  293.                   --wIndex;
  294.                 }
  295.               /* We'll call this the DOS System Area, otherwise */
  296.               else
  297.                 {
  298.                   strcpy (pTsrStruct[wIndex].szTsrName, pszDosSystemArea);
  299.                   pTsrStruct[wIndex].szParameters[0] = '';
  300.                 }
  301.             }
  302.           else
  303.             {
  304.               strcpy (pTsrStruct[wIndex].szTsrName, pszDosSystemArea);
  305.               pTsrStruct[wIndex].szParameters[0] = '';
  306.             }
  307.         }
  308.       else
  309.         {
  310.           /* If the PSP == the parent's PSP, it's COMMAND.COM */
  311.           if (fpPspAddress == fpParentPspAddress)
  312.             strcpy (pTsrStruct[wIndex].szTsrName, pszCommandCom);
  313.           else
  314.             {
  315.               /* Otherwise, we have to find the name.  First, search */
  316.               /*   in the environment area.                          */
  317.               CHAR chEnvironName[80];   /* Buffer for storing what the */
  318.                                         /*   environment claims the is */
  319.                                         /*   the name of the TSR       */
  320.               fwWordPointer = (WORD FAR *) (fpPspAddress + 0x002C);
  321.               fpTsrName = (CHAR FAR *) ((DWORD) *fwWordPointer << 16);
  322.               /* The name of the program that owns this MCB is located */
  323.               /*   2 bytes after 2 zero bytes and a word count.  Loop  */
  324.               /*   through the environment block until 2 back-to-back  */
  325.               /*   zero bytes are located.                             */
  326.               while (!(fpTsrName[0] == 0 && fpTsrName[1] == 0))
  327.                 ++fpTsrName;
  328.               fpTsrName += 4;
  329.               /* fpTsrName is now pointing to the fully qualified path    */
  330.               /*   to the program name.  Parse for just the program name. */
  331.               for (i = 0; i < MAX_TSR_NAME - 1 &&
  332.                           *fpTsrName > ' '    &&
  333.                           *fpTsrName < 127;      ++fpTsrName)
  334.                 {
  335.                   if (*fpTsrName == '\')
  336.                     i = 0;
  337.                   else
  338.                     chEnvironName[i++] = *fpTsrName;
  339.                 }
  340.               /* If this was the real name, it should end with a zero   */
  341.               /*   byte.  If it was garbage, we should have dropped out */
  342.               /*   because fpTsrName pointed to something other than a  */
  343.               /*   zero byte, or the length of the string is zero.      */
  344.               if (*fpTsrName == '')
  345.                 chEnvironName[i] = '';
  346.               else
  347.                 chEnvironName[0] = '';
  348.               /* The name from the environment is now ready.  Next,     */
  349.               /*   get the MCB owner (DOS 4.0 and above).  If the MCB   */
  350.               /*   owner is the same as the beginning of the name from  */
  351.               /*   the environment, use chEnvironName.  Otherwise, use  */
  352.               /*   the MCB name.                                        */
  353.               if (wDosMajor < 4)
  354.                 {
  355.                   /* If there is no name, put in "???" */
  356.                   if (strlen (chEnvironName) == 0)
  357.                     strcpy (pTsrStruct[wIndex].szTsrName, "???");
  358.                   else
  359.                     strcpy (pTsrStruct[wIndex].szTsrName, chEnvironName);
  360.                 }
  361.               else
  362.                 {
  363.                   /* Obtain the program name from the MCB */
  364.                   fpTsrName = fpMcbHeader + 8;
  365.                   for (i = 0; i < 8             &&
  366.                               *fpTsrName >  ' ' &&
  367.                               *fpTsrName <  127 &&
  368.                               *fpTsrName == (CHAR) toupper (*fpTsrName);
  369.                               ++i, ++fpTsrName)
  370.                     {
  371.                       pTsrStruct[wIndex].szTsrName[i] = *fpTsrName;
  372.                     }
  373.                   pTsrStruct[wIndex].szTsrName[i] = '';
  374.                   /* Determine if this is a valid program name.  If we */
  375.                   /*   have not taken 8 characters from the MCB, we    */
  376.                   /*   should have run into a zero byte (the name is   */
  377.                   /*   null terminated if there are less than 8        */
  378.                   /*   characters).                                    */
  379.                   if (i < 8 && (*fpTsrName != '' ||
  380.                       pTsrStruct[wIndex].szTsrName[0] == ''))
  381.                     {
  382.                       /* Use the environment name */
  383.                       strcpy (pTsrStruct[wIndex].szTsrName, chEnvironName);
  384.                     }
  385.                   /* The MCB contains a valid name.  Check to see if the */
  386.                   /*   environment contains a more complete name (ie,    */
  387.                   /*   the environment contains an extention, the MCB    */
  388.                   /*   does not.                                         */
  389.                   else if (strnicmp (chEnvironName,
  390.                                      pTsrStruct[wIndex].szTsrName,
  391.                                      strlen (pTsrStruct[wIndex].szTsrName)) == 0)
  392.                     {
  393.                       strcpy (pTsrStruct[wIndex].szTsrName, chEnvironName);
  394.                     }
  395.                   if (strnicmp (pszCommand, pTsrStruct[wIndex].szTsrName,
  396.                                 strlen (pszCommand)) == 0)
  397.                     {
  398.                       /* The word "command" was found, put COMMAND.COM */
  399.                       /*   into the TSR Name field.                    */
  400.                       strcpy (pTsrStruct[wIndex].szTsrName, pszCommandCom);
  401.                     }
  402.                   if (pTsrStruct[wIndex].szTsrName[0] == '')
  403.                     {
  404.                       /* A valid program name could not be found */
  405.                       strcpy (pTsrStruct[wIndex].szTsrName, "???");
  406.                     }
  407.                 }
  408.             }
  409.           /* Get the command line parameters */
  410.           fpCommandLine = fpPspAddress + 0x0080;
  411.           /* The first byte is the number of characters in the */
  412.           /*   command line.                                   */
  413.           wCharCount = fpCommandLine[0];
  414.           if (wCharCount > MAX_TSR_CMD_LINE - 1)
  415.             wCharCount = MAX_TSR_CMD_LINE - 1;
  416.           ++fpCommandLine;
  417.           for (i = 0; i < wCharCount &&
  418.                       fpCommandLine[i] >= ' ' &&
  419.                       fpCommandLine[i] <= 127;   ++i)
  420.             pTsrStruct[wIndex].szParameters[i] = fpCommandLine[i];
  421.           pTsrStruct[wIndex].szParameters[i] = '';
  422.         }
  423.       /* Determine if this was the last MCB */
  424.       if (*fpMcbHeader == 'Z')
  425.         fEndOfList = TRUE;
  426.       else
  427.         {
  428.           /* Point to the next MCB */
  429.           dwNextMcbHeader = (DWORD) fpMcbHeader +
  430.                             ((DWORD) (wMcbParagraphs + 1) << 16);
  431.           fpMcbHeader     = (CHAR FAR *) dwNextMcbHeader;
  432.         }
  433.     }
  434.   /* Set the last record to zeroes */
  435.   pTsrStruct[wIndex].wAddress        = 0;
  436.   pTsrStruct[wIndex].dwBlockSize     = 0;
  437.   pTsrStruct[wIndex].szTsrName[0]    = '';
  438.   pTsrStruct[wIndex].szParameters[0] = '';
  439.   /* Set the UMB/DOS MCB chain back to normal */
  440.   LinkUmbToDosChain (FALSE);
  441.   return (FALSE);
  442. }
  443. /*********************************************************************
  444.  * SprintTsrInfo - Put TSR program information into a set of strings
  445.  *                 to be printed or displayed.
  446.  * fIncludeParms - TRUE if command line parameters are to be included.
  447.  *
  448.  * Returns:  NULL if an error occured.
  449.  *********************************************************************/
  450. QSZ * SprintTsrInfo (TSR_PROGRAMS_STRUCT *pTsrStruct,
  451.                      BOOL fIncludeParms)
  452. {
  453.   WORD wNmbrStrings;        /* Number of strings                     */
  454.   WORD wNmbrChars;          /* Number of characters in the strings   */
  455.   WORD wUnderlineLength;    /* Length of the underline string        */
  456.   WORD wIndex;              /* Index to the structure of TSR data    */
  457.   WORD i;                   /* Looping variable                      */
  458.   QSZ  *pqszStrings = NULL; /* Location for storing string pointers  */
  459.   /* Calculate the amount of space required for the strings */
  460.   wUnderlineLength = strlen (pszTsrUnderline);
  461.   if (fIncludeParms)
  462.     {
  463.       wNmbrChars   = strlen (pszTsrHeader) + 1 +
  464.                      wUnderlineLength      + 1 +
  465.                      (wTsrCount * (wUnderlineLength + 1));
  466.       if (wNmbrChars > _memmax() - 100)
  467.         fIncludeParms = FALSE;
  468.     }
  469.   if (fIncludeParms == FALSE)
  470.     wNmbrChars   = strlen (pszTsrHeader) + 1 +
  471.                    wUnderlineLength      + 1 +
  472.                    (wTsrCount * (TSR_CMD_LINE_COL + 1));
  473.   /* The underline string is expected to be as long as a line of */
  474.   /*   TSR program info.                                         */
  475.   wNmbrStrings = wTsrCount + 3;
  476.   /* "+ 3" is for the header line, the underline, and the NULL */
  477.   /*   pointer at the end of the array.                        */
  478.   /* Allocate space for the pointer area and string area */
  479.   pqszStrings = AllocStringSpace (wNmbrStrings, wNmbrChars);
  480.   if (pqszStrings == NULL)
  481.     return (NULL);
  482.   /* Put the first two strings in place */
  483.   Qstrcpy (pqszStrings[0], pszTsrHeader);
  484.   pqszStrings[1] = pqszStrings[0] + Qstrlen (pqszStrings[0]) + 1;
  485.   Qstrcpy (pqszStrings[1], pszTsrUnderline);
  486.   pqszStrings[2] = pqszStrings[1] + wUnderlineLength + 1;
  487.   /* Put the TSR information in place */
  488.   for (i = 2, wIndex = 0;
  489.        !(pTsrStruct[wIndex].wAddress  == 0 &&
  490.        pTsrStruct[wIndex].dwBlockSize == 0);
  491.        ++i, ++wIndex)
  492.     {
  493.       WORD wLength;       /* Current length of string */
  494.       CHAR chBuffer[80];  /* Buffer for string data   */
  495.       /* Fill the line with spaces */
  496.       Qmemset (pqszStrings[i], ' ', wUnderlineLength);
  497.       pqszStrings[i][wUnderlineLength] = '';
  498.       /* TSR Name */
  499.       Qstrcpy (pqszStrings[i], pTsrStruct[wIndex].szTsrName);
  500.       wLength    = Qstrlen (pqszStrings[i]);
  501.       pqszStrings[i][wLength] = ' ';
  502.       /* Size */
  503.       wLength = sprintf (chBuffer, "%6lu",
  504.                          pTsrStruct[wIndex].dwBlockSize);
  505.       Qstrcpy (&pqszStrings[i][TSR_SIZE_COL], chBuffer);
  506.       pqszStrings[i][TSR_SIZE_COL + wLength] = ' ';
  507.       /* Address */
  508.       wLength = sprintf (chBuffer, "%04X", pTsrStruct[wIndex].wAddress);
  509.       Qstrcpy (&pqszStrings[i][TSR_ADDRESS_COL], chBuffer);
  510.       pqszStrings[i][TSR_ADDRESS_COL + wLength] = ' ';
  511.       /* Command line parameters */
  512.       if (fIncludeParms)
  513.         Qstrcpy (&pqszStrings[i][TSR_CMD_LINE_COL],
  514.                 pTsrStruct[wIndex].szParameters);
  515.       /* Set the next pointer */
  516.       PrepNextString (pqszStrings, i);
  517.     }
  518.   /* Set the last pointer to NULL */
  519.   pqszStrings[i] = NULL;
  520.   /* Return the pointer to pqszStrings */
  521.   return (pqszStrings);
  522. }
  523. /*********************************************************************
  524.  * FindFirstMcbHeader - Finds the pointer to the first memory control
  525.  *                      block (MCB).
  526.  *
  527.  * Returns:  Far pointer to the first MCB.
  528.  *********************************************************************/
  529. CHAR FAR * FindFirstMcbHeader (VOID)
  530. {
  531.   union REGS regsIn, regsOut;   /* Register structures for int86x call */
  532.   struct SREGS sregs;           /* Segment registers for int86x call   */
  533.   WORD wMcbSegment        = 0;  /* Segment of first MCB                */
  534.   WORD FAR *fwWordPointer = NULL; /* A far pointer to a WORD           */
  535.   /* Get the address of the start of DOS' list of lists (ES:BX) */
  536.   regsIn.h.ah = 0x52;
  537.   int86x (0x21, &regsIn, &regsOut, &sregs);
  538.   /* Get first MCB Segment */
  539.   fwWordPointer = (WORD FAR *)
  540.                   ((((long) (sregs.es) << 16) + (long) (regsOut.x.bx)) - 2);
  541.   wMcbSegment = *fwWordPointer;
  542.   /* Return pointer to the first MCB */
  543.   return ((CHAR FAR *) ((DWORD) wMcbSegment << 16));
  544. }
  545. /*********************************************************************
  546.  * LinkUmbToDosChain - Links or unlinks UMBs to the DOS memory control
  547.  *                     block chain.
  548.  * fLinkFlag - TRUE  - Link UMBs to the DOS MCB chain.
  549.  *             FALSE - Set the chain back to the default.
  550.  *********************************************************************/
  551. VOID LinkUmbToDosChain (BOOL fLinkFlag)
  552. {
  553.   union REGS regsin, regsout;         /* Register structs for int86 call   */
  554.   static BOOL fDefaultLink = 0xFFFF;  /* Set to DOS Default of UMBs linked */
  555.                                       /*   or unlinked                     */
  556.   /* Are we running under a valid version of DOS */
  557.   if (wDosMajor >= 5 && wDosMajor < 10)
  558.     {
  559.       /* Set the default, if necessary */
  560.       if (fDefaultLink == 0xFFFF)
  561.         {
  562.           regsin.x.ax = 0x5802;
  563.           int86 (0x21, &regsin, &regsout);
  564.           if (regsout.x.cflag == 0)
  565.             fDefaultLink = (BOOL) regsout.h.al;
  566.           else
  567.             return;
  568.         }
  569.       /* Now, set the link as per the request */
  570.       regsin.x.ax = 0x5803;
  571.       if (fLinkFlag)
  572.         {
  573.           /* Link the UMB chain to the DOS MCB chain */
  574.           regsin.x.bx = 0x0001;
  575.           int86 (0x21, &regsin, &regsout);
  576.         }
  577.       else
  578.         {
  579.           /* Set the UMB chain link to the default state */
  580.           regsin.x.bx = fDefaultLink;
  581.           int86 (0x21, &regsin, &regsout);
  582.         }
  583.     }
  584. }