home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 8 / CDASC08.ISO / VRAC / MEMSZ210.ZIP / MEMSIZE.CC < prev    next >
C/C++ Source or Header  |  1993-07-28  |  111KB  |  3,281 lines

  1. /***************************************************************** MEMSIZE.CC
  2.  *                                        *
  3.  * System Resources Monitor                            *
  4.  *                                        *
  5.  * (C) Copyright 1991-1993 by Richard W. Papo.                    *
  6.  *                                        *
  7.  * This is 'FreeWare'.    As such, it may be copied and distributed        *
  8.  * freely.  If you want to use part of it in your own program, please        *
  9.  * give credit where credit is due.  If you want to change the            *
  10.  * program, please refer the change request to me or send me the        *
  11.  * modified source code.  I can be reached at CompuServe 72607,3111.        *
  12.  *                                        *
  13.  ****************************************************************************/
  14.  
  15. //
  16. // Things to do:
  17. //
  18. //   (1) Validate memory statistics against OS20MEMU.
  19. //
  20. //   (2) Provide an item to serve as a button to cause a secondary
  21. //     drive status window to be displayed.
  22. //
  23.  
  24. #define INCL_BASE
  25. #define INCL_PM
  26. #include <os2.h>
  27.  
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31.  
  32. #include "debug.h"
  33. #include "support.h"
  34.  
  35. #include "about.h"
  36. #include "config.h"
  37. #include "process.h"
  38. #include "profile.h"
  39. #include "restring.h"
  40.  
  41. #include "items.h"
  42.  
  43. #include "memsize.h"
  44.  
  45. #define STATIC static
  46.  
  47.  
  48. /****************************************************************************
  49.  *                                        *
  50.  *             Definitions & Declarations                *
  51.  *                                        *
  52.  ****************************************************************************/
  53.  
  54.   // Constants
  55.  
  56. #define PROGRAM_NAME       "MEMSIZE"
  57. #define CLASS_NAME        PROGRAM_NAME
  58.  
  59. #define WM_REFRESH        (WM_USER)
  60.  
  61. #define MAX_DRIVES      (26)
  62. #define DRIVE_ERROR      (0xFFFFFFFFL)
  63.  
  64. enum
  65. {
  66.   ITEM_CLOCK,
  67.   ITEM_ELAPSEDTIME,
  68.   ITEM_MEMORYFREE,
  69.   ITEM_SWAPFILESIZE,
  70.   ITEM_SWAPDISKFREE,
  71.   ITEM_SPOOLFILESIZE,
  72.   ITEM_CPULOAD,
  73.   ITEM_TASKCOUNT,
  74.   ITEM_BASE_COUNT
  75. } ;
  76.  
  77.  
  78.   // Data Types
  79.  
  80. typedef struct          // Parameters saved to system.
  81. {
  82.   // The Display Item List - - -
  83.   Item         *Items [ ITEM_BASE_COUNT + MAX_DRIVES ] ;
  84.   int          ItemCount ;
  85.  
  86.   // Data required for the display item objects to function.
  87.   ULONG       IdleCount ;
  88.   ULONG       MaxCount ;
  89.   BYTE          SwapPath [_MAX_PATH] ;
  90.   ULONG       MinFree ;
  91.   PBYTE       SpoolPath ;
  92.   COUNTRYINFO      CountryInfo ;
  93.   ResourceString *Day ;
  94.   ResourceString *Days ;
  95.   ResourceString *DriveError ;
  96.  
  97.   // Window size and location
  98.   SWP     Position ;
  99.   BOOL     fPosition ;
  100.  
  101.   // User Options
  102.   BOOL     HideControls ;
  103.   BOOL     fHideControls ;
  104.  
  105.   BOOL     Float ;
  106.   BOOL     fFloat ;
  107.  
  108.   USHORT TimerInterval ;
  109.   BOOL     fTimerInterval ;
  110.  
  111.   // Presentation Parameters
  112.   BYTE     FontNameSize [80] ;
  113.   BOOL     fFontNameSize ;
  114.  
  115.   COLOR  BackColor ;
  116.   BOOL     fBackColor ;
  117.  
  118.   COLOR  TextColor ;
  119.   BOOL     fTextColor ;
  120. }
  121. PROFILE, *PPROFILE ;
  122.  
  123. typedef struct        // Data structure for window.
  124. {
  125.   HAB         Anchor ;
  126.   HMODULE     Library ;
  127.   HINI           ProfileHandle ;
  128.  
  129.   ULONG      IdleCounter ;
  130.   TID         IdleLoopTID ;
  131.   TID         MonitorLoopTID ;
  132.  
  133.   PROFILE     Profile ;
  134.  
  135.   HWND           hwndTitleBar ;
  136.   HWND           hwndSysMenu ;
  137.   HWND         hwndMinMax ;
  138.  
  139.   ULONG      Drives ;
  140.  
  141.   long         Width ;
  142.   long         Height ;
  143.  
  144. }
  145. DATA, *PDATA ;
  146.  
  147. typedef struct
  148. {
  149.   HAB Anchor ;
  150.   HMODULE Library ;
  151.   HINI ProfileHandle ;
  152. }
  153. PARMS, *PPARMS ;
  154.  
  155. typedef struct
  156. {
  157.   volatile PULONG Counter ;
  158.   PUSHORT Interval ;
  159.   HWND Owner ;
  160. }
  161. MONITOR_PARMS, *PMONITOR_PARMS ;
  162.  
  163.  
  164.   // Function Prototypes
  165.  
  166. extern INT main ( INT argc, PCHAR argv[] ) ;
  167.  
  168. STATIC MRESULT EXPENTRY MessageProcessor
  169. (
  170.   HWND hwnd,
  171.   USHORT msg,
  172.   MPARAM mp1,
  173.   MPARAM mp2
  174. ) ;
  175.  
  176. STATIC METHODFUNCTION Create ;
  177. STATIC METHODFUNCTION Destroy ;
  178. STATIC METHODFUNCTION Size ;
  179. STATIC METHODFUNCTION SaveApplication ;
  180. STATIC METHODFUNCTION Paint ;
  181. STATIC METHODFUNCTION Command ;
  182. STATIC METHODFUNCTION ResetDefaults ;
  183. STATIC METHODFUNCTION HideControlsCmd ;
  184. STATIC METHODFUNCTION Configure ;
  185. STATIC METHODFUNCTION About ;
  186. STATIC METHODFUNCTION ButtonDown ;
  187. STATIC METHODFUNCTION ButtonDblClick ;
  188. STATIC METHODFUNCTION PresParamChanged ;
  189. STATIC METHODFUNCTION SysColorChange ;
  190. STATIC METHODFUNCTION QueryKeysHelp ;
  191. STATIC METHODFUNCTION HelpError ;
  192. STATIC METHODFUNCTION ExtHelpUndefined ;
  193. STATIC METHODFUNCTION HelpSubitemNotFound ;
  194. STATIC METHODFUNCTION Refresh ;
  195.  
  196. STATIC int GetProfile ( HAB Anchor, HMODULE Library, HINI ProfileHandle, PPROFILE Profile ) ;
  197. STATIC VOID PutProfile ( HINI ProfileHandle, PPROFILE Profile ) ;
  198.  
  199. STATIC PSZ ScanSystemConfig ( HAB Anchor, PSZ Keyword ) ;
  200.  
  201. STATIC void ResizeWindow ( HWND hwnd, PPROFILE Profile ) ;
  202.  
  203. STATIC void HideControls
  204. (
  205.   BOOL fHide,
  206.   HWND hwndFrame,
  207.   HWND hwndSysMenu,
  208.   HWND hwndTitleBar,
  209.   HWND hwndMinMax
  210. ) ;
  211.  
  212. STATIC void UpdateWindow ( HWND hwnd, PDATA Data, BOOL All ) ;
  213.  
  214. STATIC VOID MonitorLoopThread ( PMONITOR_PARMS Parms ) ;
  215.  
  216. STATIC VOID UpdateDriveList
  217. (
  218.   HAB Anchor,
  219.   HMODULE Library,
  220.   HINI ProfileHandle,
  221.   PPROFILE Profile,
  222.   ULONG OldDrives,
  223.   ULONG NewDrives
  224. ) ;
  225.  
  226. STATIC BOOL CheckDrive ( USHORT Drive, PBYTE FileSystem ) ;
  227.  
  228. STATIC ULONG CalibrateLoadMeter ( VOID ) ;
  229.  
  230. STATIC VOID CounterThread ( PULONG Counter ) ;
  231.  
  232. STATIC HINI OpenProfile ( PSZ Name, HAB Anchor, HMODULE Library, HWND HelpInstance ) ;
  233.  
  234.  
  235. /****************************************************************************
  236.  *                                        *
  237.  *    Program Mainline                            *
  238.  *                                        *
  239.  ****************************************************************************/
  240.  
  241. extern INT main ( INT argc, PCHAR argv[] )
  242. {
  243.  /***************************************************************************
  244.   * Initialize the process.                            *
  245.   ***************************************************************************/
  246.  
  247.   Process Proc ;
  248.  
  249.  /***************************************************************************
  250.   * Now WIN and GPI calls will work.  Open the language DLL.            *
  251.   ***************************************************************************/
  252.  
  253.   HMODULE Library ;
  254.   if ( DosLoadModule ( NULL, 0, (PSZ)PROGRAM_NAME, &Library ) )
  255.   {
  256.     Debug ( HWND_DESKTOP, "ERROR: Unable to load " PROGRAM_NAME ".DLL." ) ;
  257.     DosExit ( EXIT_PROCESS, 1 ) ;
  258.   }
  259.  
  260.  /***************************************************************************
  261.   * Get the program title.                                        *
  262.   ***************************************************************************/
  263.  
  264.   ResourceString Title ( Library, IDS_TITLE ) ;
  265.  
  266.  /***************************************************************************
  267.   * Decipher command-line parameters.                        *
  268.   ***************************************************************************/
  269.  
  270.   BOOL Reset = FALSE ;
  271.  
  272.   ResourceString ResetCommand ( Library, IDS_PARMS_RESET ) ;
  273.  
  274.   while ( --argc )
  275.   {
  276.     argv ++ ;
  277.  
  278.     WinUpper ( Proc.QueryAnchor(), NULL, NULL, (PSZ)*argv ) ;
  279.  
  280.     if ( *argv[0] == '?' )
  281.     {
  282.       ResourceString Message ( Library, IDS_PARAMETERLIST ) ;
  283.  
  284.       WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, Message.Ptr(),
  285.     Title.Ptr(), 0, MB_ENTER | MB_NOICON ) ;
  286.  
  287.       DosExit ( EXIT_PROCESS, 1 ) ;
  288.     }
  289.  
  290.     if ( !strcmp ( *argv, (PCHAR)ResetCommand.Ptr() ) )
  291.     {
  292.       Reset = TRUE ;
  293.       continue ;
  294.     }
  295.  
  296.     {
  297.       ResourceString Format ( Library, IDS_ERROR_INVALIDPARM ) ;
  298.  
  299.       BYTE Message [200] ;
  300.       sprintf ( (PCHAR)Message, (PCHAR)Format.Ptr(), *argv ) ;
  301.  
  302.       WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, Message,
  303.     Title.Ptr(), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  304.  
  305.       DosExit ( EXIT_PROCESS, 1 ) ;
  306.     }
  307.   }
  308.  
  309.  /***************************************************************************
  310.   * Create the help instance.                            *
  311.   ***************************************************************************/
  312.  
  313.   HELPINIT HelpInit =
  314.   {
  315.     sizeof ( HELPINIT ),
  316.     0L,
  317.     NULL,
  318.     MAKEP ( 0xFFFF, ID_MAIN ),
  319.     0,
  320.     0,
  321.     0,
  322.     0,
  323.     NULL,
  324.     CMIC_HIDE_PANEL_ID,
  325.     (PSZ) ( PROGRAM_NAME ".HLP" )
  326.   } ;
  327.  
  328.   ResourceString HelpTitle ( Library, IDS_HELPTITLE ) ;
  329.  
  330.   HelpInit.pszHelpWindowTitle = HelpTitle.Ptr() ;
  331.  
  332.   HWND hwndHelp = WinCreateHelpInstance ( Proc.QueryAnchor(), &HelpInit ) ;
  333.  
  334.   if ( hwndHelp == NULL )
  335.   {
  336.     ResourceString Message ( Library, IDS_ERROR_WINCREATEHELPINSTANCE ) ;
  337.  
  338.     WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, Message.Ptr(),
  339.       Title.Ptr(), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  340.   }
  341.  
  342.  /***************************************************************************
  343.   * Open/create the profile file.                                       *
  344.   ***************************************************************************/
  345.  
  346.   HINI ProfileHandle = OpenProfile ( PSZ(PROGRAM_NAME),
  347.     Proc.QueryAnchor(), Library, hwndHelp ) ;
  348.  
  349.   if ( ProfileHandle == NULL )
  350.   {
  351.     ResourceString Message ( Library, IDS_ERROR_PRFOPENPROFILE ) ;
  352.  
  353.     Log ( "%s\r\n", Message.Ptr() ) ;
  354.  
  355.     WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, Message.Ptr(),
  356.       Title.Ptr(), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  357.  
  358.     DosFreeModule ( Library ) ;
  359.     DosExit ( EXIT_PROCESS, 1 ) ;
  360.   }
  361.  
  362.  /***************************************************************************
  363.   * If we're going to reset the program's profile, do it now.               *
  364.   ***************************************************************************/
  365.  
  366.   if ( Reset )
  367.   {
  368.     PrfWriteProfileData ( ProfileHandle, (PSZ)PROGRAM_NAME, NULL, NULL, 0 ) ;
  369.   }
  370.  
  371.  /***************************************************************************
  372.   * Create the frame window.                            *
  373.   ***************************************************************************/
  374.  
  375.   #pragma pack(2)
  376.   struct
  377.   {
  378.     USHORT Filler ;
  379.     USHORT cb ;
  380.     ULONG  flCreateFlags ;
  381.     USHORT hmodResources ;
  382.     USHORT idResources ;
  383.   }
  384.   fcdata ;
  385.   #pragma pack()
  386.  
  387.   fcdata.cb = sizeof(fcdata) - sizeof(fcdata.Filler) ;
  388.   fcdata.flCreateFlags =
  389.     FCF_TITLEBAR | FCF_SYSMENU | FCF_BORDER |
  390.     FCF_ICON | FCF_MINBUTTON | FCF_NOBYTEALIGN | FCF_ACCELTABLE ;
  391.   fcdata.hmodResources = 0 ;
  392.   fcdata.idResources = ID_MAIN ;
  393.  
  394.   HWND hwndFrame = WinCreateWindow
  395.   (
  396.     HWND_DESKTOP,
  397.     WC_FRAME,
  398.     Title.Ptr(),
  399.     0,
  400.     0, 0, 0, 0,
  401.     HWND_DESKTOP,
  402.     HWND_TOP,
  403.     ID_MAIN,
  404.     &fcdata.cb,
  405.     NULL
  406.   ) ;
  407.  
  408.   if ( hwndFrame == NULL )
  409.   {
  410.     ResourceString Message ( Library, IDS_ERROR_WINCREATEFRAME ) ;
  411.  
  412.     WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, Message.Ptr(),
  413.       Title.Ptr(), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  414.  
  415.     PrfCloseProfile ( ProfileHandle ) ;
  416.     DosFreeModule ( Library ) ;
  417.     DosExit ( EXIT_PROCESS, 1 ) ;
  418.   }
  419.  
  420.  /***************************************************************************
  421.   * Associate the help instance with the frame window.                *
  422.   ***************************************************************************/
  423.  
  424.   if ( hwndHelp )
  425.   {
  426.     WinAssociateHelpInstance ( hwndHelp, hwndFrame ) ;
  427.   }
  428.  
  429.  /***************************************************************************
  430.   * Register the window class.                            *
  431.   ***************************************************************************/
  432.  
  433.   if ( NOT WinRegisterClass ( Proc.QueryAnchor(), (PSZ)CLASS_NAME,
  434.     MessageProcessor, CS_MOVENOTIFY, sizeof(PVOID) ) )
  435.   {
  436.     ResourceString Format ( Library, IDS_ERROR_WINREGISTERCLASS ) ;
  437.  
  438.     BYTE Message [200] ;
  439.     sprintf ( PCHAR(Message), PCHAR(Format.Ptr()), CLASS_NAME ) ;
  440.  
  441.     WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, Message,
  442.       Title.Ptr(), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  443.  
  444.     PrfCloseProfile ( ProfileHandle ) ;
  445.     DosFreeModule ( Library ) ;
  446.     DosExit ( EXIT_PROCESS, 1 ) ;
  447.   }
  448.  
  449.  /***************************************************************************
  450.   * Create client window.  If this fails, destroy frame and return.        *
  451.   ***************************************************************************/
  452.  
  453.   PARMS Parms ;
  454.   Parms.Anchor = Proc.QueryAnchor() ;
  455.   Parms.Library = Library ;
  456.   Parms.ProfileHandle = ProfileHandle ;
  457.  
  458.   HWND hwndClient = WinCreateWindow
  459.   (
  460.     hwndFrame,
  461.     (PSZ)CLASS_NAME,
  462.     (PSZ)"",
  463.     0,
  464.     0, 0, 0, 0,
  465.     hwndFrame,
  466.     HWND_BOTTOM,
  467.     FID_CLIENT,
  468.     &Parms,
  469.     NULL
  470.   ) ;
  471.  
  472.   if ( hwndClient == NULL )
  473.   {
  474.     ResourceString Message ( Library, IDS_ERROR_WINCREATEWINDOW ) ;
  475.  
  476.     WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, Message.Ptr(),
  477.       Title.Ptr(), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  478.  
  479.     WinDestroyWindow ( hwndFrame ) ;
  480.     if ( hwndHelp )
  481.     {
  482.       WinDestroyHelpInstance ( hwndHelp ) ;
  483.     }
  484.     PrfCloseProfile ( ProfileHandle ) ;
  485.     DosFreeModule ( Library ) ;
  486.     DosExit ( EXIT_PROCESS, 1 ) ;
  487.   }
  488.  
  489.  /***************************************************************************
  490.   * Wait for and process messages to the window's queue.  Terminate         *
  491.   *   when the WM_QUIT message is received.                    *
  492.   ***************************************************************************/
  493.  
  494.   QMSG QueueMessage ;
  495.   while ( WinGetMsg ( Proc.QueryAnchor(), &QueueMessage, NULL, 0, 0 ) )
  496.   {
  497.     WinDispatchMsg ( Proc.QueryAnchor(), &QueueMessage ) ;
  498.   }
  499.  
  500.  /***************************************************************************
  501.   * Discard all that was requested of the system and terminate.         *
  502.   ***************************************************************************/
  503.  
  504.   WinDestroyWindow ( hwndFrame ) ;
  505.  
  506.   if ( hwndHelp )
  507.   {
  508.     WinDestroyHelpInstance ( hwndHelp ) ;
  509.   }
  510.  
  511.   PrfCloseProfile ( ProfileHandle ) ;
  512.  
  513.   DosFreeModule ( Library ) ;
  514.  
  515.   DosExit ( EXIT_PROCESS, 0 ) ;
  516. }
  517.  
  518. /****************************************************************************
  519.  *                                        *
  520.  *    Window Message Processor                        *
  521.  *                                        *
  522.  ****************************************************************************/
  523.  
  524. STATIC MRESULT EXPENTRY MessageProcessor
  525. (
  526.   HWND hwnd,
  527.   USHORT msg,
  528.   MPARAM mp1,
  529.   MPARAM mp2
  530. )
  531. {
  532.  /***************************************************************************
  533.   * Dispatch the message according to the method table and return the        *
  534.   *   result.  Any messages not defined above get handled by the system     *
  535.   *   default window processor.                         *
  536.   ***************************************************************************/
  537.  
  538.   static METHOD Methods [] =
  539.   {
  540.     { WM_CREATE,        Create            },
  541.     { WM_DESTROY,        Destroy         },
  542.     { WM_SIZE,            Size            },
  543.     { WM_MOVE,            Size            },
  544.     { WM_SAVEAPPLICATION,    SaveApplication     },
  545.     { WM_PAINT,         Paint            },
  546.     { WM_BUTTON1DOWN,        ButtonDown        },
  547.     { WM_BUTTON2DOWN,        ButtonDown        },
  548.     { WM_BUTTON1DBLCLK,     ButtonDblClick        },
  549.     { WM_BUTTON2DBLCLK,     ButtonDblClick        },
  550.     { WM_PRESPARAMCHANGED,    PresParamChanged    },
  551.     { WM_SYSCOLORCHANGE,    SysColorChange        },
  552.     { WM_COMMAND,        Command         },
  553.     { HM_QUERY_KEYS_HELP,    QueryKeysHelp        },
  554.     { HM_ERROR,         HelpError        },
  555.     { HM_EXT_HELP_UNDEFINED,    ExtHelpUndefined    },
  556.     { HM_HELPSUBITEM_NOT_FOUND, HelpSubitemNotFound },
  557.     { WM_REFRESH,        Refresh         }
  558.   } ;
  559.  
  560.   return ( DispatchMessage ( hwnd, msg, mp1, mp2, Methods, sizeof(Methods)/sizeof(Methods[0]), WinDefWindowProc ) ) ;
  561. }
  562.  
  563. /****************************************************************************
  564.  *                                        *
  565.  *    Create the main window.                         *
  566.  *                                        *
  567.  ****************************************************************************/
  568.  
  569. STATIC MRESULT APIENTRY Create
  570. (
  571.   HWND hwnd,
  572.   USHORT msg,
  573.   MPARAM mp1,
  574.   MPARAM mp2
  575. )
  576. {
  577.  /***************************************************************************
  578.   * Allocate instance data.                            *
  579.   ***************************************************************************/
  580.  
  581.   PDATA Data = malloc ( sizeof(DATA) ) ;
  582.  
  583.   memset ( Data, 0, sizeof(DATA) ) ;
  584.  
  585.   WinSetWindowPtr ( hwnd, QWL_USER, Data ) ;
  586.  
  587.  /***************************************************************************
  588.   * Grab any parameters from the WM_CREATE message.                *
  589.   ***************************************************************************/
  590.  
  591.   PPARMS Parms = (PPARMS) PVOIDFROMMP ( mp1 ) ;
  592.  
  593.   Data->Anchor = Parms->Anchor ;
  594.   Data->Library = Parms->Library ;
  595.   Data->ProfileHandle = Parms->ProfileHandle ;
  596.  
  597.  /***************************************************************************
  598.   * Get the current drive mask.                         *
  599.   ***************************************************************************/
  600.  
  601.   ULONG Drive ;
  602.   DosQueryCurrentDisk ( &Drive, &Data->Drives ) ;
  603.  
  604.  /***************************************************************************
  605.   * Initialize the global resource strings.                    *
  606.   ***************************************************************************/
  607.  
  608.   Data->Profile.Day       = new ResourceString ( Data->Library, IDS_DAY ) ;
  609.   Data->Profile.Days       = new ResourceString ( Data->Library, IDS_DAYS ) ;
  610.   Data->Profile.DriveError = new ResourceString ( Data->Library, IDS_DRIVEERROR ) ;
  611.  
  612.  /***************************************************************************
  613.   * Get country information.                            *
  614.   ***************************************************************************/
  615.  
  616.   COUNTRYCODE CountryCode ;
  617.   ULONG Count ;
  618.   ULONG Status ;
  619.  
  620.   CountryCode.country = 0 ;
  621.   CountryCode.codepage = 0 ;
  622.  
  623.   Status = DosGetCtryInfo ( sizeof(Data->Profile.CountryInfo), &CountryCode,
  624.     &Data->Profile.CountryInfo, &Count ) ;
  625.   if ( Status )
  626.   {
  627.     BYTE Message [80] ;
  628.     WinLoadMessage ( Data->Anchor, Data->Library, IDS_ERROR_DOSGETCTRYINFO,
  629.       sizeof(Message), Message ) ;
  630.     Debug ( hwnd, (PCHAR)Message, Status ) ;
  631.     Data->Profile.CountryInfo.fsDateFmt = DATEFMT_MM_DD_YY ;
  632.     Data->Profile.CountryInfo.fsTimeFmt = 0 ;
  633.     Data->Profile.CountryInfo.szDateSeparator[0] = '/' ;
  634.     Data->Profile.CountryInfo.szDateSeparator[1] = 0 ;
  635.     Data->Profile.CountryInfo.szTimeSeparator[0] = ':' ;
  636.     Data->Profile.CountryInfo.szTimeSeparator[1] = 0 ;
  637.     Data->Profile.CountryInfo.szThousandsSeparator[0] = ',' ;
  638.     Data->Profile.CountryInfo.szThousandsSeparator[1] = 0 ;
  639.   }
  640.  
  641.  /***************************************************************************
  642.   * Get the SWAPPATH statement from CONFIG.SYS.                 *
  643.   ***************************************************************************/
  644.  
  645.   PSZ Swappath = ScanSystemConfig ( Data->Anchor, (PSZ)"SWAPPATH" ) ;
  646.  
  647.   if ( Swappath == NULL )
  648.   {
  649.     Swappath = (PSZ) "C:\\OS2\\SYSTEM 0" ;
  650.   }
  651.  
  652.   sscanf ( (PCHAR)Swappath, "%s %li",
  653.     Data->Profile.SwapPath, &Data->Profile.MinFree ) ;
  654.  
  655.  /***************************************************************************
  656.   * Find out where the spool work directory is.                 *
  657.   ***************************************************************************/
  658.  
  659.   Data->Profile.SpoolPath = NULL ;
  660.  
  661.   ULONG Size ;
  662.   if ( PrfQueryProfileSize ( HINI_PROFILE, (PSZ)"PM_SPOOLER", (PSZ)"DIR", &Size ) )
  663.   {
  664.     Data->Profile.SpoolPath = malloc ( (int)Size ) ;
  665.  
  666.     if ( Data->Profile.SpoolPath )
  667.     {
  668.       if ( PrfQueryProfileData ( HINI_PROFILE, (PSZ)"PM_SPOOLER", (PSZ)"DIR", Data->Profile.SpoolPath, &Size ) )
  669.       {
  670.     PBYTE p = (PBYTE) strchr ( (PCHAR)Data->Profile.SpoolPath, ';' ) ;
  671.     if ( p )
  672.     {
  673.       *p = 0 ;
  674.     }
  675.       }
  676.       else
  677.       {
  678.     free ( Data->Profile.SpoolPath ) ;
  679.     Data->Profile.SpoolPath = NULL ;
  680.       }
  681.     }
  682.   }
  683.  
  684.  /***************************************************************************
  685.   * Calibrate the old-style load meter, if the high resolution timer's      *
  686.   *   available.                                *
  687.   ***************************************************************************/
  688.  
  689.   Data->Profile.MaxCount = CalibrateLoadMeter ( ) ;
  690.   Data->Profile.MaxCount = (ULONG) max ( 1L, Data->Profile.MaxCount ) ;
  691.  
  692.  /***************************************************************************
  693.   * Get profile data. Try the OS2.INI first, then try for private INI.      *
  694.   *   If obtained from OS2.INI, erase it afterwards.                        *
  695.   ***************************************************************************/
  696.  
  697.   if ( GetProfile ( Data->Anchor, Data->Library, HINI_USERPROFILE, &Data->Profile ) )
  698.   {
  699.     GetProfile ( Data->Anchor, Data->Library, Data->ProfileHandle, &Data->Profile ) ;
  700.   }
  701.   else
  702.   {
  703.     PrfWriteProfileData ( HINI_USERPROFILE, (PSZ)PROGRAM_NAME, NULL, NULL, 0 ) ;
  704.   }
  705.  
  706.  /***************************************************************************
  707.   * Get the frame handle.                            *
  708.   ***************************************************************************/
  709.  
  710.   HWND hwndFrame = WinQueryWindow ( hwnd, QW_PARENT ) ;
  711.  
  712.  /***************************************************************************
  713.   * Get the control window handles.                        *
  714.   ***************************************************************************/
  715.  
  716.   Data->hwndSysMenu  = WinWindowFromID ( hwndFrame, FID_SYSMENU  ) ;
  717.   Data->hwndTitleBar = WinWindowFromID ( hwndFrame, FID_TITLEBAR ) ;
  718.   Data->hwndMinMax   = WinWindowFromID ( hwndFrame, FID_MINMAX   ) ;
  719.  
  720.  /***************************************************************************
  721.   * Add basic extensions to the system menu.                    *
  722.   ***************************************************************************/
  723.  
  724.   static MENUITEM MenuSeparator =
  725.     { MIT_END, MIS_SEPARATOR, 0, 0, NULL, 0 } ;
  726.  
  727.   AddSysMenuItem ( hwndFrame, &MenuSeparator, NULL ) ;
  728.  
  729.   static MENUITEM MenuItems [] =
  730.   {
  731.     { MIT_END, MIS_TEXT,      0, IDM_SAVE_APPLICATION, NULL, 0 },
  732.     { MIT_END, MIS_TEXT,      0, IDM_RESET_DEFAULTS,   NULL, 0 },
  733.     { MIT_END, MIS_TEXT,      0, IDM_HIDE_CONTROLS,    NULL, 0 },
  734.     { MIT_END, MIS_TEXT,      0, IDM_CONFIGURE,        NULL, 0 },
  735.   } ;
  736.  
  737.   for ( int i=0; i<sizeof(MenuItems)/sizeof(MenuItems[0]); i++ )
  738.   {
  739.     ResourceString MenuText ( Data->Library, i+IDS_SAVE_APPLICATION ) ;
  740.     AddSysMenuItem ( hwndFrame, MenuItems+i, MenuText.Ptr() ) ;
  741.   }
  742.  
  743.   AddSysMenuItem ( hwndFrame, &MenuSeparator, NULL ) ;
  744.  
  745.  /***************************************************************************
  746.   * Add 'About' to the system menu.                        *
  747.   ***************************************************************************/
  748.  
  749.   static MENUITEM MenuAbout =
  750.     { MIT_END, MIS_TEXT, 0, IDM_ABOUT, NULL, 0 } ;
  751.  
  752.   ResourceString AboutText ( Data->Library, IDS_ABOUT ) ;
  753.  
  754.   AddSysMenuItem ( hwndFrame, &MenuAbout, AboutText.Ptr() ) ;
  755.  
  756.  /***************************************************************************
  757.   * Add 'Help' to the system menu.                        *
  758.   ***************************************************************************/
  759.  
  760.   static MENUITEM MenuHelp =
  761.     { MIT_END, MIS_HELP, 0, 0, NULL, 0 } ;
  762.  
  763.   ResourceString HelpText ( Data->Library, IDS_HELP ) ;
  764.  
  765.   AddSysMenuItem ( hwndFrame, &MenuHelp, HelpText.Ptr() ) ;
  766.  
  767.  /***************************************************************************
  768.   * Start the new load meter.                            *
  769.   ***************************************************************************/
  770.  
  771.   DosCreateThread ( &Data->IdleLoopTID, CounterThread, (ULONG)&Data->IdleCounter, 0, 4096 ) ;
  772.   DosSetPrty ( PRTYS_THREAD, PRTYC_IDLETIME, PRTYD_MINIMUM, Data->IdleLoopTID ) ;
  773.   DosSuspendThread ( Data->IdleLoopTID ) ;
  774.  
  775.   Data->Profile.IdleCount = 0 ;
  776.   Data->IdleCounter = 0 ;
  777.  
  778.   if ( Data->Profile.Items[ITEM_CPULOAD]->QueryFlag() )
  779.   {
  780.     DosResumeThread ( Data->IdleLoopTID ) ;
  781.   }
  782.  
  783.   PMONITOR_PARMS MonitorParms = PMONITOR_PARMS ( malloc ( sizeof(*MonitorParms) ) ) ;
  784.   MonitorParms->Counter = & Data->IdleCounter ;
  785.   MonitorParms->Interval = & Data->Profile.TimerInterval ;
  786.   MonitorParms->Owner = hwnd ;
  787.   DosCreateThread ( &Data->MonitorLoopTID, MonitorLoopThread, (ULONG)MonitorParms, 2, 8192 ) ;
  788.  
  789.  /***************************************************************************
  790.   * Add the program to the system task list.                    *
  791.   ***************************************************************************/
  792.  
  793.   ResourceString Title ( Data->Library, IDS_TITLE ) ;
  794.   Add2TaskList ( hwndFrame, Title.Ptr() ) ;
  795.  
  796.  /***************************************************************************
  797.   * Position & size the window.  For some reason, we must move and size     *
  798.   *   the window to the saved position before applying the resizing        *
  799.   *   function as fine-tuning.    Maybe the positioning request fails if        *
  800.   *   the window has no size?                            *
  801.   ***************************************************************************/
  802.  
  803.   WinSetWindowPos ( hwndFrame, HWND_BOTTOM,
  804.     Data->Profile.Position.x, Data->Profile.Position.y,
  805.     Data->Profile.Position.cx, Data->Profile.Position.cy,
  806.     SWP_SIZE | SWP_MOVE | SWP_ZORDER |
  807.     ( Data->Profile.Position.fl & SWP_MINIMIZE ) |
  808.     ( Data->Profile.Position.fl & SWP_RESTORE ) ) ;
  809.  
  810.   ResizeWindow ( hwnd, &Data->Profile ) ;
  811.  
  812.  /***************************************************************************
  813.   * Hide the controls if so configured.                     *
  814.   ***************************************************************************/
  815.  
  816.   if ( Data->Profile.HideControls
  817.     AND NOT ( Data->Profile.Position.fl & SWP_MINIMIZE ) )
  818.   {
  819.     CheckMenuItem ( hwndFrame, FID_SYSMENU, IDM_HIDE_CONTROLS, Data->Profile.HideControls ) ;
  820.  
  821.     HideControls
  822.     (
  823.       TRUE,
  824.       hwndFrame,
  825.       Data->hwndSysMenu,
  826.       Data->hwndTitleBar,
  827.       Data->hwndMinMax
  828.     ) ;
  829.   }
  830.  
  831.  /***************************************************************************
  832.   * Get the saved presentation parameters and reinstate them.            *
  833.   ***************************************************************************/
  834.  
  835.   if ( Data->Profile.fFontNameSize )
  836.   {
  837.     WinSetPresParam ( hwnd, PP_FONTNAMESIZE,
  838.       strlen((PCHAR)Data->Profile.FontNameSize)+1, Data->Profile.FontNameSize ) ;
  839.   }
  840.  
  841.   if ( Data->Profile.fBackColor )
  842.   {
  843.     WinSetPresParam ( hwnd, PP_BACKGROUNDCOLOR,
  844.       sizeof(Data->Profile.BackColor), &Data->Profile.BackColor ) ;
  845.   }
  846.  
  847.   if ( Data->Profile.fTextColor )
  848.   {
  849.     WinSetPresParam ( hwnd, PP_FOREGROUNDCOLOR,
  850.       sizeof(Data->Profile.TextColor), &Data->Profile.TextColor ) ;
  851.   }
  852.  
  853.  /***************************************************************************
  854.   * Determine our font size.                            *
  855.   ***************************************************************************/
  856.  
  857.   HPS hPS = WinGetPS ( hwnd ) ;
  858.   RECTL Rectangle ;
  859.   WinQueryWindowRect ( HWND_DESKTOP, &Rectangle ) ;
  860.   WinDrawText ( hPS, 1, (PSZ)" ", &Rectangle, 0L, 0L, DT_LEFT | DT_BOTTOM | DT_QUERYEXTENT ) ;
  861.   Data->Width  = Rectangle.xRight - Rectangle.xLeft ;
  862.   Data->Height = Rectangle.yTop - Rectangle.yBottom ;
  863.   WinReleasePS ( hPS ) ;
  864.  
  865.  /***************************************************************************
  866.   * Now that the window's in order, make it visible.                        *
  867.   ***************************************************************************/
  868.  
  869.   WinShowWindow ( hwndFrame, TRUE ) ;
  870.  
  871.  /***************************************************************************
  872.   * Success?  Return no error.                            *
  873.   ***************************************************************************/
  874.  
  875.   return ( 0 ) ;
  876. }
  877.  
  878. /****************************************************************************
  879.  *                                        *
  880.  *    Destroy main window.                            *
  881.  *                                        *
  882.  ****************************************************************************/
  883.  
  884. STATIC MRESULT APIENTRY Destroy
  885. (
  886.   HWND hwnd,
  887.   USHORT msg,
  888.   MPARAM mp1,
  889.   MPARAM mp2
  890. )
  891. {
  892.  /***************************************************************************
  893.   * Find the instance data.                            *
  894.   ***************************************************************************/
  895.  
  896.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  897.  
  898.  /***************************************************************************
  899.   * Release the instance memory.                        *
  900.   ***************************************************************************/
  901.  
  902.   free ( Data ) ;
  903.  
  904.  /***************************************************************************
  905.   * We're done.                                                             *
  906.   ***************************************************************************/
  907.  
  908.   return ( MRFROMSHORT ( 0 ) ) ;
  909. }
  910.  
  911. /****************************************************************************
  912.  *                                        *
  913.  *    Process window resize message.                        *
  914.  *                                        *
  915.  ****************************************************************************/
  916.  
  917. STATIC MRESULT APIENTRY Size
  918. (
  919.   HWND hwnd,
  920.   USHORT msg,
  921.   MPARAM mp1,
  922.   MPARAM mp2
  923. )
  924. {
  925.  /***************************************************************************
  926.   * Find the instance data.                            *
  927.   ***************************************************************************/
  928.  
  929.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  930.  
  931.  /***************************************************************************
  932.   * Find out the window's new position and size.                            *
  933.   ***************************************************************************/
  934.  
  935.   HWND hwndFrame = WinQueryWindow ( hwnd, QW_PARENT ) ;
  936.  
  937.   SWP Position ;
  938.   WinQueryWindowPos ( hwndFrame, &Position ) ;
  939.  
  940.   if ( NOT ( Position.fl & SWP_MINIMIZE )
  941.     AND NOT ( Position.fl & SWP_MAXIMIZE ) )
  942.   {
  943.     Data->Profile.Position.x = Position.x ;
  944.     Data->Profile.Position.y = Position.y ;
  945.  
  946.     Data->Profile.Position.cx = Position.cx ;
  947.     Data->Profile.Position.cy = Position.cy ;
  948.   }
  949.  
  950.  /***************************************************************************
  951.   * If hiding the controls . . .                        *
  952.   ***************************************************************************/
  953.  
  954.   if ( Data->Profile.HideControls )
  955.   {
  956.  
  957.    /*************************************************************************
  958.     * If changing to or from minimized state . . .                *
  959.     *************************************************************************/
  960.  
  961.     if ( ( Position.fl & SWP_MINIMIZE ) != ( Data->Profile.Position.fl & SWP_MINIMIZE ) )
  962.     {
  963.  
  964.      /***********************************************************************
  965.       * Hide the controls if no longer minimized.                *
  966.       ***********************************************************************/
  967.  
  968.       HideControls
  969.       (
  970.     NOT ( Position.fl & SWP_MINIMIZE ),
  971.     hwndFrame,
  972.     Data->hwndSysMenu,
  973.     Data->hwndTitleBar,
  974.     Data->hwndMinMax
  975.       ) ;
  976.     }
  977.   }
  978.  
  979.   Data->Profile.Position.fl = Position.fl ;
  980.  
  981.  /***************************************************************************
  982.   * We're done.                                                             *
  983.   ***************************************************************************/
  984.  
  985.   return ( 0 ) ;
  986. }
  987.  
  988. /****************************************************************************
  989.  *                                        *
  990.  *    Process SAVE APPLICATION message.                    *
  991.  *                                        *
  992.  ****************************************************************************/
  993.  
  994. STATIC MRESULT APIENTRY SaveApplication
  995. (
  996.   HWND hwnd,
  997.   USHORT msg,
  998.   MPARAM mp1,
  999.   MPARAM mp2
  1000. )
  1001. {
  1002.  /***************************************************************************
  1003.   * Find the instance data.                            *
  1004.   ***************************************************************************/
  1005.  
  1006.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1007.  
  1008.  /***************************************************************************
  1009.   * Call function to put all profile data out to the system.            *
  1010.   ***************************************************************************/
  1011.  
  1012.   PutProfile ( Data->ProfileHandle, &Data->Profile ) ;
  1013.  
  1014.  /***************************************************************************
  1015.   * We're done.  Let the system complete default processing.                *
  1016.   ***************************************************************************/
  1017.  
  1018.   return ( WinDefWindowProc ( hwnd, WM_SAVEAPPLICATION, 0, 0 ) ) ;
  1019. }
  1020.  
  1021. /****************************************************************************
  1022.  *                                        *
  1023.  *    Repaint entire window.                            *
  1024.  *                                        *
  1025.  ****************************************************************************/
  1026.  
  1027. STATIC MRESULT APIENTRY Paint
  1028. (
  1029.   HWND hwnd,
  1030.   USHORT msg,
  1031.   MPARAM mp1,
  1032.   MPARAM mp2
  1033. )
  1034. {
  1035.  /***************************************************************************
  1036.   * Find the instance data.                            *
  1037.   ***************************************************************************/
  1038.  
  1039.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1040.  
  1041.  /***************************************************************************
  1042.   * Get presentation space and make it use RGB colors.                *
  1043.   ***************************************************************************/
  1044.  
  1045.   HPS hPS = WinBeginPaint ( hwnd, NULL, NULL ) ;
  1046.   GpiCreateLogColorTable ( hPS, LCOL_RESET, LCOLF_RGB, 0L, 0L, NULL ) ;
  1047.  
  1048.  /***************************************************************************
  1049.   * Clear the window.                                *
  1050.   ***************************************************************************/
  1051.  
  1052.   RECTL Rectangle ;
  1053.   WinQueryWindowRect ( hwnd, &Rectangle ) ;
  1054.  
  1055.   GpiMove ( hPS, (PPOINTL) &Rectangle.xLeft ) ;
  1056.   GpiSetColor ( hPS, Data->Profile.BackColor ) ;
  1057.   GpiBox ( hPS, DRO_FILL, (PPOINTL) &Rectangle.xRight, 0L, 0L ) ;
  1058.  
  1059.  /***************************************************************************
  1060.   * Release presentation space.                         *
  1061.   ***************************************************************************/
  1062.  
  1063.   WinEndPaint ( hPS ) ;
  1064.  
  1065.  /***************************************************************************
  1066.   * Update the window and return.                        *
  1067.   ***************************************************************************/
  1068.  
  1069.   UpdateWindow ( hwnd, Data, TRUE ) ;
  1070.  
  1071.   return ( 0 ) ;
  1072. }
  1073.  
  1074. /****************************************************************************
  1075.  *                                        *
  1076.  *    Process commands received by Main Window                *
  1077.  *                                        *
  1078.  ****************************************************************************/
  1079.  
  1080. STATIC MRESULT APIENTRY Command
  1081. (
  1082.   HWND hwnd,
  1083.   USHORT msg,
  1084.   MPARAM mp1,
  1085.   MPARAM mp2
  1086. )
  1087. {
  1088.  /***************************************************************************
  1089.   * Dispatch all other commands through the method table.            *
  1090.   ***************************************************************************/
  1091.  
  1092.   static METHOD Methods [] =
  1093.   {
  1094.     { IDM_SAVE_APPLICATION, SaveApplication },
  1095.     { IDM_RESET_DEFAULTS,   ResetDefaults   },
  1096.     { IDM_HIDE_CONTROLS,    HideControlsCmd },
  1097.     { IDM_CONFIGURE,        Configure        },
  1098.     { IDM_EXIT,         Exit        },
  1099.     { IDM_ABOUT,        About        },
  1100.   } ;
  1101.  
  1102.   return ( DispatchMessage ( hwnd, SHORT1FROMMP(mp1), mp1, mp2, Methods, sizeof(Methods)/sizeof(Methods[0]), NULL ) ) ;
  1103. }
  1104.  
  1105. /****************************************************************************
  1106.  *                                        *
  1107.  *    Process Reset Defaults menu command.                    *
  1108.  *                                        *
  1109.  ****************************************************************************/
  1110.  
  1111. STATIC MRESULT APIENTRY ResetDefaults
  1112.   HWND hwnd, 
  1113.   USHORT msg, 
  1114.   MPARAM mp1, 
  1115.   MPARAM mp2
  1116. )
  1117. {
  1118.  /***************************************************************************
  1119.   * Find the instance data.                            *
  1120.   ***************************************************************************/
  1121.  
  1122.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1123.  
  1124.  /***************************************************************************
  1125.   * Reset all profile data for this program.                    *
  1126.   ***************************************************************************/
  1127.  
  1128.   PrfWriteProfileData ( Data->ProfileHandle, (PSZ)PROGRAM_NAME, NULL, NULL, 0 ) ;
  1129.  
  1130.  /***************************************************************************
  1131.   * Reset the program's presentation parameters.                            *
  1132.   ***************************************************************************/
  1133.  
  1134.   WinRemovePresParam ( hwnd, PP_FONTNAMESIZE ) ;
  1135.   WinRemovePresParam ( hwnd, PP_FOREGROUNDCOLOR ) ;
  1136.   WinRemovePresParam ( hwnd, PP_BACKGROUNDCOLOR ) ;
  1137.  
  1138.  /***************************************************************************
  1139.   * Done.                                    *
  1140.   ***************************************************************************/
  1141.  
  1142.   return ( MRFROMSHORT ( 0 ) ) ;
  1143. }
  1144.  
  1145. /****************************************************************************
  1146.  *                                        *
  1147.  *    Process Hide Controls menu command.                    *
  1148.  *                                        *
  1149.  ****************************************************************************/
  1150.  
  1151. STATIC MRESULT APIENTRY HideControlsCmd
  1152.   HWND hwnd, 
  1153.   USHORT msg, 
  1154.   MPARAM mp1, 
  1155.   MPARAM mp2
  1156. )
  1157. {
  1158.  /***************************************************************************
  1159.   * Find the instance data.                            *
  1160.   ***************************************************************************/
  1161.  
  1162.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1163.  
  1164.  /***************************************************************************
  1165.   * Toggle the Hide Controls setting.                        *
  1166.   ***************************************************************************/
  1167.  
  1168.   Data->Profile.HideControls = Data->Profile.HideControls ? FALSE : TRUE ;
  1169.   Data->Profile.fHideControls = TRUE ;
  1170.  
  1171.  /***************************************************************************
  1172.   * Get the frame handle.                                *
  1173.   ***************************************************************************/
  1174.  
  1175.   HWND hwndFrame = WinQueryWindow ( hwnd, QW_PARENT ) ;
  1176.  
  1177.  /***************************************************************************
  1178.   * If controls aren't hidden yet, update the menu check-mark.              *
  1179.   ***************************************************************************/
  1180.  
  1181.   if ( Data->Profile.HideControls )
  1182.     CheckMenuItem ( hwndFrame, FID_SYSMENU, IDM_HIDE_CONTROLS, Data->Profile.HideControls ) ;
  1183.  
  1184.  /***************************************************************************
  1185.   * If not minimized right now, hide or reveal the controls.            *
  1186.   ***************************************************************************/
  1187.  
  1188.   if ( NOT ( Data->Profile.Position.fl & SWP_MINIMIZE ) )
  1189.   {
  1190.     HideControls
  1191.     (
  1192.       Data->Profile.HideControls,
  1193.       hwndFrame,
  1194.       Data->hwndSysMenu,
  1195.       Data->hwndTitleBar,
  1196.       Data->hwndMinMax
  1197.     ) ;
  1198.   }
  1199.  
  1200.  /***************************************************************************
  1201.   * If controls are no longer hidden, update the menu check-mark.        *
  1202.   ***************************************************************************/
  1203.  
  1204.   if ( NOT Data->Profile.HideControls )
  1205.     CheckMenuItem ( hwndFrame, FID_SYSMENU, IDM_HIDE_CONTROLS, Data->Profile.HideControls ) ;
  1206.  
  1207.  /***************************************************************************
  1208.   * Done.                                    *
  1209.   ***************************************************************************/
  1210.  
  1211.   return ( MRFROMSHORT ( 0 ) ) ;
  1212. }
  1213.  
  1214. /****************************************************************************
  1215.  *                                        *
  1216.  *    Process Configure command.                        *
  1217.  *                                        *
  1218.  ****************************************************************************/
  1219.  
  1220. STATIC MRESULT APIENTRY Configure
  1221.   HWND hwnd, 
  1222.   USHORT msg, 
  1223.   MPARAM mp1, 
  1224.   MPARAM mp2
  1225. )
  1226. {
  1227.  /***************************************************************************
  1228.   * Find the instance data.                            *
  1229.   ***************************************************************************/
  1230.  
  1231.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1232.  
  1233.  /***************************************************************************
  1234.   * Invoke the Configure dialog.  If cancelled, just return.            *
  1235.   ***************************************************************************/
  1236.  
  1237.   CONFIG_PARMS Parms ;
  1238.   Parms.id          = IDD_CONFIGURE ;
  1239.   Parms.hwndHelp      = WinQueryHelpInstance ( hwnd ) ;
  1240.   Parms.HideControls  = Data->Profile.HideControls ;
  1241.   Parms.Float          = Data->Profile.Float ;
  1242.   Parms.TimerInterval = Data->Profile.TimerInterval ;
  1243.  
  1244.   Parms.ItemCount     = Data->Profile.ItemCount ;
  1245.  
  1246.   PSZ  ItemNames [ ITEM_BASE_COUNT + MAX_DRIVES ] ;
  1247.   BOOL ItemFlags [ ITEM_BASE_COUNT + MAX_DRIVES ] ;
  1248.   for ( int i=0; i<Data->Profile.ItemCount; i++ )
  1249.   {
  1250.     ItemNames[i] = Data->Profile.Items[i]->QueryOption () ;
  1251.     ItemFlags[i] = Data->Profile.Items[i]->QueryFlag () ;
  1252.   }
  1253.   Parms.ItemNames = ItemNames ;
  1254.   Parms.ItemFlags = ItemFlags ;
  1255.  
  1256.   if ( WinDlgBox ( HWND_DESKTOP, hwnd, ConfigureProcessor,
  1257.     Data->Library, IDD_CONFIGURE, &Parms ) == FALSE )
  1258.   {
  1259.     return ( MRFROMSHORT ( 0 ) ) ;
  1260.   }
  1261.  
  1262.  /***************************************************************************
  1263.   * Save the new timer interval.                        *
  1264.   ***************************************************************************/
  1265.  
  1266.   Data->Profile.fTimerInterval = TRUE ;
  1267.   Data->Profile.TimerInterval = Parms.TimerInterval ;
  1268.  
  1269.  /***************************************************************************
  1270.   * Save the float-to-top flag.                         *
  1271.   ***************************************************************************/
  1272.  
  1273.   Data->Profile.fFloat = TRUE ;
  1274.   Data->Profile.Float = Parms.Float ;
  1275.  
  1276.  /***************************************************************************
  1277.   * Save the hide controls flag, and adjust the window if it changed.        *
  1278.   ***************************************************************************/
  1279.  
  1280.   Data->Profile.fHideControls = TRUE ;
  1281.   if ( Data->Profile.HideControls != Parms.HideControls )
  1282.   {
  1283.     HWND FrameWindow = WinQueryWindow ( hwnd, QW_PARENT ) ;
  1284.     Data->Profile.HideControls = Parms.HideControls ;
  1285.     if ( Data->Profile.HideControls )
  1286.       CheckMenuItem ( FrameWindow, FID_SYSMENU, IDM_HIDE_CONTROLS, Data->Profile.HideControls ) ;
  1287.     if ( NOT ( Data->Profile.Position.fl & SWP_MINIMIZE ) )
  1288.     {
  1289.       HideControls
  1290.       (
  1291.     Data->Profile.HideControls,
  1292.     FrameWindow,
  1293.     Data->hwndSysMenu,
  1294.     Data->hwndTitleBar,
  1295.     Data->hwndMinMax
  1296.       ) ;
  1297.     }
  1298.     if ( NOT Data->Profile.HideControls )
  1299.       CheckMenuItem ( FrameWindow, FID_SYSMENU, IDM_HIDE_CONTROLS, Data->Profile.HideControls ) ;
  1300.   }
  1301.  
  1302.  /***************************************************************************
  1303.   * Determine if the display item list has changed.  If not, return.        *
  1304.   ***************************************************************************/
  1305.  
  1306.   BOOL ItemsChanged = FALSE ;
  1307.   for ( i=0; i<Data->Profile.ItemCount; i++ )
  1308.   {
  1309.     if ( ItemFlags[i] != Data->Profile.Items[i]->QueryFlag() )
  1310.     {
  1311.       ItemsChanged = TRUE ;
  1312.       break ;
  1313.     }
  1314.   }
  1315.  
  1316.   if ( NOT ItemsChanged )
  1317.   {
  1318.     return ( MRFROMSHORT ( 0 ) ) ;
  1319.   }
  1320.  
  1321.  /***************************************************************************
  1322.   * If CPU load monitoring has changed, start/stop the monitoring thread.   *
  1323.   ***************************************************************************/
  1324.  
  1325.   if ( ItemFlags[ITEM_CPULOAD] != Data->Profile.Items[ITEM_CPULOAD]->QueryFlag() )
  1326.   {
  1327.     if ( ItemFlags[ITEM_CPULOAD] )
  1328.       DosResumeThread ( Data->IdleLoopTID ) ;
  1329.     else
  1330.       DosSuspendThread ( Data->IdleLoopTID ) ;
  1331.   }
  1332.  
  1333.  /***************************************************************************
  1334.   * Save the new item flags.                            *
  1335.   ***************************************************************************/
  1336.  
  1337.   for ( i=0; i<Data->Profile.ItemCount; i++ )
  1338.   {
  1339.     if ( ItemFlags[i] )
  1340.       Data->Profile.Items[i]->SetFlag ( ) ;
  1341.     else
  1342.       Data->Profile.Items[i]->ResetFlag ( ) ;
  1343.   }
  1344.  
  1345.  /***************************************************************************
  1346.   * Resize the display window.                            *
  1347.   ***************************************************************************/
  1348.  
  1349.   ResizeWindow ( hwnd, &Data->Profile ) ;
  1350.  
  1351.  /***************************************************************************
  1352.   * Done.                                    *
  1353.   ***************************************************************************/
  1354.  
  1355.   return ( MRFROMSHORT ( 0 ) ) ;
  1356. }
  1357.  
  1358. /****************************************************************************
  1359.  *                                        *
  1360.  *    Process About menu command.                        *
  1361.  *                                        *
  1362.  ****************************************************************************/
  1363.  
  1364. STATIC MRESULT APIENTRY About
  1365.   HWND hwnd, 
  1366.   USHORT msg, 
  1367.   MPARAM mp1, 
  1368.   MPARAM mp2
  1369. )
  1370. {
  1371.  /***************************************************************************
  1372.   * Find the instance data.                            *
  1373.   ***************************************************************************/
  1374.  
  1375.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1376.  
  1377.  /***************************************************************************
  1378.   * Invoke the About dialog.                            *
  1379.   ***************************************************************************/
  1380.  
  1381.   ABOUT_PARMS Parms ;
  1382.   Parms.id = IDD_ABOUT ;
  1383.   Parms.hwndHelp = WinQueryHelpInstance ( hwnd ) ;
  1384.  
  1385.   WinDlgBox ( HWND_DESKTOP, hwnd, AboutProcessor,
  1386.     Data->Library, IDD_ABOUT, &Parms ) ;
  1387.  
  1388.  /***************************************************************************
  1389.   * Done.                                    *
  1390.   ***************************************************************************/
  1391.  
  1392.   return ( MRFROMSHORT ( 0 ) ) ;
  1393. }
  1394.  
  1395. /****************************************************************************
  1396.  *                                        *
  1397.  *    Process Mouse Button being pressed.                    *
  1398.  *                                        *
  1399.  ****************************************************************************/
  1400.  
  1401. STATIC MRESULT APIENTRY ButtonDown
  1402. (
  1403.   HWND hwnd,
  1404.   USHORT msg,
  1405.   MPARAM mp1,
  1406.   MPARAM mp2
  1407. )
  1408. {
  1409.  /***************************************************************************
  1410.   * Find the instance data.                            *
  1411.   ***************************************************************************/
  1412.  
  1413.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1414.  
  1415.  /***************************************************************************
  1416.   * Determine the new window position.                        *
  1417.   ***************************************************************************/
  1418.  
  1419.   TRACKINFO TrackInfo ;
  1420.   memset ( &TrackInfo, 0, sizeof(TrackInfo) ) ;
  1421.  
  1422.   TrackInfo.cxBorder = 1 ;
  1423.   TrackInfo.cyBorder = 1 ;
  1424.   TrackInfo.cxGrid = 1 ;
  1425.   TrackInfo.cyGrid = 1 ;
  1426.   TrackInfo.cxKeyboard = 8 ;
  1427.   TrackInfo.cyKeyboard = 8 ;
  1428.  
  1429.   HWND hwndFrame = WinQueryWindow ( hwnd, QW_PARENT ) ;
  1430.  
  1431.   SWP Position ;
  1432.   WinQueryWindowPos ( hwndFrame, &Position ) ;
  1433.   TrackInfo.rclTrack.xLeft   = Position.x ;
  1434.   TrackInfo.rclTrack.xRight  = Position.x + Position.cx ;
  1435.   TrackInfo.rclTrack.yBottom = Position.y ;
  1436.   TrackInfo.rclTrack.yTop    = Position.y + Position.cy ;
  1437.  
  1438.   WinQueryWindowPos ( HWND_DESKTOP, &Position ) ;
  1439.   TrackInfo.rclBoundary.xLeft   = Position.x ;
  1440.   TrackInfo.rclBoundary.xRight  = Position.x + Position.cx ;
  1441.   TrackInfo.rclBoundary.yBottom = Position.y ;
  1442.   TrackInfo.rclBoundary.yTop    = Position.y + Position.cy ;
  1443.  
  1444.   TrackInfo.ptlMinTrackSize.x = 0 ;
  1445.   TrackInfo.ptlMinTrackSize.y = 0 ;
  1446.   TrackInfo.ptlMaxTrackSize.x = Position.cx ;
  1447.   TrackInfo.ptlMaxTrackSize.y = Position.cy ;
  1448.  
  1449.   TrackInfo.fs = TF_MOVE | TF_STANDARD | TF_ALLINBOUNDARY ;
  1450.  
  1451.   if ( WinTrackRect ( HWND_DESKTOP, NULL, &TrackInfo ) )
  1452.   {
  1453.     WinSetWindowPos ( hwndFrame, NULL,
  1454.       (SHORT) TrackInfo.rclTrack.xLeft,
  1455.       (SHORT) TrackInfo.rclTrack.yBottom,
  1456.       0, 0, SWP_MOVE ) ;
  1457.   }
  1458.  
  1459.  /***************************************************************************
  1460.   * Return through the default processor, letting window activation        *
  1461.   *   and other system functions occur.                     *
  1462.   ***************************************************************************/
  1463.  
  1464.   return ( WinDefWindowProc ( hwnd, msg, mp1, mp2 ) ) ;
  1465. }
  1466.  
  1467. /****************************************************************************
  1468.  *                                        *
  1469.  *    Process Mouse Button having been double-clicked.            *
  1470.  *                                        *
  1471.  ****************************************************************************/
  1472.  
  1473. STATIC MRESULT APIENTRY ButtonDblClick
  1474. (
  1475.   HWND hwnd,
  1476.   USHORT msg,
  1477.   MPARAM mp1,
  1478.   MPARAM mp2
  1479. )
  1480. {
  1481.  /***************************************************************************
  1482.   * Send message to self to stop hiding the controls.                *
  1483.   ***************************************************************************/
  1484.  
  1485.   WinPostMsg ( hwnd, WM_COMMAND,
  1486.     MPFROM2SHORT ( IDM_HIDE_CONTROLS, 0 ),
  1487.     MPFROM2SHORT ( CMDSRC_OTHER, TRUE ) ) ;
  1488.  
  1489.  /***************************************************************************
  1490.   * Return through the default processor, letting window activation        *
  1491.   *   and other system functions occur.                     *
  1492.   ***************************************************************************/
  1493.  
  1494.   return ( WinDefWindowProc ( hwnd, msg, mp1, mp2 ) ) ;
  1495. }
  1496.  
  1497. /****************************************************************************
  1498.  *                                        *
  1499.  *    Process Presentation Parameter Changed notification.            *
  1500.  *                                        *
  1501.  ****************************************************************************/
  1502.  
  1503. STATIC MRESULT APIENTRY PresParamChanged
  1504. (
  1505.   HWND hwnd,
  1506.   USHORT msg,
  1507.   MPARAM mp1,
  1508.   MPARAM mp2
  1509. )
  1510. {
  1511.  /***************************************************************************
  1512.   * Find the instance data.                            *
  1513.   ***************************************************************************/
  1514.  
  1515.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1516.  
  1517.  /***************************************************************************
  1518.   * Get the presentation parameter that changed.                *
  1519.   ***************************************************************************/
  1520.  
  1521.   switch ( LONGFROMMP(mp1) )
  1522.   {
  1523.  
  1524.    /*************************************************************************
  1525.     * If font, note the fact that we now have a font to be saved as        *
  1526.     *    part of the configuration.  Get the font metrics and resize        *
  1527.     *    the window appropriately.                        *
  1528.     *************************************************************************/
  1529.  
  1530.     case PP_FONTNAMESIZE:
  1531.     {
  1532.       ULONG ppid ;
  1533.       if ( WinQueryPresParam ( hwnd, PP_FONTNAMESIZE, 0, &ppid,
  1534.     sizeof(Data->Profile.FontNameSize), &Data->Profile.FontNameSize,
  1535.     0 ) )
  1536.       {
  1537.     Data->Profile.fFontNameSize = TRUE ;
  1538.       }
  1539.       else
  1540.       {
  1541.     strcpy ( (PCHAR)Data->Profile.FontNameSize, "" ) ;
  1542.     Data->Profile.fFontNameSize = FALSE ;
  1543.     PrfWriteProfileData ( Data->ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"FontNameSize", NULL, 0 ) ;
  1544.       }
  1545.  
  1546.       HPS hPS = WinGetPS ( hwnd ) ;
  1547.       RECTL Rectangle ;
  1548.       WinQueryWindowRect ( HWND_DESKTOP, &Rectangle ) ;
  1549.       WinDrawText ( hPS, 1, (PSZ)" ", &Rectangle, 0L, 0L, DT_LEFT | DT_BOTTOM | DT_QUERYEXTENT ) ;
  1550.       Data->Width  = Rectangle.xRight - Rectangle.xLeft ;
  1551.       Data->Height = Rectangle.yTop - Rectangle.yBottom ;
  1552.       WinReleasePS ( hPS ) ;
  1553.       ResizeWindow ( hwnd, &Data->Profile ) ;
  1554.       break ;
  1555.     }
  1556.  
  1557.    /*************************************************************************
  1558.     * If background color, note the fact and repaint the window.        *
  1559.     *************************************************************************/
  1560.  
  1561.     case PP_BACKGROUNDCOLOR:
  1562.     {
  1563.       ULONG ppid ;
  1564.       if ( WinQueryPresParam ( hwnd, PP_BACKGROUNDCOLOR, 0, &ppid,
  1565.     sizeof(Data->Profile.BackColor), &Data->Profile.BackColor, 0 ) )
  1566.       {
  1567.     Data->Profile.fBackColor = TRUE ;
  1568.       }
  1569.       else
  1570.       {
  1571.     Data->Profile.BackColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_WINDOW, 0L ) ;
  1572.     Data->Profile.fBackColor = FALSE ;
  1573.     PrfWriteProfileData ( Data->ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"BackgroundColor", NULL, 0 ) ;
  1574.       }
  1575.       WinInvalidateRect ( hwnd, NULL, TRUE ) ;
  1576.       break ;
  1577.     }
  1578.  
  1579.    /*************************************************************************
  1580.     * If foreground color, note the fact and repaint the window.        *
  1581.     *************************************************************************/
  1582.  
  1583.     case PP_FOREGROUNDCOLOR:
  1584.     {
  1585.       ULONG ppid ;
  1586.       if ( WinQueryPresParam ( hwnd, PP_FOREGROUNDCOLOR, 0, &ppid,
  1587.     sizeof(Data->Profile.TextColor), &Data->Profile.TextColor, 0 ) )
  1588.       {
  1589.     Data->Profile.fTextColor = TRUE ;
  1590.       }
  1591.       else
  1592.       {
  1593.     Data->Profile.TextColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_OUTPUTTEXT, 0L ) ;
  1594.     Data->Profile.fTextColor = FALSE ;
  1595.     PrfWriteProfileData ( Data->ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"ForegroundColor", NULL, 0 ) ;
  1596.       }
  1597.       WinInvalidateRect ( hwnd, NULL, TRUE ) ;
  1598.       break ;
  1599.     }
  1600.   }
  1601.  
  1602.  /***************************************************************************
  1603.   * Return through the default processor, letting window activation        *
  1604.   *   and other system functions occur.                     *
  1605.   ***************************************************************************/
  1606.  
  1607.   return ( WinDefWindowProc ( hwnd, msg, mp1, mp2 ) ) ;
  1608. }
  1609.  
  1610. /****************************************************************************
  1611.  *                                        *
  1612.  *    Process System Color Change notification.                *
  1613.  *                                        *
  1614.  ****************************************************************************/
  1615.  
  1616. STATIC MRESULT APIENTRY SysColorChange
  1617. (
  1618.   HWND hwnd,
  1619.   USHORT msg,
  1620.   MPARAM mp1,
  1621.   MPARAM mp2
  1622. )
  1623. {
  1624.  /***************************************************************************
  1625.   * Find the instance data.                            *
  1626.   ***************************************************************************/
  1627.  
  1628.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1629.  
  1630.  /***************************************************************************
  1631.   * If we aren't using custom colors, then query for the new defaults.      *
  1632.   ***************************************************************************/
  1633.  
  1634.   if ( NOT Data->Profile.fBackColor )
  1635.   {
  1636.     Data->Profile.BackColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_WINDOW, 0L ) ;
  1637.   }
  1638.  
  1639.   if ( NOT Data->Profile.fTextColor )
  1640.   {
  1641.     Data->Profile.TextColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_OUTPUTTEXT, 0L ) ;
  1642.   }
  1643.  
  1644.  /***************************************************************************
  1645.   * Return value must be NULL, according to the documentation.            *
  1646.   ***************************************************************************/
  1647.  
  1648.   return ( MRFROMP ( NULL ) ) ;
  1649. }
  1650.  
  1651. /****************************************************************************
  1652.  *                                        *
  1653.  *    Process Query for Keys Help resource id.                *
  1654.  *                                        *
  1655.  ****************************************************************************/
  1656.  
  1657. STATIC MRESULT APIENTRY QueryKeysHelp
  1658. (
  1659.   HWND hwnd,
  1660.   USHORT msg,
  1661.   MPARAM mp1,
  1662.   MPARAM mp2
  1663. )
  1664. {
  1665.  /***************************************************************************
  1666.   * Simply return the ID of the Keys Help panel.                *
  1667.   ***************************************************************************/
  1668.  
  1669.   return ( (MRESULT) IDM_KEYS_HELP ) ;
  1670. }
  1671.  
  1672. /****************************************************************************
  1673.  *                                        *
  1674.  *    Process Help Manager Error                        *
  1675.  *                                        *
  1676.  ****************************************************************************/
  1677.  
  1678. STATIC MRESULT APIENTRY HelpError
  1679.   HWND hwnd, 
  1680.   USHORT msg, 
  1681.   MPARAM mp1, 
  1682.   MPARAM mp2
  1683. )
  1684. {
  1685.  /***************************************************************************
  1686.   * Local Declarations                                *
  1687.   ***************************************************************************/
  1688.  
  1689.   static struct
  1690.   {
  1691.     ULONG Error ;
  1692.     USHORT StringId ;
  1693.   }
  1694.   HelpErrors [] =
  1695.   {
  1696.     { HMERR_NO_FRAME_WND_IN_CHAIN,     IDS_HMERR_NO_FRAME_WND_IN_CHAIN },
  1697.     { HMERR_INVALID_ASSOC_APP_WND,     IDS_HMERR_INVALID_ASSOC_APP_WND },
  1698.     { HMERR_INVALID_ASSOC_HELP_INST,   IDS_HMERR_INVALID_ASSOC_HELP_IN },
  1699.     { HMERR_INVALID_DESTROY_HELP_INST, IDS_HMERR_INVALID_DESTROY_HELP_ },
  1700.     { HMERR_NO_HELP_INST_IN_CHAIN,     IDS_HMERR_NO_HELP_INST_IN_CHAIN },
  1701.     { HMERR_INVALID_HELP_INSTANCE_HDL, IDS_HMERR_INVALID_HELP_INSTANCE },
  1702.     { HMERR_INVALID_QUERY_APP_WND,     IDS_HMERR_INVALID_QUERY_APP_WND },
  1703.     { HMERR_HELP_INST_CALLED_INVALID,  IDS_HMERR_HELP_INST_CALLED_INVA },
  1704.     { HMERR_HELPTABLE_UNDEFINE,        IDS_HMERR_HELPTABLE_UNDEFINE    },
  1705.     { HMERR_HELP_INSTANCE_UNDEFINE,    IDS_HMERR_HELP_INSTANCE_UNDEFIN },
  1706.     { HMERR_HELPITEM_NOT_FOUND,        IDS_HMERR_HELPITEM_NOT_FOUND    },
  1707.     { HMERR_INVALID_HELPSUBITEM_SIZE,  IDS_HMERR_INVALID_HELPSUBITEM_S },
  1708.     { HMERR_HELPSUBITEM_NOT_FOUND,     IDS_HMERR_HELPSUBITEM_NOT_FOUND },
  1709.     { HMERR_INDEX_NOT_FOUND,           IDS_HMERR_INDEX_NOT_FOUND       },
  1710.     { HMERR_CONTENT_NOT_FOUND,           IDS_HMERR_CONTENT_NOT_FOUND     },
  1711.     { HMERR_OPEN_LIB_FILE,           IDS_HMERR_OPEN_LIB_FILE           },
  1712.     { HMERR_READ_LIB_FILE,           IDS_HMERR_READ_LIB_FILE           },
  1713.     { HMERR_CLOSE_LIB_FILE,           IDS_HMERR_CLOSE_LIB_FILE        },
  1714.     { HMERR_INVALID_LIB_FILE,           IDS_HMERR_INVALID_LIB_FILE      },
  1715.     { HMERR_NO_MEMORY,               IDS_HMERR_NO_MEMORY           },
  1716.     { HMERR_ALLOCATE_SEGMENT,           IDS_HMERR_ALLOCATE_SEGMENT      },
  1717.     { HMERR_FREE_MEMORY,           IDS_HMERR_FREE_MEMORY           },
  1718.     { HMERR_PANEL_NOT_FOUND,           IDS_HMERR_PANEL_NOT_FOUND       },
  1719.     { HMERR_DATABASE_NOT_OPEN,           IDS_HMERR_DATABASE_NOT_OPEN     },
  1720.     { 0,                   IDS_HMERR_UNKNOWN           }
  1721.   } ;
  1722.  
  1723.   ULONG ErrorCode = (ULONG) LONGFROMMP ( mp1 ) ;
  1724.  
  1725.  /***************************************************************************
  1726.   * Find the instance data.                            *
  1727.   ***************************************************************************/
  1728.  
  1729.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1730.  
  1731.  /***************************************************************************
  1732.   * Find the error code in the message table.                    *
  1733.   ***************************************************************************/
  1734.  
  1735.   int Index = 0 ;
  1736.   while ( HelpErrors[Index].Error
  1737.     AND ( HelpErrors[Index].Error != ErrorCode ) )
  1738.   {
  1739.     Index ++ ;
  1740.   }
  1741.  
  1742.  /***************************************************************************
  1743.   * Get the message texts.                            *
  1744.   ***************************************************************************/
  1745.  
  1746.   ResourceString Title ( Data->Library, IDS_HMERR ) ;
  1747.  
  1748.   ResourceString Message ( Data->Library, HelpErrors[Index].StringId ) ;
  1749.  
  1750.  /***************************************************************************
  1751.   * Display the error message.                            *
  1752.   ***************************************************************************/
  1753.  
  1754.   WinMessageBox
  1755.   (
  1756.     HWND_DESKTOP,
  1757.     hwnd,
  1758.     Message.Ptr(),
  1759.     Title.Ptr(),
  1760.     0,
  1761.     MB_OK | MB_WARNING
  1762.   ) ;
  1763.  
  1764.  /***************************************************************************
  1765.   * Return zero, indicating that the message was processed.            *
  1766.   ***************************************************************************/
  1767.  
  1768.   return ( MRFROMSHORT ( 0 ) ) ;
  1769. }
  1770.  
  1771. /****************************************************************************
  1772.  *                                        *
  1773.  *    Process "Extended Help Undefined" notification                *
  1774.  *                                        *
  1775.  ****************************************************************************/
  1776.  
  1777. STATIC MRESULT APIENTRY ExtHelpUndefined
  1778.   HWND hwnd, 
  1779.   USHORT msg, 
  1780.   MPARAM mp1, 
  1781.   MPARAM mp2
  1782. )
  1783. {
  1784.  /***************************************************************************
  1785.   * Find the instance data.                            *
  1786.   ***************************************************************************/
  1787.  
  1788.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1789.  
  1790.  /***************************************************************************
  1791.   * Get the message texts.                            *
  1792.   ***************************************************************************/
  1793.  
  1794.   ResourceString Title ( Data->Library, IDS_HMERR ) ;
  1795.  
  1796.   ResourceString Message ( Data->Library, IDS_HMERR_EXTHELPUNDEFINED ) ;
  1797.  
  1798.  /***************************************************************************
  1799.   * Display the error message.                            *
  1800.   ***************************************************************************/
  1801.  
  1802.   WinMessageBox
  1803.   (
  1804.     HWND_DESKTOP,
  1805.     hwnd,
  1806.     Message.Ptr(),
  1807.     Title.Ptr(),
  1808.     0,
  1809.     MB_OK | MB_WARNING
  1810.   ) ;
  1811.  
  1812.  /***************************************************************************
  1813.   * Return zero, indicating that the message was processed.            *
  1814.   ***************************************************************************/
  1815.  
  1816.   return ( MRFROMSHORT ( 0 ) ) ;
  1817. }
  1818.  
  1819. /****************************************************************************
  1820.  *                                        *
  1821.  *    Process "Help Subitem Not Found" notification                *
  1822.  *                                        *
  1823.  ****************************************************************************/
  1824.  
  1825. STATIC MRESULT APIENTRY HelpSubitemNotFound
  1826.   HWND hwnd, 
  1827.   USHORT msg, 
  1828.   MPARAM mp1, 
  1829.   MPARAM mp2
  1830. )
  1831. {
  1832.  /***************************************************************************
  1833.   * Find the instance data.                            *
  1834.   ***************************************************************************/
  1835.  
  1836.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1837.  
  1838.  /***************************************************************************
  1839.   * Get the title text.                             *
  1840.   ***************************************************************************/
  1841.  
  1842.   ResourceString Title ( Data->Library, IDS_HMERR ) ;
  1843.  
  1844.  /***************************************************************************
  1845.   * Format the error message.                            *
  1846.   ***************************************************************************/
  1847.  
  1848.   USHORT Topic = (USHORT) SHORT1FROMMP ( mp2 ) ;
  1849.   USHORT Subtopic = (USHORT) SHORT2FROMMP ( mp2 ) ;
  1850.  
  1851.   ResourceString Frame     ( Data->Library, IDS_HELPMODE_FRAME ) ;
  1852.   ResourceString Menu     ( Data->Library, IDS_HELPMODE_MENU ) ;
  1853.   ResourceString Window  ( Data->Library, IDS_HELPMODE_WINDOW ) ;
  1854.   ResourceString Unknown ( Data->Library, IDS_HELPMODE_UNKNOWN ) ;
  1855.  
  1856.   PBYTE Mode ;
  1857.   switch ( SHORT1FROMMP ( mp1 ) )
  1858.   {
  1859.     case HLPM_FRAME:
  1860.       Mode = Frame.Ptr() ;
  1861.       break ;
  1862.  
  1863.     case HLPM_MENU:
  1864.       Mode = Menu.Ptr() ;
  1865.       break ;
  1866.  
  1867.     case HLPM_WINDOW:
  1868.       Mode = Window.Ptr() ;
  1869.       break ;
  1870.  
  1871.     default:
  1872.       Mode = Unknown.Ptr() ;
  1873.   }
  1874.  
  1875.   ResourceString Format ( Data->Library, IDS_HELPSUBITEMNOTFOUND ) ;
  1876.  
  1877.   BYTE Message [200] ;
  1878.   sprintf ( (PCHAR)Message, PCHAR(Format.Ptr()), Mode, Topic, Subtopic ) ;
  1879.  
  1880.  /***************************************************************************
  1881.   * Display the error message.                            *
  1882.   ***************************************************************************/
  1883.  
  1884.   WinMessageBox
  1885.   (
  1886.     HWND_DESKTOP,
  1887.     hwnd,
  1888.     Message,
  1889.     Title.Ptr(),
  1890.     0,
  1891.     MB_OK | MB_WARNING
  1892.   ) ;
  1893.  
  1894.  /***************************************************************************
  1895.   * Return zero, indicating that the message was processed.            *
  1896.   ***************************************************************************/
  1897.  
  1898.   return ( MRFROMSHORT ( 0 ) ) ;
  1899. }
  1900.  
  1901. /****************************************************************************
  1902.  *                                        *
  1903.  *    Process Refresh message.                        *
  1904.  *                                        *
  1905.  ****************************************************************************/
  1906.  
  1907. STATIC MRESULT APIENTRY Refresh
  1908.   HWND hwnd, 
  1909.   USHORT msg, 
  1910.   MPARAM mp1, 
  1911.   MPARAM mp2
  1912. )
  1913. {
  1914.  /***************************************************************************
  1915.   * Find the instance data.                            *
  1916.   ***************************************************************************/
  1917.  
  1918.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1919.  
  1920.  /***************************************************************************
  1921.   * If we're supposed to float the window, do so here.                      *
  1922.   ***************************************************************************/
  1923.  
  1924.   if ( Data->Profile.Float )
  1925.     WinSetWindowPos ( WinQueryWindow(hwnd,QW_PARENT), HWND_TOP, 0, 0, 0, 0, SWP_ZORDER ) ;
  1926.  
  1927.  /***************************************************************************
  1928.   * Save the idle counter.                            *
  1929.   ***************************************************************************/
  1930.  
  1931.   Data->Profile.IdleCount = LONGFROMMP ( mp1 ) ;
  1932.  
  1933.  /***************************************************************************
  1934.   * Determine if drive mask has changed.                    *
  1935.   ***************************************************************************/
  1936.  
  1937.   ULONG Drive ;
  1938.   ULONG Drives ;
  1939.   DosQueryCurrentDisk ( &Drive, &Drives ) ;
  1940.  
  1941.   if ( Drives != Data->Drives )
  1942.   {
  1943.    /*************************************************************************
  1944.     * It has.  First save the display options.                    *
  1945.     *************************************************************************/
  1946.  
  1947.     SaveApplication ( hwnd, WM_SAVEAPPLICATION, 0, 0 ) ;
  1948.  
  1949.    /*************************************************************************
  1950.     * Next, update the drive item list.                     *
  1951.     *************************************************************************/
  1952.  
  1953.     UpdateDriveList ( Data->Anchor, Data->Library, Data->ProfileHandle, 
  1954.       &Data->Profile, Data->Drives, Drives ) ;
  1955.  
  1956.    /*************************************************************************
  1957.     * If the controls are hidden, hide the whole window and reveal the        *
  1958.     *    controls.  Otherwise the menu wouldn't get updated correctly.       *
  1959.     *************************************************************************/
  1960.  
  1961.     if ( Data->Profile.HideControls )
  1962.     {
  1963.       WinShowWindow ( WinQueryWindow(hwnd,QW_PARENT), FALSE ) ;
  1964.       HideControls
  1965.       (
  1966.     FALSE,
  1967.     WinQueryWindow ( hwnd, QW_PARENT ),
  1968.     Data->hwndSysMenu,
  1969.     Data->hwndTitleBar,
  1970.     Data->hwndMinMax
  1971.       ) ;
  1972.     }
  1973.  
  1974.    /*************************************************************************
  1975.     * If the controls were supposed to be hidden, hide them once more and   *
  1976.     *    show the window to the world again.                    *
  1977.     *************************************************************************/
  1978.  
  1979.     if ( Data->Profile.HideControls )
  1980.     {
  1981.       HideControls
  1982.       (
  1983.     TRUE,
  1984.     WinQueryWindow ( hwnd, QW_PARENT ),
  1985.     Data->hwndSysMenu,
  1986.     Data->hwndTitleBar,
  1987.     Data->hwndMinMax
  1988.       ) ;
  1989.       WinShowWindow ( WinQueryWindow(hwnd,QW_PARENT), TRUE ) ;
  1990.     }
  1991.  
  1992.    /*************************************************************************
  1993.     * Save the updated drive mask.                        *
  1994.     *************************************************************************/
  1995.  
  1996.     Data->Drives = Drives ;
  1997.  
  1998.    /*************************************************************************
  1999.     * Resize the window to accommodate the new option list.            *
  2000.     *************************************************************************/
  2001.  
  2002.     ResizeWindow ( hwnd, &Data->Profile ) ;
  2003.   }
  2004.  
  2005.  /***************************************************************************
  2006.   * Update the statistics.                            *
  2007.   ***************************************************************************/
  2008.  
  2009.   UpdateWindow ( hwnd, Data, FALSE ) ;
  2010.  
  2011.  /***************************************************************************
  2012.   * Return zero, indicating that the message was processed.            *
  2013.   ***************************************************************************/
  2014.  
  2015.   return ( MRFROMSHORT ( 0 ) ) ;
  2016. }
  2017.  
  2018.  
  2019. /****************************************************************************
  2020.  *                                        *
  2021.  *                 Get Profile Data                    *
  2022.  *                                        *
  2023.  ****************************************************************************/
  2024.  
  2025. STATIC int GetProfile ( HAB Anchor, HMODULE Library, HINI ProfileHandle, PPROFILE Profile )
  2026. {
  2027.  /***************************************************************************
  2028.   * Get the window's current size and position.                             *
  2029.   ***************************************************************************/
  2030.  
  2031.   #pragma pack(2)
  2032.   typedef struct {
  2033.     USHORT Filler ;
  2034.     USHORT fs ;
  2035.     USHORT cy, cx, y, x ;
  2036.     HWND hwndInsertBehind ;
  2037.     HWND hwnd ;
  2038.   } OLDSWP ;
  2039.   #pragma pack()
  2040.  
  2041.   ULONG Size ;
  2042.   memset ( &Profile->Position, 0, sizeof(Profile->Position) ) ;
  2043.   Profile->fPosition = FALSE ;
  2044.   if ( PrfQueryProfileSize ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"Position", &Size ) )
  2045.   {
  2046.     if ( Size == sizeof(OLDSWP)-sizeof(USHORT) )
  2047.     {
  2048.       OLDSWP OldPosition ;
  2049.       if ( PrfQueryProfileData ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"Position", &OldPosition.fs, &Size ) )
  2050.       {
  2051.         Profile->Position.fl = OldPosition.fs ;
  2052.         Profile->Position.cy = OldPosition.cy ;
  2053.         Profile->Position.cx = OldPosition.cx ;
  2054.         Profile->Position.y = OldPosition.y ;
  2055.         Profile->Position.x = OldPosition.x ;
  2056.         Profile->Position.hwndInsertBehind = OldPosition.hwndInsertBehind ;
  2057.         Profile->Position.hwnd = OldPosition.hwnd ;
  2058.         Profile->fPosition = TRUE ;
  2059.       }
  2060.     }
  2061.     else if ( Size == sizeof(Profile->Position) )
  2062.     {
  2063.       if ( PrfQueryProfileData ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"Position", &Profile->Position, &Size ) )
  2064.       {
  2065.         Profile->fPosition = TRUE ;
  2066.       }
  2067.     }
  2068.   }
  2069.  
  2070.   if ( NOT Profile->fPosition )
  2071.   {
  2072.     if ( ProfileHandle == HINI_USERPROFILE )
  2073.     {
  2074.       return ( 1 ) ;
  2075.     }
  2076.   }
  2077.  
  2078.  /***************************************************************************
  2079.   * Get the program options.                            *
  2080.   ***************************************************************************/
  2081.  
  2082.   Profile->HideControls = FALSE ;
  2083.   Profile->fHideControls = FALSE ;
  2084.   if 
  2085.   ( 
  2086.     PrfQueryProfileSize ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"HideControls", &Size )
  2087.     AND
  2088.     ( ( Size == sizeof(Profile->HideControls) ) OR ( Size == sizeof(short) ) )
  2089.     AND
  2090.     PrfQueryProfileData ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"HideControls", &Profile->HideControls, &Size )
  2091.   )
  2092.   {
  2093.     Profile->fHideControls = TRUE ;
  2094.   }
  2095.  
  2096.   Profile->Float = FALSE ;
  2097.   Profile->fFloat = FALSE ;
  2098.   if 
  2099.   ( 
  2100.     PrfQueryProfileSize ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"Float", &Size )
  2101.     AND
  2102.     ( ( Size == sizeof(Profile->Float) ) OR ( Size == sizeof(short) ) )
  2103.     AND
  2104.     PrfQueryProfileData ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"Float", &Profile->Float, &Size )
  2105.   )
  2106.   {
  2107.     Profile->fFloat = TRUE ;
  2108.   }
  2109.  
  2110.   Profile->TimerInterval = 1000 ;
  2111.   Profile->fTimerInterval = FALSE ;
  2112.   if 
  2113.   ( 
  2114.     PrfQueryProfileSize ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"TimerInterval", &Size )
  2115.     AND
  2116.     ( ( Size == sizeof(Profile->TimerInterval) ) OR ( Size == sizeof(short) ) )
  2117.     AND
  2118.     PrfQueryProfileData ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"TimerInterval", &Profile->TimerInterval, &Size ) 
  2119.   )
  2120.   {
  2121.     Profile->fTimerInterval = TRUE ;
  2122.   }
  2123.  
  2124.  /***************************************************************************
  2125.   * Get the presentation parameters.                        *
  2126.   ***************************************************************************/
  2127.  
  2128.   strcpy ( (PCHAR)Profile->FontNameSize, "" ) ;
  2129.   Profile->fFontNameSize = FALSE ;
  2130.   if
  2131.   (
  2132.     PrfQueryProfileSize ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"FontNameSize", &Size )
  2133.     AND
  2134.     ( Size == sizeof(Profile->FontNameSize) )
  2135.     AND
  2136.     PrfQueryProfileData ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"FontNameSize", &Profile->FontNameSize, &Size )
  2137.   )
  2138.   {
  2139.     Profile->fFontNameSize = TRUE ;
  2140.   }
  2141.  
  2142.   Profile->BackColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_WINDOW, 0L ) ;
  2143.   Profile->fBackColor = FALSE ;
  2144.   if
  2145.   (
  2146.     PrfQueryProfileSize ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"BackgroundColor", &Size )
  2147.     AND
  2148.     ( Size == sizeof(Profile->BackColor) )
  2149.     AND
  2150.     PrfQueryProfileData ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"BackgroundColor", &Profile->BackColor, &Size )
  2151.   )
  2152.   {
  2153.     Profile->fBackColor = TRUE ;
  2154.   }
  2155.  
  2156.   Profile->TextColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_OUTPUTTEXT, 0L ) ;
  2157.   Profile->fTextColor = FALSE ;
  2158.   if
  2159.   (
  2160.     PrfQueryProfileSize ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"ForegroundColor", &Size )
  2161.     AND
  2162.     ( Size == sizeof(Profile->TextColor) )
  2163.     AND
  2164.     PrfQueryProfileData ( ProfileHandle, (PSZ)PROGRAM_NAME, (PSZ)"ForegroundColor", &Profile->TextColor, &Size )
  2165.   )
  2166.   {
  2167.     Profile->fTextColor = TRUE ;
  2168.   }
  2169.  
  2170.  /***************************************************************************
  2171.   * Build the fixed portion of the item list.                    *
  2172.   ***************************************************************************/
  2173.  
  2174.   ResourceString ClockLabel ( Library, IDS_SHOW_CLOCK_LABEL ) ;
  2175.   ResourceString ClockOption ( Library, IDS_SHOW_CLOCK_OPTION ) ;
  2176.   Profile->Items[ITEM_CLOCK] = new Clock ( ITEM_CLOCK,
  2177.     PSZ("ShowClock"), ClockLabel.Ptr(), ClockOption.Ptr(),
  2178.     Profile->CountryInfo ) ;
  2179.  
  2180.   ResourceString ElapsedLabel ( Library, IDS_SHOW_ELAPSED_LABEL ) ;
  2181.   ResourceString ElapsedOption ( Library, IDS_SHOW_ELAPSED_OPTION ) ;
  2182.   Profile->Items[ITEM_ELAPSEDTIME] = new ElapsedTime ( ITEM_ELAPSEDTIME,
  2183.     PSZ("ShowElapsed"), ElapsedLabel.Ptr(), ElapsedOption.Ptr(),
  2184.     Profile->CountryInfo,
  2185.     Profile->Day,
  2186.     Profile->Days ) ;
  2187.  
  2188.   ResourceString SwapSizeLabel ( Library, IDS_SHOW_SWAPSIZE_LABEL ) ;
  2189.   ResourceString SwapSizeOption ( Library, IDS_SHOW_SWAPSIZE_OPTION ) ;
  2190.   Profile->Items[ITEM_SWAPFILESIZE] = new SwapSize ( ITEM_SWAPFILESIZE,
  2191.     PSZ("ShowSwapsize"), SwapSizeLabel.Ptr(), SwapSizeOption.Ptr(),
  2192.     Profile->CountryInfo,
  2193.     Profile->SwapPath ) ;
  2194.  
  2195.   ResourceString SwapFreeLabel ( Library, IDS_SHOW_SWAPFREE_LABEL ) ;
  2196.   ResourceString SwapFreeOption ( Library, IDS_SHOW_SWAPFREE_OPTION ) ;
  2197.   Profile->Items[ITEM_SWAPDISKFREE] = new SwapFree ( ITEM_SWAPDISKFREE,
  2198.     PSZ("ShowSwapfree"), SwapFreeLabel.Ptr(), SwapFreeOption.Ptr(),
  2199.     Profile->CountryInfo,
  2200.     Profile->SwapPath,
  2201.     Profile->MinFree ) ;
  2202.  
  2203.   ResourceString MemoryLabel ( Library, IDS_SHOW_MEMORY_LABEL ) ;
  2204.   ResourceString MemoryOption ( Library, IDS_SHOW_MEMORY_OPTION ) ;
  2205.   Profile->Items[ITEM_MEMORYFREE] = new MemoryFree ( ITEM_MEMORYFREE,
  2206.     PSZ("ShowMemory"), MemoryLabel.Ptr(), MemoryOption.Ptr(),
  2207.     Profile->CountryInfo,
  2208.     (SwapFree*)Profile->Items[ITEM_SWAPDISKFREE] ) ;
  2209.  
  2210.   ResourceString SpoolSizeLabel ( Library, IDS_SHOW_SPOOLSIZE_LABEL ) ;
  2211.   ResourceString SpoolSizeOption ( Library, IDS_SHOW_SPOOLSIZE_OPTION ) ;
  2212.   Profile->Items[ITEM_SPOOLFILESIZE] = new SpoolSize ( ITEM_SPOOLFILESIZE,
  2213.     PSZ("ShowSpoolSize"), SpoolSizeLabel.Ptr(), SpoolSizeOption.Ptr(),
  2214.     Profile->CountryInfo,
  2215.     Profile->SpoolPath ) ;
  2216.  
  2217.   ResourceString CpuLoadLabel ( Library, IDS_SHOW_CPULOAD_LABEL ) ;
  2218.   ResourceString CpuLoadOption ( Library, IDS_SHOW_CPULOAD_OPTION ) ;
  2219.   Profile->Items[ITEM_CPULOAD] = new CpuLoad ( ITEM_CPULOAD,
  2220.     PSZ("ShowCpuLoad"), CpuLoadLabel.Ptr(), CpuLoadOption.Ptr(),
  2221.     Profile->MaxCount,
  2222.     &Profile->IdleCount ) ;
  2223.  
  2224.   ResourceString TaskCountLabel ( Library, IDS_SHOW_TASKCOUNT_LABEL ) ;
  2225.   ResourceString TaskCountOption ( Library, IDS_SHOW_TASKCOUNT_OPTION ) ;
  2226.   Profile->Items[ITEM_TASKCOUNT] = new TaskCount ( ITEM_TASKCOUNT,
  2227.     PSZ("ShowTaskCount"), TaskCountLabel.Ptr(), TaskCountOption.Ptr(),
  2228.     Anchor ) ;
  2229.  
  2230.   for ( int i=0; i<ITEM_BASE_COUNT; i++ )
  2231.   {
  2232.     BOOL Flag = TRUE ;
  2233.     if 
  2234.     ( 
  2235.       PrfQueryProfileSize ( ProfileHandle, (PSZ)PROGRAM_NAME, Profile->Items[i]->QueryName(), &Size )
  2236.       AND
  2237.       ( ( Size == sizeof(Flag) ) OR ( Size == sizeof(short) ) )
  2238.       AND 
  2239.       PrfQueryProfileData ( ProfileHandle, (PSZ)PROGRAM_NAME, Profile->Items[i]->QueryName(), &Flag, &Size )
  2240.     )
  2241.     {
  2242.       ;
  2243.     }
  2244.  
  2245.     if ( Flag )
  2246.       Profile->Items[i]->SetFlag() ;
  2247.     else
  2248.       Profile->Items[i]->ResetFlag() ;
  2249.   }
  2250.  
  2251.  /***************************************************************************
  2252.   * Add items for each drive on the system.                    *
  2253.   ***************************************************************************/
  2254.  
  2255.   ULONG Drive, Drives ;
  2256.   DosQueryCurrentDisk ( &Drive, &Drives ) ;
  2257.   UpdateDriveList ( Anchor, Library, ProfileHandle, Profile, 0, Drives ) ;
  2258.  
  2259.   return ( 0 ) ;
  2260. }
  2261.  
  2262. /****************************************************************************
  2263.  *                                        *
  2264.  *                 Put Profile Data                    *
  2265.  *                                        *
  2266.  ****************************************************************************/
  2267.  
  2268. STATIC void PutProfile ( HINI ProfileHandle, PPROFILE Profile )
  2269. {
  2270.  /***************************************************************************
  2271.   * Save the window's current size and position.                            *
  2272.   ***************************************************************************/
  2273.  
  2274.   PrfWriteProfileData
  2275.   (
  2276.     ProfileHandle,
  2277.     (PSZ)PROGRAM_NAME,
  2278.     (PSZ)"Position",
  2279.     &Profile->Position,
  2280.     sizeof(Profile->Position)
  2281.   ) ;
  2282.  
  2283.  /***************************************************************************
  2284.   * Save the program options.                            *
  2285.   ***************************************************************************/
  2286.  
  2287.   if ( Profile->fHideControls )
  2288.   {
  2289.     PrfWriteProfileData
  2290.     (
  2291.       ProfileHandle,
  2292.       (PSZ)PROGRAM_NAME,
  2293.       (PSZ)"HideControls",
  2294.       &Profile->HideControls,
  2295.       sizeof(Profile->HideControls)
  2296.     ) ;
  2297.   }
  2298.  
  2299.   if ( Profile->fFloat )
  2300.   {
  2301.     PrfWriteProfileData
  2302.     (
  2303.       ProfileHandle,
  2304.       (PSZ)PROGRAM_NAME,
  2305.       (PSZ)"Float",
  2306.       &Profile->Float,
  2307.       sizeof(Profile->Float)
  2308.     ) ;
  2309.   }
  2310.  
  2311.   if ( Profile->fTimerInterval )
  2312.   {
  2313.     PrfWriteProfileData
  2314.     (
  2315.       ProfileHandle,
  2316.       (PSZ)PROGRAM_NAME,
  2317.       (PSZ)"TimerInterval",
  2318.       &Profile->TimerInterval,
  2319.       sizeof(Profile->TimerInterval)
  2320.     ) ;
  2321.   }
  2322.  
  2323.  /***************************************************************************
  2324.   * Save the item options.                            *
  2325.   ***************************************************************************/
  2326.  
  2327.   for ( int i=0; i<Profile->ItemCount; i++ )
  2328.   {
  2329.     Item *pItem = Profile->Items [i] ;
  2330.     BOOL Flag = pItem->QueryFlag() ;
  2331.  
  2332.     PrfWriteProfileData
  2333.     (
  2334.       ProfileHandle,
  2335.       PSZ(PROGRAM_NAME),
  2336.       pItem->QueryName(),
  2337.       &Flag,
  2338.       sizeof(Flag)
  2339.     ) ;
  2340.   }
  2341.  
  2342.  /***************************************************************************
  2343.   * Save the presentation parameters.                        *
  2344.   ***************************************************************************/
  2345.  
  2346.   if ( Profile->fFontNameSize )
  2347.   {
  2348.     PrfWriteProfileData
  2349.     (
  2350.       ProfileHandle,
  2351.       (PSZ)PROGRAM_NAME,
  2352.       (PSZ)"FontNameSize",
  2353.       Profile->FontNameSize,
  2354.       sizeof(Profile->FontNameSize)
  2355.     ) ;
  2356.   }
  2357.  
  2358.   if ( Profile->fBackColor )
  2359.   {
  2360.     PrfWriteProfileData
  2361.     (
  2362.       ProfileHandle,
  2363.       (PSZ)PROGRAM_NAME,
  2364.       (PSZ)"BackgroundColor",
  2365.       &Profile->BackColor,
  2366.       sizeof(Profile->BackColor)
  2367.     ) ;
  2368.   }
  2369.  
  2370.   if ( Profile->fTextColor )
  2371.   {
  2372.     PrfWriteProfileData
  2373.     (
  2374.       ProfileHandle,
  2375.       (PSZ)PROGRAM_NAME,
  2376.       (PSZ)"ForegroundColor",
  2377.       &Profile->TextColor,
  2378.       sizeof(Profile->TextColor)
  2379.     ) ;
  2380.   }
  2381. }
  2382.  
  2383. /****************************************************************************
  2384.  *                                        *
  2385.  *    Scan CONFIG.SYS for a keyword.    Return the value.            *
  2386.  *                                        *
  2387.  ****************************************************************************/
  2388.  
  2389. STATIC PSZ ScanSystemConfig ( HAB Anchor, PSZ Keyword )
  2390. {
  2391.  /***************************************************************************
  2392.   * Get the boot drive number from the global information segment.        *
  2393.   ***************************************************************************/
  2394.  
  2395.   ULONG BootDrive ;
  2396.   DosQuerySysInfo ( QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, &BootDrive, sizeof(BootDrive) ) ;
  2397.  
  2398.  /***************************************************************************
  2399.   * Convert the keyword to upper case.                                      *
  2400.   ***************************************************************************/
  2401.  
  2402.   WinUpper ( Anchor, NULL, NULL, Keyword ) ;
  2403.  
  2404.  /***************************************************************************
  2405.   * Build the CONFIG.SYS path.                            *
  2406.   ***************************************************************************/
  2407.  
  2408.   char Path [_MAX_PATH] ;
  2409.   Path[0] = (char) ( BootDrive + 'A' - 1 ) ;
  2410.   Path[1] = 0 ;
  2411.   strcat ( Path, ":\\CONFIG.SYS" ) ;
  2412.  
  2413.  /***************************************************************************
  2414.   * Open CONFIG.SYS for reading.                        *
  2415.   ***************************************************************************/
  2416.  
  2417.   FILE *File = fopen ( Path, "rt" ) ;
  2418.   if ( NOT File )
  2419.   {
  2420.     return ( NULL ) ;
  2421.   }
  2422.  
  2423.  /***************************************************************************
  2424.   * While there're more lines in CONFIG.SYS, read a line and check it.      *
  2425.   ***************************************************************************/
  2426.  
  2427.   static char Buffer [500] ;
  2428.   while ( fgets ( Buffer, sizeof(Buffer), File ) )
  2429.   {
  2430.  
  2431.    /*************************************************************************
  2432.     * Clean any trailing newline character from the input string.        *
  2433.     *************************************************************************/
  2434.  
  2435.     if ( Buffer[strlen(Buffer)-1] == '\n' )
  2436.     {
  2437.       Buffer[strlen(Buffer)-1] = 0 ;
  2438.     }
  2439.  
  2440.    /*************************************************************************
  2441.     * If keyword starts the line, we've found the line we want.  Close      *
  2442.     *    the file and return a pointer to the parameter text.            *
  2443.     *************************************************************************/
  2444.  
  2445.     WinUpper ( Anchor, NULL, NULL, (PSZ)Buffer ) ;
  2446.  
  2447.     if ( NOT strncmp ( Buffer, (PCHAR)Keyword, strlen((PCHAR)Keyword) )
  2448.       AND ( Buffer[strlen((PCHAR)Keyword)] == '=' ) )
  2449.     {
  2450.       fclose ( File ) ;
  2451.       return ( (PSZ) ( Buffer + strlen((PCHAR)Keyword) + 1 ) ) ;
  2452.     }
  2453.   }
  2454.  
  2455.  /***************************************************************************
  2456.   * Close the file.  We haven't found the line we wanted.                   *
  2457.   ***************************************************************************/
  2458.  
  2459.   fclose ( File ) ;
  2460.  
  2461.   return ( NULL ) ;
  2462. }
  2463.  
  2464. /****************************************************************************
  2465.  *                                        *
  2466.  *             Resize Client Window                    *
  2467.  *                                        *
  2468.  ****************************************************************************/
  2469.  
  2470. STATIC void ResizeWindow ( HWND hwnd, PPROFILE Profile )
  2471. {
  2472.  /***************************************************************************
  2473.   * If the window is visible and minimized, restore it invisibly.        *
  2474.   ***************************************************************************/
  2475.  
  2476.   HWND hwndFrame = WinQueryWindow ( hwnd, QW_PARENT ) ;
  2477.  
  2478.   SHORT fHadToHide = FALSE ;
  2479.   SHORT fHadToRestore = FALSE ;
  2480.   if ( Profile->Position.fl & SWP_MINIMIZE )
  2481.   {
  2482.     if ( WinIsWindowVisible ( hwndFrame ) )
  2483.     {
  2484.       WinShowWindow ( hwndFrame, FALSE ) ;
  2485.       fHadToHide = TRUE ;
  2486.     }
  2487.     WinSetWindowPos ( hwndFrame, NULL, 0, 0, 0, 0, SWP_RESTORE ) ;
  2488.     fHadToRestore = TRUE ;
  2489.   }
  2490.  
  2491.  /***************************************************************************
  2492.   * Determine how many items are to be displayed.                *
  2493.   ***************************************************************************/
  2494.  
  2495.   HPS hPS = WinGetPS ( hwnd ) ;
  2496.  
  2497.   int Count = 0 ;
  2498.   LONG Widest = 0 ;
  2499.   LONG Height = 0 ;
  2500.  
  2501.   for ( int i=0; i<Profile->ItemCount; i++ )
  2502.   {
  2503.     Item *pItem = Profile->Items [i] ;
  2504.  
  2505.     if ( pItem->QueryFlag() )
  2506.     {
  2507.       Count ++ ;
  2508.  
  2509.       BYTE Text [100] ;
  2510.       sprintf ( (PCHAR)Text, "%s 1,234,567K", pItem->QueryLabel() ) ;
  2511.  
  2512.       RECTL Rectangle ;
  2513.       WinQueryWindowRect ( HWND_DESKTOP, &Rectangle ) ;
  2514.  
  2515.       WinDrawText ( hPS, strlen((PCHAR)Text), Text,
  2516.     &Rectangle, 0L, 0L, DT_LEFT | DT_BOTTOM | DT_QUERYEXTENT ) ;
  2517.  
  2518.       Widest = max ( Widest, (Rectangle.xRight-Rectangle.xLeft+1) ) ;
  2519.  
  2520.       Height += Rectangle.yTop - Rectangle.yBottom ;
  2521.     }
  2522.   }
  2523.  
  2524.   WinReleasePS ( hPS ) ;
  2525.  
  2526.  /***************************************************************************
  2527.   * Get the window's current size & position.                               *
  2528.   ***************************************************************************/
  2529.  
  2530.   RECTL Rectangle ;
  2531.   WinQueryWindowRect ( hwndFrame, &Rectangle ) ;
  2532.  
  2533.   WinCalcFrameRect ( hwndFrame, &Rectangle, TRUE ) ;
  2534.  
  2535.  /***************************************************************************
  2536.   * Adjust the window's width & height.                                     *
  2537.   ***************************************************************************/
  2538.  
  2539.   Rectangle.xRight  = Rectangle.xLeft + Widest ;
  2540.  
  2541.   Rectangle.yTop    = Rectangle.yBottom + Height ;
  2542.  
  2543.  /***************************************************************************
  2544.   * Compute new frame size and apply it.                    *
  2545.   ***************************************************************************/
  2546.  
  2547.   WinCalcFrameRect ( hwndFrame, &Rectangle, FALSE ) ;
  2548.  
  2549.   WinSetWindowPos ( hwndFrame, NULL, 0, 0,
  2550.     (SHORT) (Rectangle.xRight-Rectangle.xLeft),
  2551.     (SHORT) (Rectangle.yTop-Rectangle.yBottom),
  2552.     SWP_SIZE ) ;
  2553.  
  2554.  /***************************************************************************
  2555.   * Return the window to its original state.                    *
  2556.   ***************************************************************************/
  2557.  
  2558.   if ( fHadToRestore )
  2559.   {
  2560.     WinSetWindowPos ( hwndFrame, NULL,
  2561.       Profile->Position.x, Profile->Position.y,
  2562.       Profile->Position.cx, Profile->Position.cy,
  2563.       SWP_MOVE | SWP_SIZE | SWP_MINIMIZE ) ;
  2564.   }
  2565.  
  2566.   if ( fHadToHide )
  2567.   {
  2568.     WinShowWindow ( hwndFrame, TRUE ) ;
  2569.   }
  2570.  
  2571.  /***************************************************************************
  2572.   * Invalidate the window so that it gets repainted.                *
  2573.   ***************************************************************************/
  2574.  
  2575.   WinInvalidateRect ( hwnd, NULL, TRUE ) ;
  2576. }
  2577.  
  2578. /****************************************************************************
  2579.  *                                        *
  2580.  *            Hide Window Controls                    *
  2581.  *                                        *
  2582.  ****************************************************************************/
  2583.  
  2584. STATIC void HideControls
  2585. (
  2586.   BOOL fHide,
  2587.   HWND hwndFrame,
  2588.   HWND hwndSysMenu,
  2589.   HWND hwndTitleBar,
  2590.   HWND hwndMinMax
  2591. )
  2592. {
  2593.  /***************************************************************************
  2594.   * Get original window position and state.                    *
  2595.   ***************************************************************************/
  2596.  
  2597.   SWP OldPosition ;
  2598.   WinQueryWindowPos ( hwndFrame, &OldPosition ) ;
  2599.  
  2600.   BOOL WasVisible = WinIsWindowVisible ( hwndFrame ) ;
  2601.  
  2602.  /***************************************************************************
  2603.   * Restore and hide the window.                        *
  2604.   ***************************************************************************/
  2605.  
  2606.   WinSetWindowPos ( hwndFrame, NULL, 0, 0, 0, 0, SWP_RESTORE | SWP_HIDE ) ;
  2607.  
  2608.  /***************************************************************************
  2609.   * Determine client window and location.                    *
  2610.   ***************************************************************************/
  2611.  
  2612.   SWP Position ;
  2613.   WinQueryWindowPos ( hwndFrame, &Position ) ;
  2614.  
  2615.   RECTL Rectangle ;
  2616.   Rectangle.xLeft   = Position.x ;
  2617.   Rectangle.xRight  = Position.x + Position.cx ;
  2618.   Rectangle.yBottom = Position.y ;
  2619.   Rectangle.yTop    = Position.y + Position.cy ;
  2620.  
  2621.   WinCalcFrameRect ( hwndFrame, &Rectangle, TRUE ) ;
  2622.  
  2623.  /***************************************************************************
  2624.   * Hide or reveal the controls windows by changing their parentage.        *
  2625.   ***************************************************************************/
  2626.  
  2627.   if ( fHide )
  2628.   {
  2629.     WinSetParent ( hwndSysMenu,  HWND_OBJECT, FALSE ) ;
  2630.     WinSetParent ( hwndTitleBar, HWND_OBJECT, FALSE ) ;
  2631.     WinSetParent ( hwndMinMax,     HWND_OBJECT, FALSE ) ;
  2632.   }
  2633.   else
  2634.   {
  2635.     WinSetParent ( hwndSysMenu,  hwndFrame, TRUE ) ;
  2636.     WinSetParent ( hwndTitleBar, hwndFrame, TRUE ) ;
  2637.     WinSetParent ( hwndMinMax,     hwndFrame, TRUE ) ;
  2638.   }
  2639.  
  2640.  /***************************************************************************
  2641.   * Tell the frame that things have changed.  Let it update the window.     *
  2642.   ***************************************************************************/
  2643.  
  2644.   WinSendMsg ( hwndFrame, WM_UPDATEFRAME,
  2645.     MPFROMSHORT ( FCF_TITLEBAR | FCF_SYSMENU | FCF_MINBUTTON ), 0L ) ;
  2646.  
  2647.  /***************************************************************************
  2648.   * Reposition the frame around the client window, which is left be.        *
  2649.   ***************************************************************************/
  2650.  
  2651.   WinCalcFrameRect ( hwndFrame, &Rectangle, FALSE ) ;
  2652.  
  2653.   WinSetWindowPos ( hwndFrame, NULL,
  2654.     (SHORT) Rectangle.xLeft,  (SHORT) Rectangle.yBottom,
  2655.     (SHORT) (Rectangle.xRight-Rectangle.xLeft),
  2656.     (SHORT) (Rectangle.yTop-Rectangle.yBottom),
  2657.     SWP_SIZE | SWP_MOVE ) ;
  2658.  
  2659.  /***************************************************************************
  2660.   * If window was maximized, put it back that way.                *
  2661.   ***************************************************************************/
  2662.  
  2663.   if ( OldPosition.fl & SWP_MAXIMIZE )
  2664.   {
  2665.     WinSetWindowPos ( hwndFrame, NULL,
  2666.       (SHORT) Rectangle.xLeft,    (SHORT) Rectangle.yBottom,
  2667.       (SHORT) (Rectangle.xRight-Rectangle.xLeft),
  2668.       (SHORT) (Rectangle.yTop-Rectangle.yBottom),
  2669.       SWP_SIZE | SWP_MOVE |
  2670.       ( OldPosition.fl & SWP_MAXIMIZE ) ) ;
  2671.   }
  2672.  
  2673.  /***************************************************************************
  2674.   * If the window was visible in the first place, show it.            *
  2675.   ***************************************************************************/
  2676.  
  2677.   if ( WasVisible )
  2678.   {
  2679.     WinShowWindow ( hwndFrame, TRUE ) ;
  2680.   }
  2681. }
  2682.  
  2683. /****************************************************************************
  2684.  *                                        *
  2685.  *    Update Window                                *
  2686.  *                                        *
  2687.  ****************************************************************************/
  2688.  
  2689. STATIC void UpdateWindow ( HWND hwnd, PDATA Data, BOOL All )
  2690. {
  2691.  /***************************************************************************
  2692.   * Determine how many items are to be displayed.                *
  2693.   ***************************************************************************/
  2694.  
  2695.   int Count = 0 ;
  2696.   for ( int i=0; i<Data->Profile.ItemCount; i++ )
  2697.   {
  2698.     if ( Data->Profile.Items[i]->QueryFlag() )
  2699.     {
  2700.       Count ++ ;
  2701.     }
  2702.   }
  2703.  
  2704.  /***************************************************************************
  2705.   * Get presentation space and make it use RGB colors.                *
  2706.   ***************************************************************************/
  2707.  
  2708.   HPS hPS = WinGetPS ( hwnd ) ;
  2709.   GpiCreateLogColorTable ( hPS, LCOL_RESET, LCOLF_RGB, 0L, 0L, NULL ) ;
  2710.  
  2711.  /***************************************************************************
  2712.   * Get the window's size and determine the initial position.               *
  2713.   ***************************************************************************/
  2714.  
  2715.   RECTL Rectangle ;
  2716.   WinQueryWindowRect ( hwnd, &Rectangle ) ;
  2717.  
  2718.   Rectangle.xLeft += Data->Width / 2 ;
  2719.   Rectangle.xRight -= Data->Width / 2 ;
  2720.  
  2721.   Rectangle.yBottom = Data->Height * ( Count - 1 ) ;
  2722.   Rectangle.yTop = Rectangle.yBottom + Data->Height ;
  2723.  
  2724.  /***************************************************************************
  2725.   * Review all items.  Display those changed, or all.                *
  2726.   ***************************************************************************/
  2727.  
  2728.   for ( i=0; i<Data->Profile.ItemCount; i++ )
  2729.   {
  2730.     ULONG NewValue ;
  2731.  
  2732.     Item *pItem = Data->Profile.Items [i] ;
  2733.  
  2734.     if ( pItem->QueryFlag() )
  2735.     {
  2736.       pItem->Repaint ( hPS, Rectangle,
  2737.     Data->Profile.TextColor, Data->Profile.BackColor, All ) ;
  2738.  
  2739.       Rectangle.yBottom -= Data->Height ;
  2740.       Rectangle.yTop    -= Data->Height ;
  2741.     }
  2742.   }
  2743.  
  2744.  /***************************************************************************
  2745.   * Release the presentation space and return.                    *
  2746.   ***************************************************************************/
  2747.  
  2748.   WinReleasePS ( hPS ) ;
  2749. }
  2750.  
  2751.  
  2752. /****************************************************************************
  2753.  *                                        *
  2754.  *    Monitor Loop Thread                            *
  2755.  *                                        *
  2756.  ****************************************************************************/
  2757.  
  2758. STATIC VOID MonitorLoopThread ( PMONITOR_PARMS Parms )
  2759. {
  2760.  /***************************************************************************
  2761.   * Set this thread's priority as high as it can go.                        *
  2762.   ***************************************************************************/
  2763.  
  2764.   DosSetPrty ( PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, 0 ) ;
  2765.  
  2766.  /***************************************************************************
  2767.   * Start up the high resolution timer, if it is available.            *
  2768.   ***************************************************************************/
  2769.  
  2770.   BOOL HiResTimer = OpenTimer ( ) ;
  2771.  
  2772.  /***************************************************************************
  2773.   * Loop forever . . .                                *
  2774.   ***************************************************************************/
  2775.  
  2776.   while ( 1 )
  2777.   {
  2778.  
  2779.    /*************************************************************************
  2780.     * Reset the last time and count seen.                    *
  2781.     *************************************************************************/
  2782.  
  2783.     ULONG LastMilliseconds ;
  2784.     TIMESTAMP Time [2] ;
  2785.  
  2786.     if ( HiResTimer )
  2787.       GetTime ( &Time[0] ) ;
  2788.     else
  2789.       DosQuerySysInfo ( QSV_MS_COUNT, QSV_MS_COUNT, &LastMilliseconds, sizeof(LastMilliseconds) ) ;
  2790.  
  2791.     ULONG LastCounter = *Parms->Counter ;
  2792.  
  2793.    /*************************************************************************
  2794.     * Sleep for a bit.                                *
  2795.     *************************************************************************/
  2796.  
  2797.     DosSleep ( *Parms->Interval ) ;
  2798.  
  2799.    /*************************************************************************
  2800.     * Find out how much time and counts went by.                *
  2801.     *************************************************************************/
  2802.  
  2803.     ULONG CurrentCounter = *Parms->Counter ;
  2804.  
  2805.     ULONG DeltaMilliseconds ;
  2806.  
  2807.     if ( HiResTimer )
  2808.     {
  2809.       GetTime ( &Time[1] ) ;
  2810.  
  2811.       ULONG Nanoseconds ;
  2812.       DeltaMilliseconds = ElapsedTime ( &Time[0], &Time[1], &Nanoseconds ) ;
  2813.  
  2814.       if ( Nanoseconds >= 500000L )
  2815.     DeltaMilliseconds ++ ;
  2816.     }
  2817.     else
  2818.     {
  2819.       ULONG Milliseconds ;
  2820.       DosQuerySysInfo ( QSV_MS_COUNT, QSV_MS_COUNT, &Milliseconds, sizeof(Milliseconds) ) ;
  2821.       DeltaMilliseconds = Milliseconds - LastMilliseconds ;
  2822.     }
  2823.  
  2824.    /*************************************************************************
  2825.     * Find out how much idle time was counted.    Adjust it to persecond.     *
  2826.     *************************************************************************/
  2827.  
  2828.     ULONG Counter = (ULONG) ( ( (double)(CurrentCounter-LastCounter) * 1000L ) / (double)DeltaMilliseconds ) ;
  2829.  
  2830.    /*************************************************************************
  2831.     * Tell the owner window to refresh its statistics.                *
  2832.     *************************************************************************/
  2833.  
  2834.     WinPostMsg ( Parms->Owner, WM_REFRESH, MPFROMLONG(Counter), 0L ) ;
  2835.   }
  2836. }
  2837.  
  2838. /****************************************************************************
  2839.  *                                        *
  2840.  *    Update the Item List to reflect changes in the available drives.    *
  2841.  *                                        *
  2842.  ****************************************************************************/
  2843.  
  2844. STATIC VOID UpdateDriveList
  2845. (
  2846.   HAB Anchor,
  2847.   HMODULE Library,
  2848.   HINI ProfileHandle,
  2849.   PPROFILE Profile,
  2850.   ULONG OldDrives,
  2851.   ULONG NewDrives
  2852. )
  2853. {
  2854.  /***************************************************************************
  2855.   * Get format strings.                             *
  2856.   ***************************************************************************/
  2857.  
  2858.   ResourceString LabelFormat ( Library, IDS_SHOW_DRIVE_FREE_LABEL ) ;
  2859.   ResourceString OptionFormat ( Library, IDS_SHOW_DRIVE_FREE_OPTION ) ;
  2860.  
  2861.  /***************************************************************************
  2862.   * Save the old item list for comparison.                    *
  2863.   ***************************************************************************/
  2864.  
  2865.   Item *OldItems [ ITEM_BASE_COUNT + MAX_DRIVES ] ;
  2866.  
  2867.   memset ( OldItems, 0, sizeof(OldItems) ) ;
  2868.  
  2869.   USHORT OldCount = 0 ;
  2870.   if ( OldDrives )
  2871.   {
  2872.     OldCount = Profile->ItemCount ;
  2873.     memcpy ( OldItems, Profile->Items, sizeof(OldItems) ) ;
  2874.   }
  2875.  
  2876.  /***************************************************************************
  2877.   * Add items for each drive on the system.                    *
  2878.   ***************************************************************************/
  2879.  
  2880.   USHORT Count = ITEM_BASE_COUNT ;
  2881.   USHORT OldIndex = ITEM_BASE_COUNT ;
  2882.  
  2883.   NewDrives >>= 2 ;
  2884.   OldDrives >>= 2 ;
  2885.  
  2886.   for ( int Drive=3; Drive<=MAX_DRIVES; Drive++ )
  2887.   {
  2888.     while ( ( OldIndex < OldCount )
  2889.       AND ( (SHORT)OldItems[OldIndex]->QueryId() < ITEM_BASE_COUNT + Drive ) )
  2890.     {
  2891.       OldIndex ++ ;
  2892.     }
  2893.  
  2894.     if ( NewDrives & 1 )
  2895.     {
  2896.       if ( OldDrives & 1 )
  2897.       {
  2898.     if ( ( OldIndex < OldCount )
  2899.       AND ( (SHORT)OldItems[OldIndex]->QueryId() == ITEM_BASE_COUNT + Drive ) )
  2900.     {
  2901.       Profile->Items[Count++] = OldItems[OldIndex++] ;
  2902.     }
  2903.       }
  2904.       else
  2905.       {
  2906.         BYTE FileSystem [80] ;
  2907.     if ( CheckDrive ( Drive, FileSystem ) )
  2908.     {
  2909.       BYTE Name [80] ;
  2910.       sprintf ( PCHAR(Name),   "ShowDrive%c:", Drive+'A'-1 ) ;
  2911.  
  2912.       BYTE Label [80] ;
  2913.       sprintf ( PCHAR(Label),  (PCHAR)LabelFormat.Ptr(),  Drive+'A'-1, FileSystem ) ;
  2914.  
  2915.       BYTE Option [80] ;
  2916.       sprintf ( PCHAR(Option), (PCHAR)OptionFormat.Ptr(), Drive+'A'-1 ) ;
  2917.  
  2918.       Profile->Items[Count++] = new DriveFree ( ITEM_BASE_COUNT+Drive,
  2919.         Name, Label, Option, Profile->CountryInfo,
  2920.         Drive, Profile->DriveError ) ;
  2921.     }
  2922.       }
  2923.     }
  2924.     else
  2925.     {
  2926.       if ( OldDrives & 1 )
  2927.       {
  2928.     delete OldItems[OldIndex++] ;
  2929.       }
  2930.       else
  2931.       {
  2932.     // Do nothing.
  2933.       }
  2934.     }
  2935.  
  2936.     NewDrives >>= 1 ;
  2937.     OldDrives >>= 1 ;
  2938.   }
  2939.  
  2940.  /***************************************************************************
  2941.   * Save the new item count.                            *
  2942.   ***************************************************************************/
  2943.  
  2944.   Profile->ItemCount = Count ;
  2945.  
  2946.  /***************************************************************************
  2947.   * Fetch the display flags for the drives.                    *
  2948.   ***************************************************************************/
  2949.  
  2950.   for ( int i=ITEM_BASE_COUNT; i<Profile->ItemCount; i++ )
  2951.   {
  2952.     BOOL Flag = TRUE ;
  2953.     Item *pItem = Profile->Items [i] ;
  2954.     ULONG Size ;
  2955.  
  2956.     if
  2957.     (
  2958.       PrfQueryProfileSize ( ProfileHandle, (PSZ)PROGRAM_NAME, pItem->QueryName(), &Size )
  2959.       AND
  2960.       ( ( Size == sizeof(Flag) ) OR ( Size == sizeof(short) ) )
  2961.       AND
  2962.       PrfQueryProfileData ( ProfileHandle, (PSZ)PROGRAM_NAME, pItem->QueryName(), &Flag, &Size )
  2963.     )
  2964.     {
  2965.       ;
  2966.     }
  2967.  
  2968.     if ( Flag )
  2969.       pItem->SetFlag () ;
  2970.     else
  2971.       pItem->ResetFlag () ;
  2972.   }
  2973. }
  2974.  
  2975. /****************************************************************************
  2976.  *                                        *
  2977.  *    Check to see if drive should be added to display list.            *
  2978.  *                                        *
  2979.  ****************************************************************************/
  2980.  
  2981. STATIC BOOL CheckDrive ( USHORT Drive, PBYTE FileSystem )
  2982. {
  2983.  /***************************************************************************
  2984.   * First, check to see if drive is local or remote.  Remote drives are     *
  2985.   *   always monitored.                             *
  2986.   ***************************************************************************/
  2987.  
  2988.   BYTE Path [3] ;
  2989.   Path[0] = (BYTE) ( Drive + 'A' - 1 ) ;
  2990.   Path[1] = ':' ;
  2991.   Path[2] = 0 ;
  2992.  
  2993.   DosError ( FERR_DISABLEHARDERR ) ;
  2994.  
  2995.   BYTE Buffer [1024] ;
  2996.   ULONG Size = sizeof(Buffer) ;
  2997.   ULONG Status = DosQueryFSAttach ( Path, 0, FSAIL_QUERYNAME, (PFSQBUFFER2)Buffer, &Size ) ;
  2998.   DosError ( FERR_ENABLEHARDERR ) ;
  2999.  
  3000.   if ( Status )
  3001.   {
  3002.     Log ( "ERROR: Unable to query drive %s for file system.  Status %04X.\r\n",
  3003.       Path, Status ) ;
  3004.     return ( FALSE ) ;
  3005.   }
  3006.  
  3007.   USHORT cbName = ((PFSQBUFFER2)Buffer)->cbName ;
  3008.   strcpy ( (PCHAR)FileSystem, (PCHAR)((PFSQBUFFER2)(Buffer+cbName))->szFSDName ) ;
  3009.  
  3010.   if ( ((PFSQBUFFER2)Buffer)->iType == FSAT_REMOTEDRV )
  3011.   {
  3012.     return ( TRUE ) ;
  3013.   }
  3014.  
  3015.  /***************************************************************************
  3016.   * Attempt to open the local drive as an entire device.  If unable to do   *
  3017.   *   so, we cannot monitor this drive.                     *
  3018.   ***************************************************************************/
  3019.  
  3020.   ULONG Action ;
  3021.   HFILE Handle ;
  3022.   Status = DosOpen ( Path, &Handle, &Action, 0, 0, FILE_OPEN,
  3023.     OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE |
  3024.     OPEN_FLAGS_DASD | OPEN_FLAGS_FAIL_ON_ERROR, 0 ) ;
  3025.  
  3026.   if ( Status )
  3027.   {
  3028.     Log ( "ERROR: Unable to open local drive %s.  Status %04X.\r\n",
  3029.       Path, Status ) ;
  3030.     return ( FALSE ) ;
  3031.   }
  3032.  
  3033.  /***************************************************************************
  3034.   * Check to see if the drive has removable media.  We cannot monitor such. *
  3035.   ***************************************************************************/
  3036.  
  3037.   BOOL Addit = FALSE ;
  3038.   BYTE Command = 0 ;
  3039.   BYTE NonRemovable ;
  3040.  
  3041.   ULONG LengthIn = sizeof(Command) ;
  3042.   ULONG LengthOut = sizeof(NonRemovable);
  3043.  
  3044.   if 
  3045.   ( 
  3046.     NOT DosDevIOCtl 
  3047.     ( 
  3048.       Handle, 8, 0x20, 
  3049.       &Command, sizeof(Command), &LengthIn,
  3050.       &NonRemovable, sizeof(NonRemovable), &LengthOut 
  3051.     ) 
  3052.   )
  3053.   {
  3054.     Addit = NonRemovable ;
  3055.   }
  3056.  
  3057.  /***************************************************************************
  3058.   * Close the drive.                                *
  3059.   ***************************************************************************/
  3060.  
  3061.   DosClose ( Handle ) ;
  3062.  
  3063.  /***************************************************************************
  3064.   * Return the final verdict.                            *
  3065.   ***************************************************************************/
  3066.  
  3067.   return ( Addit ) ;
  3068. }
  3069.  
  3070. /****************************************************************************
  3071.  *                                        *
  3072.  *             Calibrate the Load Meter                *
  3073.  *                                        *
  3074.  ****************************************************************************/
  3075.  
  3076. STATIC ULONG CalibrateLoadMeter ( void )
  3077. {
  3078.  /***************************************************************************
  3079.   * Set result to zero as a default.                        *
  3080.   ***************************************************************************/
  3081.  
  3082.   double AdjustedMaxLoad = 0.0 ;
  3083.  
  3084.  /***************************************************************************
  3085.   * If HRTIMER.SYS has been installed . . .                    *
  3086.   ***************************************************************************/
  3087.  
  3088.   if ( OpenTimer ( ) )
  3089.   {
  3090.    /*************************************************************************
  3091.     * Increase this thread's priority to the maximum.                       *
  3092.     *************************************************************************/
  3093.  
  3094.     DosSetPrty ( PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, 0 ) ;
  3095.  
  3096.    /*************************************************************************
  3097.     * Create the calibration thread and set its priority next highest.        *
  3098.     *************************************************************************/
  3099.  
  3100.     TID tidCalibrate ;
  3101.     ULONG MaxLoad ;
  3102.     DosCreateThread ( &tidCalibrate, CounterThread, (ULONG)&MaxLoad, 0, 4096 ) ;
  3103.     DosSetPrty ( PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM-1, tidCalibrate ) ;
  3104.     DosSuspendThread ( tidCalibrate ) ;
  3105.  
  3106.    /*************************************************************************
  3107.     * Reset the calibration count, get the time, and let the counter go.    *
  3108.     *************************************************************************/
  3109.  
  3110.     MaxLoad = 0 ;
  3111.     TIMESTAMP Time[2] ;
  3112.     GetTime ( &Time[0] ) ;
  3113.     DosResumeThread ( tidCalibrate ) ;
  3114.  
  3115.    /*************************************************************************
  3116.     * Sleep for one second.                            *
  3117.     *************************************************************************/
  3118.  
  3119.     DosSleep ( 1000 ) ;
  3120.  
  3121.    /*************************************************************************
  3122.     * Suspend the calibration counter and get the time.             *
  3123.     *************************************************************************/
  3124.  
  3125.     DosSuspendThread ( tidCalibrate ) ;
  3126.     GetTime ( &Time[1] ) ;
  3127.  
  3128.    /*************************************************************************
  3129.     * Return priorities to normal.                        *
  3130.     *************************************************************************/
  3131.  
  3132.     DosSetPrty ( PRTYS_THREAD, PRTYC_REGULAR, 0, 0 ) ;
  3133.  
  3134.    /*************************************************************************
  3135.     * Get the elapsed time and adjust the calibration count.            *
  3136.     *************************************************************************/
  3137.  
  3138.     ULONG Milliseconds ;
  3139.     ULONG Nanoseconds ;
  3140.     Milliseconds = ElapsedTime ( &Time[0], &Time[1], &Nanoseconds ) ;
  3141.  
  3142.     AdjustedMaxLoad = (double)MaxLoad * 1.0E9 ;
  3143.     AdjustedMaxLoad /= (double)Milliseconds*1.0E6L + (double)Nanoseconds ;
  3144.  
  3145.    /*************************************************************************
  3146.     * Close down the connection to HRTIMER.SYS.                 *
  3147.     *************************************************************************/
  3148.  
  3149.     CloseTimer ( ) ;
  3150.   }
  3151.  
  3152.  /***************************************************************************
  3153.   * Return the adjusted calibration count.  If HRTIMER was not there, it    *
  3154.   *   will be zero.                                *
  3155.   ***************************************************************************/
  3156.  
  3157.   return ( (ULONG)AdjustedMaxLoad ) ;
  3158. }
  3159.  
  3160. /****************************************************************************
  3161.  *                                        *
  3162.  *              General Purpose Counter Thread                *
  3163.  *                                        *
  3164.  ****************************************************************************/
  3165.  
  3166. STATIC VOID CounterThread ( PULONG Counter )
  3167. {
  3168.   while ( 1 )
  3169.   {
  3170.     (*Counter) ++ ;
  3171.   }
  3172. }
  3173.  
  3174. /****************************************************************************
  3175.  *                                        *
  3176.  *    Open the Profile                            *
  3177.  *                                        *
  3178.  ****************************************************************************/
  3179.  
  3180. STATIC HINI OpenProfile ( PSZ Name, HAB Anchor, HMODULE Library, HWND HelpInstance )
  3181. {
  3182.  /***************************************************************************
  3183.   * Query the system INI for the profile file's path.                       *
  3184.   ***************************************************************************/
  3185.  
  3186.   PSZ ProfilePath = NULL ;
  3187.   ULONG Size ;
  3188.  
  3189.   if ( PrfQueryProfileSize ( HINI_USERPROFILE, PSZ(PROGRAM_NAME), PSZ("INIPATH"), &Size ) )
  3190.   {
  3191.     // The info exists.  Fetch it.
  3192.     ProfilePath = PSZ ( AllocateMemory ( Size ) ) ;
  3193.     PrfQueryProfileData ( HINI_USERPROFILE, PSZ(PROGRAM_NAME), PSZ("INIPATH"),
  3194.       ProfilePath, &Size ) ;
  3195.  
  3196.     // Build the profile file name.
  3197.     BYTE FullPath [_MAX_PATH] ;
  3198.     strcpy ( PCHAR(FullPath), PCHAR(ProfilePath) ) ;
  3199.     strcat ( PCHAR(FullPath), "\\" ) ;
  3200.     strcat ( PCHAR(FullPath), PCHAR(Name) ) ;
  3201.     strcat ( PCHAR(FullPath), ".INI" ) ;
  3202.  
  3203.     // Clean the name up and expand it to a full path.
  3204.     BYTE Path [256] ;
  3205.     DosQueryPathInfo ( FullPath, FIL_QUERYFULLNAME, Path, sizeof(Path) ) ;
  3206.  
  3207.     // Does the file exist?  If not, discard the name.
  3208.     FILESTATUS3 Status ;
  3209.     if ( DosQueryPathInfo ( Path, FIL_STANDARD, &Status, sizeof(Status) ) )
  3210.     {
  3211.       FreeMemory ( ProfilePath ) ;
  3212.       ProfilePath = NULL ;
  3213.     }
  3214.   }
  3215.  
  3216.  /***************************************************************************
  3217.   * If the profile file couldn't be found, ask the user for a path.         *
  3218.   ***************************************************************************/
  3219.  
  3220.   if ( ProfilePath == NULL )
  3221.   {
  3222.     // Set the default path.
  3223.     BYTE Path [256] ;
  3224.     DosQueryPathInfo ( PSZ("."), FIL_QUERYFULLNAME, Path, sizeof(Path) ) ;
  3225.  
  3226.     // Call up the entry dialog.
  3227.     PROFILE_PARMS Parms ;
  3228.     Parms.id = IDD_PROFILE_PATH ;
  3229.     Parms.hwndHelp = HelpInstance ;
  3230.     Parms.Path = Path ;
  3231.     Parms.PathSize = sizeof(Path) ;
  3232.     if ( WinDlgBox ( HWND_DESKTOP, HWND_DESKTOP, ProfileProcessor,
  3233.       Library, IDD_PROFILE_PATH, &Parms ) )
  3234.     {
  3235.       // If OK, save the approved path in the system profile.
  3236.       ProfilePath = PSZ ( AllocateMemory ( strlen(PCHAR(Path)) + 1 ) ) ;
  3237.       strcpy ( PCHAR(ProfilePath), PCHAR(Path) ) ;
  3238.  
  3239.       PrfWriteProfileData ( HINI_USERPROFILE, PSZ(PROGRAM_NAME), PSZ("INIPATH"),
  3240.     ProfilePath, strlen(PCHAR(ProfilePath))+1 ) ;
  3241.     }
  3242.     else
  3243.     {
  3244.       // If not, return an error.
  3245.       return ( NULL ) ;
  3246.     }
  3247.   }
  3248.  
  3249.  /***************************************************************************
  3250.   * Build the full profile file name.                        *
  3251.   ***************************************************************************/
  3252.  
  3253.   BYTE ProfileName [_MAX_PATH] ;
  3254.   strcpy ( PCHAR(ProfileName), PCHAR(ProfilePath) ) ;
  3255.   strcat ( PCHAR(ProfileName), "\\" PROGRAM_NAME ".INI" ) ;
  3256.  
  3257.  /***************************************************************************
  3258.   * Release the memory previously allocated to store the path.            *
  3259.   ***************************************************************************/
  3260.  
  3261.   if ( ProfilePath )
  3262.   {
  3263.     FreeMemory ( ProfilePath ) ;
  3264.   }
  3265.  
  3266.  /***************************************************************************
  3267.   * Open/Create the profile file and return the resultant handle.        *
  3268.   ***************************************************************************/
  3269.  
  3270.   return ( PrfOpenProfile ( Anchor, ProfileName ) ) ;
  3271. }
  3272. 
  3273.