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