home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / memsz331.zip / Source.zip / MEMSIZE.CPP < prev    next >
C/C++ Source or Header  |  1996-12-30  |  169KB  |  3,719 lines

  1. /**************************************************************** MEMSIZE.CPP
  2.  *                                                                          *
  3.  * System Resources Monitor                                                 *
  4.  *                                                                          *
  5.  * (C) Copyright 1991-1996 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.  * on Internet at rpapo@msen.com, and through my web home page:             *
  13.  *                                                                          *
  14.  *                      http://www.msen.com/~rpapo                          *
  15.  *                                                                          *
  16.  ****************************************************************************/
  17.  
  18. // Things to do:
  19. //
  20. //   (1) Add option for configuring the time/date field's justification (left/center/right).
  21. //
  22. //   (2) Revise ResetDefaults to reset -all- defaults, including monitor priority, anchor, etc.
  23. //
  24. //   (3) Add option for year in date.
  25. //
  26. //   (4) Add displayable item for Average CPU Load.  Add menu item to reset it.
  27. //
  28. //   (5) Bring the date-format support from Escriba over here.
  29. //
  30. //   (6) Incorporate new window class and make all this multiplatform.
  31. //
  32.  
  33. #define INCL_BASE
  34. #define INCL_DOSDEVIOCTL
  35. #define INCL_PM
  36. #include <os2.h>
  37.  
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <string.h>
  41. #include <time.h>
  42.  
  43. #include "Dde.h"
  44. #include "Debug.h"
  45. #include "DQPS.h"
  46. #include "Event.h"
  47. #include "Except.h"
  48. #include "HelpWin.h"
  49. #include "Module.h"
  50. #include "Process.h"
  51. #include "Profile.h"
  52. #include "ReString.h"
  53. #include "Support.h"
  54. #include "SVDisk.h"
  55. #include "Thread.h"
  56. #include "Window.h"
  57.  
  58. #include "About.h"
  59. #include "Config.h"
  60.  
  61. #include "Items.h"
  62.  
  63. #include "MemSize.h"
  64.  
  65. #define STATIC          // When left blank, all functions appear in link-map.
  66. // #define DEBUG           // If defined, enables certain debugging messages to MEMSIZE.LOG.
  67. // #define DEBUG_POSITION  // If defined, enables window position debugging.
  68.  
  69.  
  70. /****************************************************************************
  71.  *                                                                          *
  72.  *                       Definitions & Declarations                         *
  73.  *                                                                          *
  74.  ****************************************************************************/
  75.  
  76.   // Data Types
  77.  
  78. typedef struct {
  79.    BOOL Active ;
  80.    PULONG Counter ;
  81.    PUSHORT Interval ;
  82.    PBYTE Priority ;
  83.    HWND Owner ;
  84. } MONITOR_PARMS, *PMONITOR_PARMS ;
  85.  
  86. typedef struct {
  87.    BOOL Active ;
  88.    ULONG Counter ;
  89. } COUNTER_PARMS, *PCOUNTER_PARMS ;
  90.  
  91. typedef struct {      // Data structure for window.
  92.    Process       *Proc ;
  93.    Module        *Library ;
  94.    Profile       *IniFile ;
  95.  
  96.    INIDATA        IniData ;
  97.    COLOR          BorderColor ;
  98.  
  99.    TID            CounterTID ;
  100.    COUNTER_PARMS  CounterParms ;
  101.  
  102.    TID            MonitorTID ;
  103.    MONITOR_PARMS  MonitorParms ;
  104.  
  105.    HWND           TitleBar ;
  106.    HWND           SysMenu ;
  107.    HWND           MinMax ;
  108.    HWND           Menu ;
  109.  
  110.    DATETIME       PreviousDateTime ;
  111.    int            WasDischarging ;
  112.  
  113.    int            Rows ;         // Number of table rows being displayed.
  114.    int            Columns ;      // Number of table columns being displayed.
  115.    int            ColumnWidth ;  // Table column width.
  116.  
  117.    ULONG          Exclude ;      // Drive exclusion mask.
  118.    ULONG          Drives ;       // Current active drive mask.
  119.    long           Width ;        // Font cell width.
  120.    long           Height ;       // Font cell height.
  121.    int            MaxColumns ;   // Maximum text columns per entry.
  122.    FONTMETRICS    FontMetrics ;
  123.    LONG           CharMode ;
  124.    SIZEF          CharBox ;
  125.    USHORT         CodePage ;
  126.  
  127.    Dde_Server    *pDdeServer ;
  128.  
  129.    HWND           DialogWindow ;
  130.  
  131. } DATA, *PDATA ;
  132.  
  133. typedef struct {
  134.    short Filler ;
  135.    Process *Proc ;
  136.    Module *Library ;
  137.    Profile *IniFile ;
  138.    USHORT CodePage ;
  139.    ULONG Exclude ;      
  140. } PARMS, *PPARMS ;
  141.  
  142.  
  143.   // Function Prototypes
  144.  
  145. extern int main ( int argc, char *argv[] ) ;
  146.  
  147. STATIC FNWP MessageProcessor ;
  148.  
  149. STATIC FNWP Create ;
  150. STATIC FNWP Destroy ;
  151. STATIC FNWP Size ;
  152. STATIC FNWP WindowTimer ;
  153. STATIC FNWP SaveApplication ;
  154. STATIC FNWP Paint ;
  155. STATIC FNWP InitMenu ;
  156. STATIC FNWP Activate ;
  157. STATIC FNWP Command ;
  158. STATIC FNWP ResetDefaults ;
  159. STATIC FNWP HideControlsCmd ;
  160. STATIC FNWP Configure ;
  161. STATIC FNWP ResetLoad ;
  162. STATIC FNWP ResetDrives ;
  163. STATIC FNWP Copy ;
  164. STATIC FNWP About ;
  165. STATIC FNWP BeginDrag ;
  166. STATIC FNWP ButtonDblClick ;
  167. STATIC FNWP ContextMenu ;
  168. STATIC FNWP PresParamChanged ;
  169. STATIC FNWP SysColorChange ;
  170. STATIC FNWP QueryKeysHelp ;
  171. STATIC FNWP HelpError ;
  172. STATIC FNWP ExtHelpUndefined ;
  173. STATIC FNWP HelpSubitemNotFound ;
  174. STATIC FNWP Refresh ;
  175. STATIC FNWP UpdateParms ;
  176. STATIC FNWP Dde_Initiate ;
  177.  
  178. STATIC int GetIniData ( HAB Anchor, HMODULE Library, HINI IniHandle, PINIDATA IniData, Dde_Server *pDdeServer, ULONG &Exclude ) ;
  179. extern PSZ ScanSystemConfig ( HAB Anchor, PSZ Keyword ) ;
  180. STATIC char *CopyString ( char *Buffer, char *Original ) ;
  181.  
  182. STATIC void ResizeWindow ( HWND hwnd ) ;
  183.  
  184. STATIC void HideControls ( BOOL fHide, HWND Frame, HWND SysMenu, HWND TitleBar, HWND MinMax ) ;
  185.  
  186. STATIC void UpdateWindow ( HWND hwnd, PDATA Data, BOOL All ) ;
  187.  
  188. STATIC void MonitorLoopThread ( void *Parameter ) ;
  189.  
  190. STATIC BOOL UpdateDriveList (
  191.    HAB Anchor, HMODULE Library, HINI IniHandle, PINIDATA IniData,
  192.    Dde_Server *pDdeServer, ULONG OldDrives, ULONG NewDrives, ULONG &ResultDrives, ULONG &Exclude ) ;
  193.  
  194. STATIC int CheckDrive ( USHORT Drive, PBYTE FileSystem, PBYTE DiskLabel ) ;
  195.  
  196. STATIC ULONG CalibrateLoadMeter ( PCOUNTER_PARMS Parms ) ;
  197.  
  198. STATIC void CounterThread ( void *Parameter ) ;
  199.  
  200.  
  201.   // Global Data
  202.  
  203. static Process Proc ;                           // Must be declared first.
  204. static Module Library ( PSZ(PROGRAM_NAME) ) ;
  205.  
  206. static Event CounterThreadEvent = Event ( ) ;
  207. static Event MonitorThreadEvent = Event ( ) ;
  208.  
  209. HMODULE LibraryHandle ;
  210.  
  211.  
  212. /****************************************************************************
  213.  *                                                                          *
  214.  *      Program Mainline                                                    *
  215.  *                                                                          *
  216.  ****************************************************************************/
  217.  
  218. extern int main ( int argc, char *argv[] ) {
  219.  
  220.   /**************************************************************************
  221.    * Save the resource library handle for the exception handler to use.     *
  222.    **************************************************************************/
  223.  
  224.    LibraryHandle = Library.QueryHandle() ;
  225.  
  226.   /**************************************************************************
  227.    * Get the program title.                                                 *
  228.    **************************************************************************/
  229.  
  230.    ResourceString Title ( Library.QueryHandle(), IDS_TITLE ) ;
  231.  
  232.   /**************************************************************************
  233.    * Set the codepage.  Abort if unable to do so.                           *
  234.    **************************************************************************/
  235.  
  236.    void *Offset ;
  237.    DosGetResource ( Library.QueryHandle(), RT_RCDATA, 1, &Offset ) ;
  238.  
  239.    PUSHORT pCodePage = PUSHORT ( Offset ) ;
  240.    USHORT DisplayCodePage = *pCodePage ;
  241.  
  242.    static PSZ pszData [2] = { 0, PSZ("Display") } ;
  243.    HDC MemoryDC = DevOpenDC ( Proc.QueryAnchor(), OD_MEMORY, PSZ("*"), 2, PDEVOPENDATA(pszData), 0 ) ;
  244.    SIZEL PageSize = { 0, 0 } ;
  245.    HPS hPS = GpiCreatePS ( Proc.QueryAnchor(), MemoryDC, &PageSize, PU_PELS | GPIA_ASSOC | GPIT_MICRO ) ;
  246.    while ( *pCodePage ) {
  247.       if ( GpiSetCp ( hPS, *pCodePage ) )
  248.          DisplayCodePage = *pCodePage ;
  249.       if ( !DosSetProcessCp ( *pCodePage ) )
  250.          if ( WinSetCp ( Proc.QueryQueue(), *pCodePage ) )
  251.             break ;
  252.       pCodePage ++ ;
  253.    } /* endwhile */
  254.    GpiDestroyPS ( hPS ) ;
  255.    DevCloseDC ( MemoryDC ) ;
  256.  
  257.    if ( *pCodePage == 0 ) {
  258.       ResourceString Format ( Library.QueryHandle(), IDS_ERROR_BADCODEPAGE ) ;
  259.       CHAR Message [200] ;
  260.       sprintf ( Message, PCHAR(Format), *pCodePage ) ;
  261.       Log ( "%s", Message ) ;
  262.       WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, PSZ(Message),
  263.          PSZ(Title), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  264.       return ( 1 ) ;
  265.    } /* endif */
  266.  
  267.   /**************************************************************************
  268.    * Decipher command-line parameters.                                      *
  269.    **************************************************************************/
  270.  
  271.    BOOL Reset = FALSE ;
  272.    ULONG ExcludeDrives = 0 ;
  273.  
  274.    ResourceString ResetCommand ( Library.QueryHandle(), IDS_PARMS_RESET ) ;
  275.    ResourceString ExcludeCommand ( Library.QueryHandle(), IDS_PARMS_EXCLUDE ) ;
  276.  
  277.    while ( --argc ) {
  278.  
  279.       argv ++ ;
  280.  
  281.       if ( *argv[0] == '?' ) {
  282.          ResourceString Message ( Library.QueryHandle(), IDS_PARAMETERLIST ) ;
  283.          WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, PSZ(Message),
  284.             PSZ(Title), 0, MB_ENTER | MB_NOICON ) ;
  285.          return ( 0 ) ;
  286.       } /* endif */
  287.  
  288.       if ( !stricmp ( *argv, PCHAR(ResetCommand) ) ) {
  289.          Reset = TRUE ;
  290.          continue ;
  291.       } /* endif */
  292.  
  293.       if ( !strnicmp ( *argv, PCHAR(ExcludeCommand), strlen(PCHAR(ExcludeCommand)) ) ) {
  294.          char *p = *argv+strlen(PCHAR(ExcludeCommand)) ;
  295.          while ( *p ) {
  296.             ExcludeDrives |= 0x0001 << ( *p - 'A' ) ;
  297.             p ++ ;
  298.          } /* endfor */
  299.          continue ;
  300.       } /* endif */
  301.  
  302.       #if 0
  303.       ResourceString Format ( Library.QueryHandle(), IDS_ERROR_INVALIDPARM ) ;
  304.       BYTE Message [200] ;
  305.       sprintf ( PCHAR(Message), PCHAR(Format), *argv ) ;
  306.       WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, Message,
  307.          PSZ(Title), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  308.       return ( 1 ) ;
  309.       #endif
  310.  
  311.    } /* endwhile */
  312.  
  313.   /**************************************************************************
  314.    * Create the help instance.                                              *
  315.    **************************************************************************/
  316.  
  317.    ResourceString HelpTitle ( Library.QueryHandle(), IDS_HELPTITLE ) ;
  318.  
  319.    HelpWindow Help ( Proc.QueryAnchor(), 0,
  320.       ID_MAIN, PSZ(PROGRAM_NAME ".hlp"), PSZ(HelpTitle) ) ;
  321.  
  322.    if ( Help.QueryHandle() == 0 ) {
  323.       ERRORID Error = WinGetLastError ( Proc.QueryAnchor() ) ;
  324.       ResourceString Format ( Library.QueryHandle(), IDS_ERROR_CREATEHELP ) ;
  325.       CHAR Message [200] ;
  326.       sprintf ( Message, PCHAR(Format), Error ) ;
  327.       Log ( "%s", Message ) ;
  328.       WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, PSZ(Message),
  329.          PSZ(Title), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  330.    } /* endif */
  331.  
  332.   /**************************************************************************
  333.    * Open/create the profile file.  Reset if requested.                     *
  334.    **************************************************************************/
  335.  
  336.    Profile IniFile ( PSZ(PROGRAM_NAME),
  337.       Proc.QueryAnchor(), Library.QueryHandle(),
  338.       IDD_PROFILE_PATH, Help.QueryHandle(), Reset ) ;
  339.  
  340.    if ( IniFile.QueryHandle() == 0 ) {
  341.       ResourceString Message ( Library.QueryHandle(), IDS_ERROR_PRFOPENPROFILE ) ;
  342.       Log ( "%s", PSZ(Message) ) ;
  343.       WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, PSZ(Message),
  344.          PSZ(Title), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  345.       return ( 2 ) ;
  346.    } /* endif */
  347.  
  348.   /**************************************************************************
  349.    * Read the profile to find out if we're to animate the frame window.     *
  350.    **************************************************************************/
  351.  
  352.    INIDATA IniData ;
  353.    if ( GetIniData ( HINI_USERPROFILE, &IniData ) ) {
  354.       GetIniData ( IniFile.QueryHandle(), &IniData ) ;
  355.    } else {
  356.       PutIniData ( IniFile.QueryHandle(), &IniData ) ;
  357.       PrfWriteProfileData ( HINI_USERPROFILE, PSZ(PROGRAM_NAME), 0, 0, 0 ) ;
  358.    } /* endif */
  359.  
  360.   /**************************************************************************
  361.    * Create the frame window.                                               *
  362.    **************************************************************************/
  363.  
  364.    FRAMECDATA FrameControlData ;
  365.    memset ( &FrameControlData, 0, sizeof(FrameControlData) ) ;
  366.    FrameControlData.cb = sizeof(FrameControlData) ;
  367.    FrameControlData.flCreateFlags =
  368.       FCF_TITLEBAR | FCF_SYSMENU | FCF_BORDER |
  369.       FCF_ICON | FCF_MINBUTTON | FCF_NOBYTEALIGN | FCF_ACCELTABLE ;
  370.    FrameControlData.idResources = ID_MAIN ;
  371.  
  372.    Window Frame ( HWND_DESKTOP, WC_FRAME, PSZ(Title),
  373.       IniData.fAnimate AND IniData.Animate ? WS_ANIMATE : 0,
  374.       0, 0, 0, 0, HWND_DESKTOP, HWND_TOP, ID_MAIN,
  375.       &FrameControlData, NULL ) ;
  376.  
  377.    if ( Frame.QueryHandle() == 0 ) {
  378.       ERRORID Error = WinGetLastError ( Proc.QueryAnchor() ) ;
  379.       ResourceString Format ( Library.QueryHandle(), IDS_ERROR_CREATEFRAME ) ;
  380.       CHAR Message [200] ;
  381.       sprintf ( Message, PCHAR(Format), Error ) ;
  382.       Log ( "%s", Message ) ;
  383.       WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, PSZ(Message),
  384.          PSZ(Title), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  385.       return ( 3 ) ;
  386.    } /* endif */
  387.  
  388.   /**************************************************************************
  389.    * Associate the help instance with the frame window.                     *
  390.    **************************************************************************/
  391.  
  392.    if ( Help.QueryHandle() )
  393.       WinAssociateHelpInstance ( Help.QueryHandle(), Frame.QueryHandle() ) ;
  394.  
  395.   /**************************************************************************
  396.    * Register the client window class.                                      *
  397.    **************************************************************************/
  398.  
  399.    if ( !WinRegisterClass ( Proc.QueryAnchor(), PSZ(CLASS_NAME),
  400.       MessageProcessor, CS_MOVENOTIFY, sizeof(PVOID) ) ) {
  401.       ERRORID Error = WinGetLastError ( Proc.QueryAnchor() ) ;
  402.       ResourceString Format ( Library.QueryHandle(), IDS_ERROR_WINREGISTERCLASS ) ;
  403.       CHAR Message [200] ;
  404.       sprintf ( Message, PCHAR(Format), CLASS_NAME, Error ) ;
  405.       Log ( "%s", Message ) ;
  406.       WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, PSZ(Message),
  407.          PSZ(Title), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  408.       return ( 4 ) ;
  409.    } /* endif */
  410.  
  411.   /**************************************************************************
  412.    * Build the presentation parameters for the client window.               *
  413.    **************************************************************************/
  414.  
  415.    USHORT ParmCount = 0 ;
  416.    ULONG Ids [3] ;
  417.    ULONG ByteCounts [3] ;
  418.    PBYTE Params [3] ;
  419.  
  420.    if ( IniData.fTextColor ) {
  421.       Ids [ParmCount] = PP_FOREGROUNDCOLOR ;
  422.       ByteCounts [ParmCount] = sizeof(IniData.TextColor) ;
  423.       Params [ParmCount++] = PBYTE ( &IniData.TextColor ) ;
  424.    } /* endif */
  425.  
  426.    if ( IniData.fBackColor ) {
  427.       Ids [ParmCount] = PP_BACKGROUNDCOLOR ;
  428.       ByteCounts [ParmCount] = sizeof(IniData.BackColor) ;
  429.       Params [ParmCount++] = PBYTE ( &IniData.BackColor ) ;
  430.    } /* endif */
  431.  
  432.    if ( IniData.fFontNameSize ) {
  433.       Ids [ParmCount] = PP_FONTNAMESIZE ;
  434.       ByteCounts [ParmCount] = strlen(PCHAR(IniData.FontNameSize)) + 1 ;
  435.       Params [ParmCount++] = PBYTE ( IniData.FontNameSize ) ;
  436.    } /* endif */
  437.  
  438.    PPRESPARAMS PresParams = BuildPresParams ( ParmCount, Ids, ByteCounts, Params ) ;
  439.  
  440.   /**************************************************************************
  441.    * Create the client window.                                              *
  442.    **************************************************************************/
  443.  
  444.    PARMS Parms ;
  445.    Parms.Filler = 0 ;
  446.    Parms.Proc = & Proc ;
  447.    Parms.Library = & Library ;
  448.    Parms.IniFile = & IniFile ;
  449.    Parms.CodePage = DisplayCodePage ;
  450.    Parms.Exclude = ExcludeDrives ;
  451.  
  452.    Window Client ( Frame.QueryHandle(), PSZ(CLASS_NAME), PSZ(""), 0, 0, 0, 0, 0,
  453.       Frame.QueryHandle(), HWND_BOTTOM, FID_CLIENT, &Parms, PresParams ) ;
  454.  
  455.    if ( Client.QueryHandle() == 0 ) {
  456.       ERRORID Error = WinGetLastError ( Proc.QueryAnchor() ) ;
  457.       ResourceString Format ( Library.QueryHandle(), IDS_ERROR_CREATECLIENT ) ;
  458.       CHAR Message [200] ;
  459.       sprintf ( Message, PCHAR(Format), Error ) ;
  460.       Log ( "%s", Message ) ;
  461.       WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, PSZ(Message),
  462.          PSZ(Title), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  463.       return ( 5 ) ;
  464.    } /* endif */
  465.  
  466.   /**************************************************************************
  467.    * Wait for and process messages to the window's queue.  Terminate        *
  468.    *   when the WM_QUIT message is received.                                *
  469.    **************************************************************************/
  470.  
  471.    QMSG QueueMessage ;
  472.    while ( WinGetMsg ( Proc.QueryAnchor(), &QueueMessage, 0, 0, 0 ) ) {
  473.       WinDispatchMsg ( Proc.QueryAnchor(), &QueueMessage ) ;
  474.    } /* endwhile */
  475.  
  476.   /**************************************************************************
  477.    * Discard all that was requested of the system and terminate.            *
  478.    **************************************************************************/
  479.  
  480.    return ( 0 ) ;
  481. }
  482.  
  483. /****************************************************************************
  484.  *                                                                          *
  485.  *      Window Message Processor                                            *
  486.  *                                                                          *
  487.  ****************************************************************************/
  488.  
  489. STATIC MRESULT EXPENTRY MessageProcessor ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  490.  
  491.   /**************************************************************************
  492.    * Dispatch the message according to the method table and return the      *
  493.    *   result.  Any messages not defined above get handled by the system    *
  494.    *   default window processor.                                            *
  495.    **************************************************************************/
  496.  
  497.    static METHOD Methods [] = {
  498.       { WM_CREATE,                Create              },
  499.       { WM_DESTROY,               Destroy             },
  500.       { WM_SIZE,                  Size                },
  501.       { WM_MOVE,                  Size                },
  502.       { WM_TIMER,                 WindowTimer         },
  503.       { WM_SAVEAPPLICATION,       SaveApplication     },
  504.       { WM_PAINT,                 Paint               },
  505.       { WM_INITMENU,              InitMenu            },
  506.       { WM_ACTIVATE,              Activate            },
  507.       { WM_COMMAND,               Command             },
  508.       { WM_BEGINSELECT,           BeginDrag           },
  509.       { WM_BEGINDRAG,             BeginDrag           },
  510.       { WM_BUTTON1DBLCLK,         ButtonDblClick      },
  511.       { WM_CONTEXTMENU,           ContextMenu         },
  512.       { WM_PRESPARAMCHANGED,      PresParamChanged    },
  513.       { WM_SYSCOLORCHANGE,        SysColorChange      },
  514.       { HM_QUERY_KEYS_HELP,       QueryKeysHelp       },
  515.       { HM_ERROR,                 HelpError           },
  516.       { HM_EXT_HELP_UNDEFINED,    ExtHelpUndefined    },
  517.       { HM_HELPSUBITEM_NOT_FOUND, HelpSubitemNotFound },
  518.       { WM_REFRESH,               Refresh             },
  519.       { WM_UPDATEPARMS,           UpdateParms         },
  520.       { WM_DDE_INITIATE,          Dde_Initiate        },
  521.    } ;
  522.  
  523.    #ifdef DEBUG
  524.       static int Indent = 0 ;
  525.       Log ( "%*sMAIN: Message %08X received.  Parm1=%08X, Parm2=%08X.", Indent, "", msg, mp1, mp2 ) ;
  526.       Indent += 2 ;
  527.    #endif
  528.  
  529.    MRESULT Result = DispatchMessage ( hwnd, msg, mp1, mp2, Methods, sizeof(Methods)/sizeof(Methods[0]), WinDefWindowProc ) ;
  530.  
  531.    #ifdef DEBUG
  532.       Indent -= 2 ;
  533.       Log ( "%*sMAIN: Message %08X done.  Result %08X.", Indent, "", msg, Result ) ;
  534.    #endif
  535.  
  536.    return ( Result ) ;
  537. }
  538.  
  539. /****************************************************************************
  540.  *                                                                          *
  541.  *      Create the main window.                                             *
  542.  *                                                                          *
  543.  ****************************************************************************/
  544.  
  545. STATIC MRESULT APIENTRY Create ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  546.  
  547.   /**************************************************************************
  548.    * Allocate instance data.                                                *
  549.    **************************************************************************/
  550.  
  551.    PDATA Data = PDATA ( malloc ( sizeof(DATA) ) ) ;
  552.  
  553.    memset ( Data, 0, sizeof(DATA) ) ;
  554.  
  555.    WinSetWindowPtr ( hwnd, QWL_USER, Data ) ;
  556.  
  557.   /**************************************************************************
  558.    * Grab any parameters from the WM_CREATE message.                        *
  559.    **************************************************************************/
  560.  
  561.    PPARMS Parms = PPARMS ( PVOIDFROMMP ( mp1 ) ) ;
  562.  
  563.    Data->Proc = Parms->Proc ;
  564.    Data->Library = Parms->Library ;
  565.    Data->IniFile = Parms->IniFile ;
  566.    Data->CodePage = Parms->CodePage ;
  567.    Data->Exclude = Parms->Exclude ;
  568.  
  569.   /**************************************************************************
  570.    * Get the border color.                                                  *
  571.    **************************************************************************/
  572.  
  573.    Data->BorderColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_WINDOWFRAME, 0 ) ;
  574.  
  575.   /**************************************************************************
  576.    * Initialize the DDE Server.                                             *
  577.    **************************************************************************/
  578.  
  579.    Data->pDdeServer = new Dde_Server ( Data->Proc->QueryAnchor(),
  580.       Data->Library->QueryHandle(), hwnd, PROGRAM_NAME ) ;
  581.  
  582.    Data->pDdeServer->AddTopic ( SZDDESYS_TOPIC, SZDDESYS_ITEM_SYSITEMS ) ;
  583.  
  584.    char *Topics = SZDDESYS_TOPIC "\t" "Items" ;
  585.    Data->pDdeServer->AddItem ( SZDDESYS_TOPIC, SZDDESYS_ITEM_TOPICS, DDEFMT_TEXT, Topics, strlen(Topics)+1 ) ;
  586.  
  587.    char *Protocols = "" ;
  588.    Data->pDdeServer->AddItem ( SZDDESYS_TOPIC, SZDDESYS_ITEM_PROTOCOLS, DDEFMT_TEXT, Protocols, strlen(Protocols)+1 ) ;
  589.  
  590.    Data->pDdeServer->AddTopic ( "Items", "Items" ) ;
  591.  
  592.   /**************************************************************************
  593.    * Load the window context menu.                                          *
  594.    **************************************************************************/
  595.  
  596.    Data->Menu = WinLoadMenu ( HWND_DESKTOP, Data->Library->QueryHandle(), IDM_MENU ) ;
  597.    if ( Data->Menu == 0 ) {
  598.       ERRORID Error = WinGetLastError ( Data->Proc->QueryAnchor() ) ;
  599.       Log ( "WARNING: Unable to create context menu.  Error %08lX.", Error ) ;
  600.    } /* endif */ 
  601.  
  602.   /**************************************************************************
  603.    * Get the current drive mask.                                            *
  604.    **************************************************************************/
  605.  
  606.    ULONG Drive ;
  607.    DosQueryCurrentDisk ( &Drive, &Data->Drives ) ;
  608.    Data->Drives &= ~Data->Exclude ;
  609.  
  610.   /**************************************************************************
  611.    * Calibrate the old-style load meter, if the high resolution timer's     *
  612.    *   available.                                                           *
  613.    **************************************************************************/
  614.  
  615.    Data->IniData.MaxCount = CalibrateLoadMeter ( &Data->CounterParms ) ;
  616.    Data->IniData.MaxCount = (ULONG) max ( 1, Data->IniData.MaxCount ) ;
  617.  
  618.   /**************************************************************************
  619.    * Get profile data. Try the OS2.INI first, then try for private INI.     *
  620.    *   If obtained from OS2.INI, erase it afterwards.                       *
  621.    **************************************************************************/
  622.  
  623.    if ( GetIniData ( Data->Proc->QueryAnchor(), Data->Library->QueryHandle(), HINI_USERPROFILE, &Data->IniData, Data->pDdeServer, Data->Exclude ) ) {
  624.       GetIniData ( Data->Proc->QueryAnchor(), Data->Library->QueryHandle(), Data->IniFile->QueryHandle(), &Data->IniData, Data->pDdeServer, Data->Exclude ) ;
  625.    } else {
  626.       PutIniData ( Data->IniFile->QueryHandle(), &Data->IniData ) ;
  627.       PrfWriteProfileData ( HINI_USERPROFILE, PSZ(PROGRAM_NAME), 0, 0, 0 ) ;
  628.    } /* endif */
  629.  
  630.   /**************************************************************************
  631.    * Get initial time.                                                      *
  632.    **************************************************************************/
  633.  
  634.    DosGetDateTime ( &Data->PreviousDateTime ) ;
  635.  
  636.   /**************************************************************************
  637.    * Set initial battery status.                                            *
  638.    **************************************************************************/
  639.  
  640.    Data->WasDischarging = FALSE ;
  641.  
  642.   /**************************************************************************
  643.    * Get the frame handle.                                                  *
  644.    **************************************************************************/
  645.  
  646.    HWND Frame = WinQueryWindow ( hwnd, QW_PARENT ) ;
  647.  
  648.   /**************************************************************************
  649.    * Get the control window handles.                                        *
  650.    **************************************************************************/
  651.  
  652.    Data->SysMenu  = WinWindowFromID ( Frame, FID_SYSMENU  ) ;
  653.    Data->TitleBar = WinWindowFromID ( Frame, FID_TITLEBAR ) ;
  654.    Data->MinMax   = WinWindowFromID ( Frame, FID_MINMAX   ) ;
  655.  
  656.   /**************************************************************************
  657.    * Add basic extensions to the system menu.                               *
  658.    **************************************************************************/
  659.  
  660.    static MENUITEM MenuSeparator =
  661.       { MIT_END, MIS_SEPARATOR, 0, 0, 0, 0 } ;
  662.  
  663.    AddSysMenuItem ( Frame, &MenuSeparator, 0 ) ;
  664.  
  665.    static MENUITEM MenuItems [] = {
  666.       { MIT_END, MIS_TEXT,      0, IDM_SAVE_APPLICATION, 0, 0 },
  667.       { MIT_END, MIS_TEXT,      0, IDM_RESET_DEFAULTS,   0, 0 },
  668.       { MIT_END, MIS_TEXT,      0, IDM_HIDE_CONTROLS,    0, 0 },
  669.       { MIT_END, MIS_TEXT,      0, IDM_CONFIGURE,        0, 0 },
  670.       { MIT_END, MIS_TEXT,      0, IDM_RESETLOAD,        0, 0 },
  671.       { MIT_END, MIS_TEXT,      0, IDM_RESETDRIVES,      0, 0 },
  672.       { MIT_END, MIS_TEXT,      0, IDM_COPY,             0, 0 },
  673.    } ;
  674.  
  675.    for ( int i=0; i<sizeof(MenuItems)/sizeof(MenuItems[0]); i++ ) {
  676.       ResourceString MenuText ( Data->Library->QueryHandle(), i+IDS_SAVE_APPLICATION ) ;
  677.       AddSysMenuItem ( Frame, MenuItems+i, PSZ(MenuText) ) ;
  678.    } /* endfor */
  679.  
  680.    AddSysMenuItem ( Frame, &MenuSeparator, 0 ) ;
  681.  
  682.   /**************************************************************************
  683.    * Add 'About' to the system menu.                                        *
  684.    **************************************************************************/
  685.  
  686.    static MENUITEM MenuAbout =
  687.       { MIT_END, MIS_TEXT, 0, IDM_ABOUT, 0, 0 } ; 
  688.  
  689.    ResourceString AboutText ( Data->Library->QueryHandle(), IDS_ABOUT ) ;
  690.  
  691.    AddSysMenuItem ( Frame, &MenuAbout, PSZ(AboutText) ) ;
  692.  
  693.   /**************************************************************************
  694.    * Add 'Help' to the system menu.                                         *
  695.    **************************************************************************/
  696.  
  697.    static MENUITEM MenuHelp =
  698.       { MIT_END, MIS_HELP, 0, 0, 0, 0 } ;
  699.  
  700.    ResourceString HelpText ( Data->Library->QueryHandle(), IDS_HELP ) ;
  701.  
  702.    AddSysMenuItem ( Frame, &MenuHelp, PSZ(HelpText) ) ;
  703.  
  704.   /**************************************************************************
  705.    * Start the new load meter.                                              *
  706.    **************************************************************************/
  707.  
  708.    CounterThreadEvent.Reset ( ) ;
  709.    Data->CounterParms.Active = TRUE ;
  710.    Data->CounterTID = StartThread ( "CounterThread", CounterThread, 0x3000, &Data->CounterParms ) ;
  711.    DosSuspendThread ( Data->CounterTID ) ;
  712.    DosSetPriority ( PRTYS_THREAD, PRTYC_IDLETIME, PRTYD_MINIMUM, Data->CounterTID ) ;
  713.  
  714.    Data->IniData.IdleCount = 0 ;
  715.    Data->CounterParms.Counter = 0 ;
  716.  
  717.    if ( Data->IniData.Items[ITEM_CPULOAD]->QueryFlag() )
  718.       DosResumeThread ( Data->CounterTID ) ;
  719.  
  720.    MonitorThreadEvent.Reset ( ) ;
  721.    Data->MonitorParms.Active = TRUE ;
  722.    Data->MonitorParms.Counter = & Data->CounterParms.Counter ;
  723.    Data->MonitorParms.Interval = & Data->IniData.TimerInterval ;
  724.    Data->MonitorParms.Priority = & Data->IniData.MonitorPriority ;
  725.    Data->MonitorParms.Owner = hwnd ;
  726.    Data->MonitorTID = StartThread ( "MonitorLoopThread", MonitorLoopThread, 0x3000, &Data->MonitorParms ) ;
  727.  
  728.   /**************************************************************************
  729.    * Add the program to the system task list.                               *
  730.    **************************************************************************/
  731.  
  732.    ResourceString Title ( Data->Library->QueryHandle(), IDS_TITLE ) ;
  733.    Add2TaskList ( Frame, PSZ(Title) ) ;
  734.  
  735.   /**************************************************************************
  736.    * Hide the controls if so configured.                                    *
  737.    **************************************************************************/
  738.  
  739.    #ifdef DEBUG
  740.    Log ( "Create: HideControls:%s, Minimize:%s.",
  741.       Data->IniData.HideControls ? "TRUE" : "FALSE",
  742.       Data->IniData.Position.fl & SWP_MINIMIZE ? "TRUE" : "FALSE" ) ;
  743.    #endif
  744.  
  745.    if ( Data->IniData.HideControls AND NOT ( Data->IniData.Position.fl & SWP_MINIMIZE ) ) {
  746.       #ifdef DEBUG
  747.       Log ( "Create: Hiding controls." ) ;
  748.       #endif
  749.       HideControls ( TRUE, Frame, Data->SysMenu, Data->TitleBar, Data->MinMax ) ;
  750.    } /* endif */ 
  751.  
  752.   /**************************************************************************
  753.    * Position & size the window.  For some reason, we must move and size    *
  754.    *   the window to the saved position before applying the resizing        *
  755.    *   function as fine-tuning.  Maybe the positioning request fails if     *
  756.    *   the window has no size?                                              *
  757.    **************************************************************************/
  758.  
  759.    #ifdef DEBUG_POSITION
  760.    Log ( "Create: Setting window position to %i,%i (%ix%i).",
  761.       Data->IniData.Position.x, Data->IniData.Position.y,
  762.       Data->IniData.Position.cx, Data->IniData.Position.cy ) ;
  763.    #endif // DEBUG_POSITION
  764.  
  765.    WinSetWindowPos ( Frame, 0,
  766.       Data->IniData.Position.x, Data->IniData.Position.y,
  767.       Data->IniData.Position.cx, Data->IniData.Position.cy,
  768.       SWP_SIZE | SWP_MOVE | 
  769.       ( Data->IniData.Position.fl & SWP_MINIMIZE ) |
  770.       ( Data->IniData.Position.fl & SWP_RESTORE ) ) ;
  771.  
  772.   /**************************************************************************
  773.    * Determine our font size.                                               *
  774.    **************************************************************************/
  775.  
  776.    HPS hPS = WinGetPS ( hwnd ) ;
  777.    RECTL Rectangle ;
  778.    WinQueryWindowRect ( HWND_DESKTOP, &Rectangle ) ;
  779.    WinDrawText ( hPS, 1, PSZ(" "), &Rectangle, 0, 0, DT_LEFT | DT_BOTTOM | DT_QUERYEXTENT ) ;
  780.    Data->Width  = Rectangle.xRight - Rectangle.xLeft ;
  781.    Data->Height = Rectangle.yTop - Rectangle.yBottom ;
  782.    WinReleasePS ( hPS ) ;
  783.  
  784.   /**************************************************************************
  785.    * Adjust the window size to suit the displayable items.                  *
  786.    **************************************************************************/
  787.  
  788.    ResizeWindow ( hwnd ) ;
  789.  
  790.   /**************************************************************************
  791.    * Now that the window's in order, make it visible.                       *
  792.    **************************************************************************/
  793.  
  794.    WinShowWindow ( Frame, TRUE ) ;
  795.  
  796.   /**************************************************************************
  797.    * Fix for FixPack 17: Activate the window, then deactivate it.           *
  798.    *   For some reason this prevents the surfacing problem that first       *
  799.    *   appeared when I (and others) installed the FixPack.                  *
  800.    **************************************************************************/
  801.  
  802.    WinSetWindowPos ( Frame, 0, 0, 0, 0, 0, SWP_ACTIVATE ) ;
  803.    WinSetWindowPos ( Frame, 0, 0, 0, 0, 0, SWP_DEACTIVATE ) ;
  804.  
  805.   /**************************************************************************
  806.    * Start the drive error reset timer.                                     *
  807.    **************************************************************************/
  808.  
  809.    WinStartTimer ( 0, hwnd, 1, 60000 ) ;
  810.  
  811.   /**************************************************************************
  812.    * Success?  Return no error.                                             *
  813.    **************************************************************************/
  814.  
  815.    return ( 0 ) ;
  816. }
  817.  
  818. /****************************************************************************
  819.  *                                                                          *
  820.  *      Destroy main window.                                                *
  821.  *                                                                          *
  822.  ****************************************************************************/
  823.  
  824. STATIC MRESULT APIENTRY Destroy ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  825.  
  826.  /***************************************************************************
  827.   * Find the instance data.                                                 *
  828.   ***************************************************************************/
  829.  
  830.   PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  831.  
  832.  /***************************************************************************
  833.   * Kill the drive error reset timer.                                       *
  834.   ***************************************************************************/
  835.  
  836.   WinStopTimer ( 0, hwnd, 1 ) ;
  837.  
  838.  /***************************************************************************
  839.   * Kill the extra threads.                                                 *
  840.   ***************************************************************************/
  841.  
  842.   DosResumeThread ( Data->MonitorTID ) ;
  843.   Data->MonitorParms.Active = FALSE ;
  844.   MonitorThreadEvent.Wait ( 10000 ) ;
  845.  
  846.   DosResumeThread ( Data->CounterTID ) ;
  847.   Data->CounterParms.Active = FALSE ;
  848.   DosSetPriority ( PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, Data->CounterTID ) ;
  849.   CounterThreadEvent.Wait ( 10000 ) ;
  850.  
  851.  /***************************************************************************
  852.   * Destroy the DDE Server object.                                          *
  853.   ***************************************************************************/
  854.  
  855.   delete Data->pDdeServer ;
  856.  
  857.  /***************************************************************************
  858.   * Release the instance memory.                                            *
  859.   ***************************************************************************/
  860.  
  861.   free ( Data ) ;
  862.  
  863.  /***************************************************************************
  864.   * We're done.                                                             *
  865.   ***************************************************************************/
  866.  
  867.   return ( 0 ) ;
  868. }
  869.  
  870. /****************************************************************************
  871.  *                                                                          *
  872.  *      Process window resize message.                                      *
  873.  *                                                                          *
  874.  ****************************************************************************/
  875.  
  876. STATIC MRESULT APIENTRY Size ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  877.  
  878.   #ifdef DEBUG
  879.   Log ( "Size: Started." ) ;
  880.   #endif
  881.  
  882.  /***************************************************************************
  883.   * Find the instance data.                                                 *
  884.   ***************************************************************************/
  885.  
  886.   PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  887.  
  888.  /***************************************************************************
  889.   * Find out the window's new position and size.                            *
  890.   ***************************************************************************/
  891.  
  892.   HWND Frame = WinQueryWindow ( hwnd, QW_PARENT ) ;
  893.  
  894.   SWP Position ;
  895.   WinQueryWindowPos ( Frame, &Position ) ;
  896.  
  897.   if (   NOT ( Position.fl & SWP_HIDE     )
  898.      AND NOT ( Position.fl & SWP_MINIMIZE )
  899.      AND NOT ( Position.fl & SWP_MAXIMIZE ) ) {
  900.  
  901.      Data->IniData.Position.x = Position.x ;
  902.      Data->IniData.Position.y = Position.y ;
  903.  
  904.      Data->IniData.Position.cx = Position.cx ;
  905.      Data->IniData.Position.cy = Position.cy ;
  906.  
  907.      #ifdef DEBUG
  908.      Log ( "Size: Window position set to %i,%i (%ix%i).",
  909.         Data->IniData.Position.x, Data->IniData.Position.y,
  910.         Data->IniData.Position.cx, Data->IniData.Position.cy ) ;
  911.      #endif
  912.  
  913.   } /* endif */
  914.  
  915.  /***************************************************************************
  916.   * If hiding the controls . . .                                            *
  917.   ***************************************************************************/
  918.  
  919.   if ( Data->IniData.HideControls ) {
  920.  
  921.    /*************************************************************************
  922.     * If changing to or from minimized state . . .                          *
  923.     *************************************************************************/
  924.  
  925.     if ( ( Position.fl & SWP_MINIMIZE ) != ( Data->IniData.Position.fl & SWP_MINIMIZE ) ) {
  926.  
  927.      /***********************************************************************
  928.       * Hide the controls if no longer minimized.                           *
  929.       ***********************************************************************/
  930.  
  931.       HideControls ( NOT ( Position.fl & SWP_MINIMIZE ),
  932.         Frame, Data->SysMenu, Data->TitleBar, Data->MinMax ) ;
  933.  
  934.     }
  935.   }
  936.  
  937.   Data->IniData.Position.fl = Position.fl ;
  938.  
  939.  /***************************************************************************
  940.   * We're done.                                                             *
  941.   ***************************************************************************/
  942.  
  943.   #ifdef DEBUG
  944.   Log ( "Size: Done." ) ;
  945.   #endif
  946.  
  947.   return ( 0 ) ;
  948. }
  949.  
  950. /****************************************************************************
  951.  *                                                                          *
  952.  *      Process window timer message.                                       *
  953.  *                                                                          *
  954.  ****************************************************************************/
  955.  
  956. STATIC MRESULT APIENTRY WindowTimer ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  957.  
  958.  /***************************************************************************
  959.   * If this is the reset drive timer, post message to self to do it.        *
  960.   ***************************************************************************/
  961.  
  962.   if ( SHORT1FROMMP(mp1) == 1 ) 
  963.      WinPostMsg ( hwnd, WM_COMMAND, MPFROM2SHORT(IDM_RESETDRIVES,0), 0 ) ;
  964.  
  965.  /***************************************************************************
  966.   * We're done.  Pass this message on to the default procedure.             *
  967.   ***************************************************************************/
  968.  
  969.   return ( WinDefWindowProc ( hwnd, msg, mp1, mp2 ) ) ;
  970. }
  971.  
  972. /****************************************************************************
  973.  *                                                                          *
  974.  *      Process SAVE APPLICATION message.                                   *
  975.  *                                                                          *
  976.  ****************************************************************************/
  977.  
  978. STATIC MRESULT APIENTRY SaveApplication ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  979.  
  980.  /***************************************************************************
  981.   * Find the instance data.                                                 *
  982.   ***************************************************************************/
  983.  
  984.   PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  985.  
  986.  /***************************************************************************
  987.   * Call function to put all profile data out to the system.                *
  988.   ***************************************************************************/
  989.  
  990.   PutIniData ( Data->IniFile->QueryHandle(), &Data->IniData ) ;
  991.  
  992.  /***************************************************************************
  993.   * We're done.  Let the system complete default processing.                *
  994.   ***************************************************************************/
  995.  
  996.   return ( WinDefWindowProc ( hwnd, WM_SAVEAPPLICATION, 0, 0 ) ) ;
  997. }
  998.  
  999. /****************************************************************************
  1000.  *                                                                          *
  1001.  *      Repaint entire window.                                              *
  1002.  *                                                                          *
  1003.  ****************************************************************************/
  1004.  
  1005. STATIC MRESULT APIENTRY Paint ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1006.  
  1007.  /***************************************************************************
  1008.   * Find the instance data.                                                 *
  1009.   ***************************************************************************/
  1010.  
  1011.   PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  1012.  
  1013.  /***************************************************************************
  1014.   * Get presentation space and make it use RGB colors.                      *
  1015.   ***************************************************************************/
  1016.  
  1017.   HPS hPS = WinBeginPaint ( hwnd, 0, 0 ) ;
  1018.   GpiCreateLogColorTable ( hPS, LCOL_RESET, LCOLF_RGB, 0, 0, 0 ) ;
  1019.   GpiSetCp ( hPS, Data->CodePage ) ;
  1020.  
  1021.  /***************************************************************************
  1022.   * Get font information for later use with Copy command.                   *
  1023.   ***************************************************************************/
  1024.  
  1025.   GpiQueryFontMetrics ( hPS, sizeof(Data->FontMetrics), &Data->FontMetrics ) ;
  1026.   Data->CharMode = GpiQueryCharMode ( hPS ) ;
  1027.   GpiQueryCharBox ( hPS, &Data->CharBox ) ;
  1028.  
  1029.  /***************************************************************************
  1030.   * Clear the window.                                                       *
  1031.   ***************************************************************************/
  1032.  
  1033.   RECTL Rectangle ;
  1034.   WinQueryWindowRect ( hwnd, &Rectangle ) ;
  1035.  
  1036.   GpiMove ( hPS, (PPOINTL) &Rectangle.xLeft ) ;
  1037.   GpiSetColor ( hPS, Data->IniData.BackColor ) ;
  1038.   GpiBox ( hPS, DRO_FILL, (PPOINTL) &Rectangle.xRight, 0, 0 ) ;
  1039.  
  1040.  /***************************************************************************
  1041.   * Release presentation space.                                             *
  1042.   ***************************************************************************/
  1043.  
  1044.   WinEndPaint ( hPS ) ;
  1045.  
  1046.  /***************************************************************************
  1047.   * Update the window and return.                                           *
  1048.   ***************************************************************************/
  1049.  
  1050.   UpdateWindow ( hwnd, Data, TRUE ) ;
  1051.  
  1052.   return ( 0 ) ;
  1053. }
  1054.  
  1055. /****************************************************************************
  1056.  *                                                                          *
  1057.  *      Process requests for menu initialization.                           *
  1058.  *                                                                          *
  1059.  ****************************************************************************/
  1060.  
  1061. STATIC MRESULT APIENTRY InitMenu ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1062.  
  1063.  /***************************************************************************
  1064.   * Find the instance data.                                                 *
  1065.   ***************************************************************************/
  1066.  
  1067.   PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  1068.  
  1069.  /***************************************************************************
  1070.   * Get the message data.                                                   *
  1071.   ***************************************************************************/
  1072.  
  1073.   int MenuID = SHORT1FROMMP ( mp1 ) ;
  1074.   HWND Menu = HWNDFROMMP ( mp2 ) ;
  1075.  
  1076.  /***************************************************************************
  1077.   * Process according to which menu's about to be displayed.                *
  1078.   ***************************************************************************/
  1079.  
  1080.   switch ( MenuID ) {
  1081.  
  1082.      case FID_SYSMENU:
  1083.      case FID_MENU:
  1084.      case IDM_MENU: {
  1085.         CheckMenuItem ( Menu, IDM_HIDE_CONTROLS, Data->IniData.HideControls ) ;
  1086.         break ; }
  1087.  
  1088.   }
  1089.  
  1090.  /***************************************************************************
  1091.   * We're done.                                                             *
  1092.   ***************************************************************************/
  1093.  
  1094.   return ( 0 ) ;
  1095. }
  1096.  
  1097. /****************************************************************************
  1098.  *                                                                          *
  1099.  *      Process window activation message.                                  *
  1100.  *                                                                          *
  1101.  ****************************************************************************/
  1102.  
  1103. STATIC MRESULT APIENTRY Activate ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1104.  
  1105.  /***************************************************************************
  1106.   * If we're activating, set the active window for help purposes.           *
  1107.   ***************************************************************************/
  1108.  
  1109.   if ( SHORT1FROMMP ( mp1 ) ) 
  1110.      WinSendMsg ( WinQueryHelpInstance(hwnd), HM_SET_ACTIVE_WINDOW, MPFROMHWND(hwnd), MPFROMHWND(hwnd) ) ;
  1111.  
  1112.  /***************************************************************************
  1113.   * We're done.                                                             *
  1114.   ***************************************************************************/
  1115.  
  1116.   return ( 0 ) ;
  1117. }
  1118.  
  1119. /****************************************************************************
  1120.  *                                                                          *
  1121.  *      Process commands received by Main Window                            *
  1122.  *                                                                          *
  1123.  ****************************************************************************/
  1124.  
  1125. STATIC MRESULT APIENTRY Command ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1126.  
  1127.  /***************************************************************************
  1128.   * Dispatch all other commands through the method table.                   *
  1129.   ***************************************************************************/
  1130.  
  1131.   static METHOD Methods [] = {
  1132.     { IDM_SAVE_APPLICATION, SaveApplication },
  1133.     { IDM_RESET_DEFAULTS,   ResetDefaults   },
  1134.     { IDM_HIDE_CONTROLS,    HideControlsCmd },
  1135.     { IDM_CONFIGURE,        Configure       },
  1136.     { IDM_RESETLOAD,        ResetLoad       },
  1137.     { IDM_RESETDRIVES,      ResetDrives     },
  1138.     { IDM_COPY,             Copy            },
  1139.     { IDM_EXIT,             Exit            },
  1140.     { IDM_ABOUT,            About           },
  1141.   } ;
  1142.  
  1143.   return ( DispatchMessage ( hwnd, SHORT1FROMMP(mp1), mp1, mp2, Methods, sizeof(Methods)/sizeof(Methods[0]), 0 ) ) ;
  1144. }
  1145.  
  1146. /****************************************************************************
  1147.  *                                                                          *
  1148.  *      Process Reset Defaults menu command.                                *
  1149.  *                                                                          *
  1150.  ****************************************************************************/
  1151.  
  1152. STATIC MRESULT APIENTRY ResetDefaults ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1153.  
  1154.  /***************************************************************************
  1155.   * Find the instance data.                                                 *
  1156.   ***************************************************************************/
  1157.  
  1158.   PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  1159.  
  1160.  /***************************************************************************
  1161.   * Reset all profile data for this program.                                *
  1162.   ***************************************************************************/
  1163.  
  1164.   PrfWriteProfileData ( Data->IniFile->QueryHandle(), PSZ(PROGRAM_NAME), 0, 0, 0 ) ;
  1165.  
  1166.  /***************************************************************************
  1167.   * Reset the program's presentation parameters.                            *
  1168.   ***************************************************************************/
  1169.  
  1170.   WinRemovePresParam ( hwnd, PP_FONTNAMESIZE ) ;
  1171.   WinRemovePresParam ( hwnd, PP_FOREGROUNDCOLOR ) ;
  1172.   WinRemovePresParam ( hwnd, PP_BACKGROUNDCOLOR ) ;
  1173.  
  1174.  /***************************************************************************
  1175.   * Done.                                                                   *
  1176.   ***************************************************************************/
  1177.  
  1178.   return ( MRFROMSHORT ( 0 ) ) ;
  1179. }
  1180.  
  1181. /****************************************************************************
  1182.  *                                                                          *
  1183.  *      Process Hide Controls menu command.                                 *
  1184.  *                                                                          *
  1185.  ******************m*********************************************************/
  1186.  
  1187. STATIC MRESULT APIENTRY HideControlsCmd ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1188.  
  1189.  /***************************************************************************
  1190.   * Find the instance data.                                                 *
  1191.   ***************************************************************************/
  1192.  
  1193.   PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  1194.  
  1195.  /***************************************************************************
  1196.   * Toggle the Hide Controls setting.                                       *
  1197.   ***************************************************************************/
  1198.  
  1199.   Data->IniData.HideControls = Data->IniData.HideControls ? FALSE : TRUE ;
  1200.   Data->IniData.fHideControls = TRUE ;
  1201.  
  1202.  /***************************************************************************
  1203.   * Get the frame handle.                                                   *
  1204.   ***************************************************************************/
  1205.  
  1206.   HWND Frame = WinQueryWindow ( hwnd, QW_PARENT ) ;
  1207.  
  1208.  /***************************************************************************
  1209.   * If not minimized right now, hide or reveal the controls.                *
  1210.   ***************************************************************************/
  1211.  
  1212.   if ( NOT ( Data->IniData.Position.fl & SWP_MINIMIZE ) ) {
  1213.     HideControls ( Data->IniData.HideControls,
  1214.       Frame, Data->SysMenu, Data->TitleBar, Data->MinMax ) ;
  1215.   }
  1216.  
  1217.  /***************************************************************************
  1218.   * Done.                                                                   *
  1219.   ***************************************************************************/
  1220.  
  1221.   return ( MRFROMSHORT ( 0 ) ) ;
  1222. }
  1223.  
  1224. /****************************************************************************
  1225.  *                                                                          *
  1226.  *      Process Configure command.                                          *
  1227.  *                                                                          *
  1228.  ****************************************************************************/
  1229.  
  1230. STATIC MRESULT APIENTRY Configure ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1231.  
  1232.  /***************************************************************************
  1233.   * Find the instance data.                                                 *
  1234.   ***************************************************************************/
  1235.  
  1236.   PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  1237.  
  1238.  /***************************************************************************
  1239.   * Invoke the Configure dialog.  If cancelled, just return.                *
  1240.   ***************************************************************************/
  1241.  
  1242.   CONFIG_PARMS Parms ;
  1243.   Parms.HideControls        = Data->IniData.HideControls ;
  1244.   Parms.Float               = Data->IniData.Float ;
  1245.   Parms.Animate             = Data->IniData.Animate ;
  1246.   Parms.TableFormat         = Data->IniData.TableFormat ;
  1247.   Parms.Chime               = Data->IniData.Chime ;
  1248.   Parms.ShowRemoteDrives    = Data->IniData.ShowRemoteDrives ;
  1249.   Parms.ShowFileSystemNames = Data->IniData.ShowFileSystemNames ;
  1250.   Parms.ShowDiskLabels      = Data->IniData.ShowDiskLabels ;
  1251.   Parms.ShowSeconds         = Data->IniData.ShowSeconds ;
  1252.   Parms.Hour24              = Data->IniData.Hour24 ;
  1253.   Parms.ShowK               = Data->IniData.ShowK ;
  1254.   Parms.ShowTrueK           = Data->IniData.ShowTrueK ;
  1255.   Parms.ShowM               = Data->IniData.ShowM ;
  1256.   Parms.MonitorPriority     = Data->IniData.MonitorPriority ;
  1257.   Parms.TimerInterval       = Data->IniData.TimerInterval ;
  1258.   Parms.AnchorCorner        = Data->IniData.AnchorCorner ;
  1259.   Parms.NormalBackground    = Data->IniData.BackColor ;
  1260.   Parms.NormalForeground    = Data->IniData.TextColor ;
  1261.   Parms.WarningBackground   = Data->IniData.WarningBackground ;
  1262.   Parms.WarningForeground   = Data->IniData.WarningForeground ;
  1263.   Parms.ErrorBackground     = Data->IniData.ErrorBackground ;
  1264.   Parms.ErrorForeground     = Data->IniData.ErrorForeground ;
  1265.   Parms.ItemCount           = Data->IniData.ItemCount ;
  1266.  
  1267.   for ( int i=0; i<Data->IniData.ItemCount; i++ ) {
  1268.      Item *pItem = Data->IniData.Items[i] ;
  1269.      Parms.ItemFlags[i] = pItem->QueryFlag () ;
  1270.      strcpy ( Parms.CurrentLabels[i], PCHAR(pItem->QueryCurrentLabel()) ) ;
  1271.      strcpy ( Parms.DefaultLabels[i], PCHAR(pItem->QueryDefaultLabel()) ) ;
  1272.      pItem->QueryDefaultLevels ( Parms.DefaultLevels[i][0], Parms.DefaultLevels[i][1] ) ;
  1273.      Parms.WarningLevel[i] = pItem->QueryWarningLevel() ;
  1274.      Parms.ErrorLevel[i] = pItem->QueryErrorLevel() ;
  1275.      Parms.LevelSense[i] = pItem->QueryLevelSense() ;
  1276.      Parms.MinLevel[i] = pItem->QueryMinLevel() ;
  1277.      Parms.MaxLevel[i] = pItem->QueryMaxLevel() ;
  1278.   } /* endfor */
  1279.  
  1280.   Parms.MainWindow = hwnd ;
  1281.  
  1282.   Data->DialogWindow = WinLoadDlg ( HWND_DESKTOP, hwnd, ConfigureProcessor, Data->Library->QueryHandle(), IDD_CONFIGURE, &Parms ) ;
  1283.   if ( Data->DialogWindow ) {
  1284.      if ( WinProcessDlg ( Data->DialogWindow ) ) {
  1285.         UpdateParms ( hwnd, WM_UPDATEPARMS, MPFROMP(&Parms), 0 ) ;
  1286.      } /* endif */
  1287.      WinDestroyWindow ( Data->DialogWindow ) ;
  1288.      Data->DialogWindow = 0 ;
  1289.   } /* endif */
  1290.  
  1291.  /***************************************************************************
  1292.   * Done.                                                                   *
  1293.   ***************************************************************************/
  1294.  
  1295.   return ( MRFROMSHORT ( 0 ) ) ;
  1296. }
  1297.  
  1298. /****************************************************************************
  1299.  *                                                                          *
  1300.  *      Process Reset Load menu command.                                    *
  1301.  *                                                                          *
  1302.  ****************************************************************************/
  1303.  
  1304. STATIC MRESULT APIENTRY ResetLoad ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1305.  
  1306.  /***************************************************************************
  1307.   * Find the instance data.                                                 *
  1308.   ***************************************************************************/
  1309.  
  1310.   PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  1311.  
  1312.  /***************************************************************************
  1313.   * Shut down the CPU load meter threads.                                   *
  1314.   ***************************************************************************/
  1315.  
  1316.   DosResumeThread ( Data->MonitorTID ) ;
  1317.   Data->MonitorParms.Active = FALSE ;
  1318.   MonitorThreadEvent.Wait ( 10000 ) ;
  1319.  
  1320.   DosResumeThread ( Data->CounterTID ) ;
  1321.   Data->CounterParms.Active = FALSE ;
  1322.   DosSetPriority ( PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, Data->CounterTID ) ;
  1323.   CounterThreadEvent.Wait ( 10000 ) ;
  1324.  
  1325.  /***************************************************************************
  1326.   * Reset the load meter.                                                   *
  1327.   ***************************************************************************/
  1328.  
  1329.   Data->IniData.MaxCount = CalibrateLoadMeter ( &Data->CounterParms ) ;
  1330.   Data->IniData.MaxCount = (ULONG) max ( 1, Data->IniData.MaxCount ) ;
  1331.  
  1332.  /***************************************************************************
  1333.   * Restart the CPU load meter threads.                                     *
  1334.   ***************************************************************************/
  1335.  
  1336.   CounterThreadEvent.Reset ( ) ;
  1337.   Data->CounterParms.Active = TRUE ;
  1338.   Data->CounterTID = StartThread ( "CounterThread", CounterThread, 0x3000, &Data->CounterParms ) ;
  1339.   DosSuspendThread ( Data->CounterTID ) ;
  1340.   DosSetPriority ( PRTYS_THREAD, PRTYC_IDLETIME, PRTYD_MINIMUM, Data->CounterTID ) ;
  1341.  
  1342.   Data->IniData.IdleCount = 0 ;
  1343.   Data->CounterParms.Counter = 0 ;
  1344.  
  1345.   if ( Data->IniData.Items[ITEM_CPULOAD]->QueryFlag() )
  1346.      DosResumeThread ( Data->CounterTID ) ;
  1347.  
  1348.   MonitorThreadEvent.Reset ( ) ;
  1349.   Data->MonitorParms.Active = TRUE ;
  1350.   Data->MonitorParms.Counter = & Data->CounterParms.Counter ;
  1351.   Data->MonitorParms.Interval = & Data->IniData.TimerInterval ;
  1352.   Data->MonitorParms.Priority = & Data->IniData.MonitorPriority ;
  1353.   Data->MonitorParms.Owner = hwnd ;
  1354.   Data->MonitorTID = StartThread ( "MonitorLoopThread", MonitorLoopThread, 0x3000, &Data->MonitorParms ) ;
  1355.  
  1356.  /***************************************************************************
  1357.   * Done.                                                                   *
  1358.   ***************************************************************************/
  1359.  
  1360.   return ( MRFROMSHORT ( 0 ) ) ;
  1361. }
  1362.  
  1363. /****************************************************************************
  1364.  *                                                                          *
  1365.  *      Process Reset Drives command.                                       *
  1366.  *                                                                          *
  1367.  ****************************************************************************/
  1368.  
  1369. STATIC MRESULT APIENTRY ResetDrives ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1370.  
  1371.   /**************************************************************************
  1372.    * Find the instance data.                                                *
  1373.    **************************************************************************/
  1374.  
  1375.    PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  1376.  
  1377.   /**************************************************************************
  1378.    * Reset all the drive error flags.                                       *
  1379.    **************************************************************************/
  1380.  
  1381.    for ( int i=ITEM_BASE_COUNT; i<Data->IniData.ItemCount; i++ ) {
  1382.       Item *pItem = Data->IniData.Items[i] ;
  1383.       ((DriveFree*)pItem)->ResetError ( ) ;
  1384.    } /* endfor */
  1385.  
  1386.   /**************************************************************************
  1387.    * Recheck all drives, except those specifically excluded.                *
  1388.    **************************************************************************/
  1389.  
  1390.    ULONG Drives = 0x03FFFFFF ;
  1391.    Drives &= ~Data->Exclude ;
  1392.    if ( UpdateDriveList ( Data->Proc->QueryAnchor(), Data->Library->QueryHandle(), Data->IniFile->QueryHandle(),
  1393.       &Data->IniData, Data->pDdeServer, Data->Drives, Drives, Data->Drives, Data->Exclude ) )
  1394.       if ( Data->DialogWindow ) 
  1395.          WinSendMsg ( Data->DialogWindow, WM_UPDATEDRIVES, MPFROMP(&Data->IniData), 0 ) ;
  1396.  
  1397.   /**************************************************************************
  1398.    * Done.                                                                  *
  1399.    **************************************************************************/
  1400.  
  1401.    return ( MRFROMSHORT ( 0 ) ) ;
  1402. }
  1403.  
  1404. /****************************************************************************
  1405.  *                                                                          *
  1406.  *      Process Copy command.                                               *
  1407.  *                                                                          *
  1408.  ****************************************************************************/
  1409.  
  1410. STATIC MRESULT APIENTRY Copy ( HWND Window, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1411.  
  1412.   /**************************************************************************
  1413.    * Find the instance data.                                                *
  1414.    **************************************************************************/
  1415.  
  1416.    PDATA Data = PDATA ( WinQueryWindowPtr ( Window, QWL_USER ) ) ;
  1417.  
  1418.   /**************************************************************************
  1419.    * Review all items.  Display those changed, or all.                      *
  1420.    **************************************************************************/
  1421.  
  1422.    char *Buffer = (char*) malloc ( ( ITEM_BASE_COUNT + MAX_DRIVES ) * ( Data->MaxColumns + 1 ) ) ;
  1423.    Buffer [0] = 0 ;
  1424.  
  1425.    for ( int i=0; i<Data->IniData.ItemCount; i++ ) {
  1426.       Item *pItem = Data->IniData.Items[i] ;
  1427.       if ( pItem->QueryFlag() ) {
  1428.          pItem->FormatLine ( Buffer, Data->MaxColumns ) ;
  1429.       } /* endif */
  1430.    } /* endfor */
  1431.  
  1432.    char *ClipText ;
  1433.    DosAllocSharedMem ( PPVOID(&ClipText), 0, strlen(Buffer)+1,
  1434.       PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE ) ;
  1435.    strcpy ( ClipText, Buffer ) ;
  1436.    free ( Buffer ) ;
  1437.  
  1438.   /**************************************************************************
  1439.    * Create bitmap image of current window.                                 *
  1440.    **************************************************************************/
  1441.  
  1442.    static PSZ pszData [2] = { 0, PSZ("Display") } ;
  1443.    HDC MemoryDC = DevOpenDC ( Data->Proc->QueryAnchor(), OD_MEMORY, PSZ("*"), 2, PDEVOPENDATA(pszData), 0 ) ;
  1444.  
  1445.    SIZEL PageSize = { 0, 0 } ;
  1446.    HPS hPS = GpiCreatePS ( Data->Proc->QueryAnchor(), MemoryDC, &PageSize, PU_PELS | GPIA_ASSOC | GPIT_MICRO ) ;
  1447.    GpiCreateLogColorTable ( hPS, LCOL_RESET, LCOLF_RGB, 0, 0, 0 ) ;
  1448.    GpiSetCp ( hPS, Data->CodePage ) ;
  1449.  
  1450.    LONG alData [2] ;
  1451.    GpiQueryDeviceBitmapFormats ( hPS, 2, alData ) ;
  1452.  
  1453.    RECTL Rectangle ;
  1454.    WinQueryWindowRect ( Window, &Rectangle ) ;
  1455.  
  1456.    BITMAPINFOHEADER2 BitmapHeader ;
  1457.    memset ( &BitmapHeader, 0, sizeof(BitmapHeader) ) ;
  1458.    BitmapHeader.cbFix = 16 ;
  1459.    BitmapHeader.cx = Rectangle.xRight - Rectangle.xLeft ;
  1460.    BitmapHeader.cy = Rectangle.yTop - Rectangle.yBottom ;
  1461.    BitmapHeader.cPlanes = USHORT ( alData[0] ) ;
  1462.    BitmapHeader.cBitCount = USHORT ( alData[1] ) ;
  1463.  
  1464.    HBITMAP Bitmap = GpiCreateBitmap ( hPS, &BitmapHeader, 0, 0, 0 ) ;
  1465.    GpiSetBitmap ( hPS, Bitmap ) ;
  1466.  
  1467.    FATTRS FontAttributes ;
  1468.    memset ( &FontAttributes, 0, sizeof(FontAttributes) ) ;
  1469.    strcpy ( FontAttributes.szFacename, Data->FontMetrics.szFacename ) ;
  1470.    FontAttributes.usRecordLength  = sizeof(FontAttributes) ;
  1471.    FontAttributes.usCodePage      = Data->FontMetrics.usCodePage ;
  1472.    FontAttributes.lMaxBaselineExt = Data->FontMetrics.lMaxBaselineExt ;
  1473.    FontAttributes.lAveCharWidth   = Data->FontMetrics.lAveCharWidth ;
  1474.  
  1475.    GpiCreateLogFont ( hPS, 0, 1, &FontAttributes ) ;
  1476.    GpiSetCharSet ( hPS, 1 ) ;
  1477.    GpiSetCharMode ( hPS, Data->CharMode ) ;
  1478.    if ( Data->CharMode == CM_MODE3 )
  1479.       GpiSetCharBox ( hPS, &Data->CharBox ) ;
  1480.  
  1481.    GpiMove ( hPS, PPOINTL(&Rectangle.xLeft) ) ;
  1482.    GpiSetColor ( hPS, Data->IniData.BackColor ) ;
  1483.    GpiBox ( hPS, DRO_FILL, PPOINTL(&Rectangle.xRight), 0, 0 ) ;
  1484.  
  1485.    int Count = 0 ;
  1486.    for ( i=0; i<Data->IniData.ItemCount; i++ ) {
  1487.       Item *pItem = Data->IniData.Items[i] ;
  1488.       if ( pItem->QueryFlag() ) {
  1489.          Count ++ ;
  1490.       } /* endif */
  1491.    } /* endfor */
  1492.  
  1493.    Rectangle.xLeft += Data->Height / 2 ;
  1494.    Rectangle.xRight -= Data->Height / 2 ;
  1495.  
  1496.    Rectangle.yBottom = Data->Height * ( Count - 1 ) ;
  1497.    Rectangle.yTop = Rectangle.yBottom + Data->Height ;
  1498.  
  1499.    int Row = 0, Column = 0 ;
  1500.    for ( i=0; i<Data->IniData.ItemCount; i++ ) {
  1501.       RECTL Rectangle ;
  1502.       Rectangle.xLeft = Data->ColumnWidth*Column + Data->Height/2 ;
  1503.       Rectangle.xRight = Rectangle.xLeft + Data->ColumnWidth - Data->Height ;
  1504.       Rectangle.yBottom = Data->Height * ( Data->Rows - Row - 1 ) ;
  1505.       Rectangle.yTop = Rectangle.yBottom + Data->Height ;
  1506.       Item *pItem = Data->IniData.Items[i] ;
  1507.       if ( pItem->QueryFlag() ) {
  1508.          pItem->Repaint ( hPS, Rectangle, TRUE ) ;
  1509.          Row ++ ;
  1510.          if ( Row >= Data->Rows ) {
  1511.             Row = 0 ;
  1512.             Column ++ ;
  1513.          } /* endif */
  1514.       } /* endif */
  1515.    } /* endfor */
  1516.  
  1517.    if ( Data->Columns > 1 ) {
  1518.       GpiSetColor ( hPS, Data->BorderColor ) ;
  1519.       for ( i=1; i<Data->Columns; i++ ) {
  1520.          POINTL Point = { Data->ColumnWidth*i-1, Rectangle.yBottom } ;
  1521.          GpiMove ( hPS, &Point ) ;
  1522.          Point.y = Rectangle.yTop ;
  1523.          GpiLine ( hPS, &Point ) ;
  1524.       } /* endfor */
  1525.    } /* endif */
  1526.  
  1527.    GpiDestroyPS ( hPS ) ;
  1528.    DevCloseDC ( MemoryDC ) ;
  1529.  
  1530.   /**************************************************************************
  1531.    * Empty the clipboard and give it new data.                              *
  1532.    **************************************************************************/
  1533.  
  1534.    if ( WinOpenClipbrd ( Data->Proc->QueryAnchor() ) ) {
  1535.       WinEmptyClipbrd ( Data->Proc->QueryAnchor() ) ;
  1536.       WinSetClipbrdData ( Data->Proc->QueryAnchor(), ULONG(ClipText), CF_TEXT, CFI_POINTER ) ;
  1537.       WinSetClipbrdData ( Data->Proc->QueryAnchor(), ULONG(Bitmap), CF_BITMAP, CFI_HANDLE ) ;
  1538.       WinCloseClipbrd ( Data->Proc->QueryAnchor() ) ;
  1539.    } else {
  1540.       DosFreeMem ( ClipText ) ;
  1541.    } /* endif */
  1542.  
  1543.   /**************************************************************************
  1544.    * Done.                                                                  *
  1545.    **************************************************************************/
  1546.  
  1547.    return ( MRFROMSHORT ( 0 ) ) ;
  1548. }
  1549.  
  1550. /****************************************************************************
  1551.  *                                                                          *
  1552.  *      Process About menu command.                                         *
  1553.  *                                                                          *
  1554.  ****************************************************************************/
  1555.  
  1556. STATIC MRESULT APIENTRY About ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1557.  
  1558.   /**************************************************************************
  1559.    * Find the instance data.                                                *
  1560.    **************************************************************************/
  1561.  
  1562.    PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  1563.  
  1564.   /**************************************************************************
  1565.    * Invoke the About dialog.                                               *
  1566.    **************************************************************************/
  1567.  
  1568.    WinDlgBox ( HWND_DESKTOP, hwnd, PFNWP(AboutProcessor),
  1569.       Data->Library->QueryHandle(), IDD_ABOUT, 0 ) ;
  1570.  
  1571.   /**************************************************************************
  1572.    * Done.                                                                  *
  1573.    **************************************************************************/
  1574.  
  1575.    return ( MRFROMSHORT ( 0 ) ) ;
  1576. }
  1577.  
  1578. /****************************************************************************
  1579.  *                                                                          *
  1580.  *      Process Begin Drag message.                                         *
  1581.  *                                                                          *
  1582.  ****************************************************************************/
  1583.  
  1584. STATIC MRESULT APIENTRY BeginDrag ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1585.  
  1586.   /**************************************************************************
  1587.    * Determine the new window position.                                     *
  1588.    **************************************************************************/
  1589.  
  1590.    TRACKINFO TrackInfo ;
  1591.    memset ( &TrackInfo, 0, sizeof(TrackInfo) ) ;
  1592.  
  1593.    TrackInfo.cxBorder = 1 ;
  1594.    TrackInfo.cyBorder = 1 ;
  1595.    TrackInfo.cxGrid = 1 ;
  1596.    TrackInfo.cyGrid = 1 ;
  1597.    TrackInfo.cxKeyboard = 8 ;
  1598.    TrackInfo.cyKeyboard = 8 ;
  1599.  
  1600.    HWND Frame = WinQueryWindow ( hwnd, QW_PARENT ) ;
  1601.  
  1602.    SWP Position ;
  1603.    WinQueryWindowPos ( Frame, &Position ) ;
  1604.    TrackInfo.rclTrack.xLeft   = Position.x ;
  1605.    TrackInfo.rclTrack.xRight  = Position.x + Position.cx ;
  1606.    TrackInfo.rclTrack.yBottom = Position.y ;
  1607.    TrackInfo.rclTrack.yTop    = Position.y + Position.cy ;
  1608.  
  1609.    WinQueryWindowPos ( HWND_DESKTOP, &Position ) ;
  1610.    TrackInfo.rclBoundary.xLeft   = Position.x ;
  1611.    TrackInfo.rclBoundary.xRight  = Position.x + Position.cx ;
  1612.    TrackInfo.rclBoundary.yBottom = Position.y ;
  1613.    TrackInfo.rclBoundary.yTop    = Position.y + Position.cy ;
  1614.  
  1615.    TrackInfo.ptlMinTrackSize.x = 0 ;
  1616.    TrackInfo.ptlMinTrackSize.y = 0 ;
  1617.    TrackInfo.ptlMaxTrackSize.x = Position.cx ;
  1618.    TrackInfo.ptlMaxTrackSize.y = Position.cy ;
  1619.  
  1620.    TrackInfo.fs = TF_MOVE | TF_STANDARD | TF_ALLINBOUNDARY ;
  1621.  
  1622.    if ( WinTrackRect ( HWND_DESKTOP, 0, &TrackInfo ) ) 
  1623.       WinSetWindowPos ( Frame, 0, TrackInfo.rclTrack.xLeft, TrackInfo.rclTrack.yBottom, 0, 0, SWP_MOVE ) ;
  1624.  
  1625.   /**************************************************************************
  1626.    * Done.                                                                  *
  1627.    **************************************************************************/
  1628.  
  1629.    return ( 0 ) ;
  1630. }
  1631.  
  1632. /****************************************************************************
  1633.  *                                                                          *
  1634.  *      Process Mouse Button having been double-clicked.                    *
  1635.  *                                                                          *
  1636.  ****************************************************************************/
  1637.  
  1638. STATIC MRESULT APIENTRY ButtonDblClick ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1639.  
  1640.   /**************************************************************************
  1641.    * Send message to self to stop hiding the controls.                      *
  1642.    **************************************************************************/
  1643.  
  1644.    WinPostMsg ( hwnd, WM_COMMAND,
  1645.       MPFROM2SHORT ( IDM_HIDE_CONTROLS, 0 ),
  1646.       MPFROM2SHORT ( CMDSRC_OTHER, TRUE ) ) ;
  1647.  
  1648.   /**************************************************************************
  1649.    * We're done here.                                                       *
  1650.    **************************************************************************/
  1651.  
  1652.    return ( 0 ) ;
  1653. }
  1654.  
  1655. /****************************************************************************
  1656.  *                                                                          *
  1657.  *      Process Presentation Parameter Changed notification.                *
  1658.  *                                                                          *
  1659.  ****************************************************************************/
  1660.  
  1661. STATIC MRESULT APIENTRY ContextMenu ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1662.  
  1663.   /**************************************************************************
  1664.    * Find the instance data.                                                *
  1665.    **************************************************************************/
  1666.  
  1667.    PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  1668.  
  1669.   /**************************************************************************
  1670.    * Invoke the window's context menu.                                      *
  1671.    **************************************************************************/
  1672.  
  1673.    WinSetPresParam ( Data->Menu, PP_FONTNAMESIZE,
  1674.       Data->IniData.fFontNameSize ? strlen(Data->IniData.FontNameSize)+1 : 0,
  1675.       Data->IniData.fFontNameSize ? PSZ(Data->IniData.FontNameSize) : PSZ("") ) ;
  1676.  
  1677.    WinPopupMenu ( hwnd, hwnd, Data->Menu, SHORT1FROMMP(mp1), SHORT2FROMMP(mp1),
  1678.       0, PU_HCONSTRAIN | PU_VCONSTRAIN | PU_KEYBOARD | PU_MOUSEBUTTON1 ) ;
  1679.  
  1680.   /**************************************************************************
  1681.    * Done.                                                                  *
  1682.    **************************************************************************/
  1683.  
  1684.    return ( 0 ) ;
  1685. }
  1686.  
  1687. /****************************************************************************
  1688.  *                                                                          *
  1689.  *      Process Presentation Parameter Changed notification.                *
  1690.  *                                                                          *
  1691.  ****************************************************************************/
  1692.  
  1693. STATIC MRESULT APIENTRY PresParamChanged ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1694.  
  1695.  /***************************************************************************
  1696.   * Find the instance data.                                                 *
  1697.   ***************************************************************************/
  1698.  
  1699.   PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  1700.  
  1701.  /***************************************************************************
  1702.   * Get the presentation parameter that changed.                            *
  1703.   ***************************************************************************/
  1704.  
  1705.   switch ( LONGFROMMP(mp1) ) {
  1706.  
  1707.    /*************************************************************************
  1708.     * If font, note the fact that we now have a font to be saved as         *
  1709.     *   part of the configuration.  Get the font metrics and resize         *
  1710.     *   the window appropriately.                                           *
  1711.     *************************************************************************/
  1712.  
  1713.     case PP_FONTNAMESIZE: {
  1714.        ULONG ppid ;
  1715.        if ( WinQueryPresParam ( hwnd, PP_FONTNAMESIZE, 0, &ppid,
  1716.           sizeof(Data->IniData.FontNameSize), &Data->IniData.FontNameSize, 0 ) ) {
  1717.           Data->IniData.fFontNameSize = TRUE ;
  1718.        } else {
  1719.           strcpy ( PCHAR(Data->IniData.FontNameSize), "" ) ;
  1720.           Data->IniData.fFontNameSize = FALSE ;
  1721.           PrfWriteProfileData ( Data->IniFile->QueryHandle(), PSZ(PROGRAM_NAME), PSZ("FontNameSize"), NULL, 0 ) ;
  1722.        } /* endif */
  1723.  
  1724.        HPS hPS = WinGetPS ( hwnd ) ;
  1725.        RECTL Rectangle ;
  1726.        WinQueryWindowRect ( HWND_DESKTOP, &Rectangle ) ;
  1727.        WinDrawText ( hPS, 1, PSZ(" "), &Rectangle, 0, 0, DT_LEFT | DT_BOTTOM | DT_QUERYEXTENT ) ;
  1728.        Data->Width  = Rectangle.xRight - Rectangle.xLeft ;
  1729.        Data->Height = Rectangle.yTop - Rectangle.yBottom ;
  1730.        WinReleasePS ( hPS ) ;
  1731.        ResizeWindow ( hwnd ) ;
  1732.        break ;
  1733.     } /* endcase */
  1734.  
  1735.    /*************************************************************************
  1736.     * If background color, note the fact and repaint the window.            *
  1737.     *************************************************************************/
  1738.  
  1739.     case PP_BACKGROUNDCOLOR: {
  1740.        ULONG ppid ;
  1741.        if ( WinQueryPresParam ( hwnd, PP_BACKGROUNDCOLOR, 0, &ppid,
  1742.           sizeof(Data->IniData.BackColor), &Data->IniData.BackColor, 0 ) ) {
  1743.           Data->IniData.fBackColor = TRUE ;
  1744.        } else {
  1745.           Data->IniData.BackColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_WINDOW, 0 ) ;
  1746.           Data->IniData.fBackColor = FALSE ;
  1747.           PrfWriteProfileData ( Data->IniFile->QueryHandle(), PSZ(PROGRAM_NAME), PSZ("BackgroundColor"), NULL, 0 ) ;
  1748.        } /* endif */
  1749.        for ( int i=0; i<Data->IniData.ItemCount; i++ ) {
  1750.            Item *pItem = Data->IniData.Items[i] ;
  1751.            pItem->SetNormalColors  ( Data->IniData.BackColor, Data->IniData.TextColor ) ;
  1752.        } /* endfor */
  1753.        WinInvalidateRect ( hwnd, 0, TRUE ) ;
  1754.        break ;
  1755.     } /* endcase */
  1756.  
  1757.    /*************************************************************************
  1758.     * If foreground color, note the fact and repaint the window.            *
  1759.     *************************************************************************/
  1760.  
  1761.     case PP_FOREGROUNDCOLOR: {
  1762.        ULONG ppid ;
  1763.        if ( WinQueryPresParam ( hwnd, PP_FOREGROUNDCOLOR, 0, &ppid,
  1764.           sizeof(Data->IniData.TextColor), &Data->IniData.TextColor, 0 ) ) {
  1765.           Data->IniData.fTextColor = TRUE ;
  1766.        } else {
  1767.           Data->IniData.TextColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_OUTPUTTEXT, 0 ) ;
  1768.           Data->IniData.fTextColor = FALSE ;
  1769.           PrfWriteProfileData ( Data->IniFile->QueryHandle(), PSZ(PROGRAM_NAME), PSZ("ForegroundColor"), NULL, 0 ) ;
  1770.        } /* endif */
  1771.        for ( int i=0; i<Data->IniData.ItemCount; i++ ) {
  1772.            Item *pItem = Data->IniData.Items[i] ;
  1773.            pItem->SetNormalColors  ( Data->IniData.BackColor, Data->IniData.TextColor ) ;
  1774.        } /* endfor */
  1775.        WinInvalidateRect ( hwnd, 0, TRUE ) ;
  1776.        break ;
  1777.     } /* endcase */
  1778.  
  1779.   }
  1780.  
  1781.  /***************************************************************************
  1782.   * Return through the default processor, letting window activation         *
  1783.   *   and other system functions occur.                                     *
  1784.   ***************************************************************************/
  1785.  
  1786.   return ( WinDefWindowProc ( hwnd, msg, mp1, mp2 ) ) ;
  1787. }
  1788.  
  1789. /****************************************************************************
  1790.  *                                                                          *
  1791.  *      Process System Color Change notification.                           *
  1792.  *                                                                          *
  1793.  ****************************************************************************/
  1794.  
  1795. STATIC MRESULT APIENTRY SysColorChange ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1796.  
  1797.   /**************************************************************************
  1798.    * Find the instance data.                                                *
  1799.    **************************************************************************/
  1800.  
  1801.    PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  1802.  
  1803.   /**************************************************************************
  1804.    * If we aren't using custom colors, then query for the new defaults.     *
  1805.    **************************************************************************/
  1806.  
  1807.    if ( NOT Data->IniData.fBackColor ) 
  1808.       Data->IniData.BackColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_WINDOW, 0 ) ;
  1809.  
  1810.    if ( NOT Data->IniData.fTextColor ) 
  1811.       Data->IniData.TextColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_OUTPUTTEXT, 0 ) ;
  1812.  
  1813.    Data->BorderColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_WINDOWFRAME, 0 ) ;
  1814.  
  1815.   /**************************************************************************
  1816.    * Update all the item colors.                                            *
  1817.    **************************************************************************/
  1818.  
  1819.    for ( int i=0; i<Data->IniData.ItemCount; i++ ) {
  1820.       Item *pItem = Data->IniData.Items[i] ;
  1821.       pItem->SetNormalColors  ( Data->IniData.BackColor, Data->IniData.TextColor ) ;
  1822.    } /* endfor */
  1823.  
  1824.   /**************************************************************************
  1825.    * Return value must be NULL, according to the documentation.             *
  1826.    **************************************************************************/
  1827.  
  1828.    return ( 0 ) ;
  1829. }
  1830.  
  1831. /****************************************************************************
  1832.  *                                                                          *
  1833.  *      Process Query for Keys Help resource id.                            *
  1834.  *                                                                          *
  1835.  ****************************************************************************/
  1836.  
  1837. STATIC MRESULT APIENTRY QueryKeysHelp ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1838.  
  1839.   /**************************************************************************
  1840.    * Simply return the ID of the Keys Help panel.                           *
  1841.    **************************************************************************/
  1842.  
  1843.    return ( (MRESULT) IDM_KEYS_HELP ) ;
  1844. }
  1845.  
  1846. /****************************************************************************
  1847.  *                                                                          *
  1848.  *      Process Help Manager Error                                          *
  1849.  *                                                                          *
  1850.  ****************************************************************************/
  1851.  
  1852. STATIC MRESULT APIENTRY HelpError ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1853.  
  1854.   /**************************************************************************
  1855.    * Local Declarations                                                     *
  1856.    **************************************************************************/
  1857.  
  1858.    static struct {
  1859.       ULONG Error ;
  1860.       USHORT StringId ;
  1861.    } HelpErrors [] = {
  1862.       { HMERR_NO_FRAME_WND_IN_CHAIN,     IDS_HMERR_NO_FRAME_WND_IN_CHAIN },
  1863.       { HMERR_INVALID_ASSOC_APP_WND,     IDS_HMERR_INVALID_ASSOC_APP_WND },
  1864.       { HMERR_INVALID_ASSOC_HELP_INST,   IDS_HMERR_INVALID_ASSOC_HELP_IN },
  1865.       { HMERR_INVALID_DESTROY_HELP_INST, IDS_HMERR_INVALID_DESTROY_HELP_ },
  1866.       { HMERR_NO_HELP_INST_IN_CHAIN,     IDS_HMERR_NO_HELP_INST_IN_CHAIN },
  1867.       { HMERR_INVALID_HELP_INSTANCE_HDL, IDS_HMERR_INVALID_HELP_INSTANCE },
  1868.       { HMERR_INVALID_QUERY_APP_WND,     IDS_HMERR_INVALID_QUERY_APP_WND },
  1869.       { HMERR_HELP_INST_CALLED_INVALID,  IDS_HMERR_HELP_INST_CALLED_INVA },
  1870.       { HMERR_HELPTABLE_UNDEFINE,        IDS_HMERR_HELPTABLE_UNDEFINE    },
  1871.       { HMERR_HELP_INSTANCE_UNDEFINE,    IDS_HMERR_HELP_INSTANCE_UNDEFIN },
  1872.       { HMERR_HELPITEM_NOT_FOUND,        IDS_HMERR_HELPITEM_NOT_FOUND    },
  1873.       { HMERR_INVALID_HELPSUBITEM_SIZE,  IDS_HMERR_INVALID_HELPSUBITEM_S },
  1874.       { HMERR_HELPSUBITEM_NOT_FOUND,     IDS_HMERR_HELPSUBITEM_NOT_FOUND },
  1875.       { HMERR_INDEX_NOT_FOUND,           IDS_HMERR_INDEX_NOT_FOUND       },
  1876.       { HMERR_CONTENT_NOT_FOUND,         IDS_HMERR_CONTENT_NOT_FOUND     },
  1877.       { HMERR_OPEN_LIB_FILE,             IDS_HMERR_OPEN_LIB_FILE         },
  1878.       { HMERR_READ_LIB_FILE,             IDS_HMERR_READ_LIB_FILE         },
  1879.       { HMERR_CLOSE_LIB_FILE,            IDS_HMERR_CLOSE_LIB_FILE        },
  1880.       { HMERR_INVALID_LIB_FILE,          IDS_HMERR_INVALID_LIB_FILE      },
  1881.       { HMERR_NO_MEMORY,                 IDS_HMERR_NO_MEMORY             },
  1882.       { HMERR_ALLOCATE_SEGMENT,          IDS_HMERR_ALLOCATE_SEGMENT      },
  1883.       { HMERR_FREE_MEMORY,               IDS_HMERR_FREE_MEMORY           },
  1884.       { HMERR_PANEL_NOT_FOUND,           IDS_HMERR_PANEL_NOT_FOUND       },
  1885.       { HMERR_DATABASE_NOT_OPEN,         IDS_HMERR_DATABASE_NOT_OPEN     },
  1886.       { 0,                               IDS_HMERR_UNKNOWN               }
  1887.    } ;
  1888.  
  1889.    ULONG ErrorCode = (ULONG) LONGFROMMP ( mp1 ) ;
  1890.  
  1891.   /**************************************************************************
  1892.    * Find the instance data.                                                *
  1893.    **************************************************************************/
  1894.  
  1895.    PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  1896.  
  1897.   /**************************************************************************
  1898.    * Find the error code in the message table.                              *
  1899.    **************************************************************************/
  1900.  
  1901.    int Index = 0 ;
  1902.    while ( HelpErrors[Index].Error AND ( HelpErrors[Index].Error != ErrorCode ) ) 
  1903.       Index ++ ;
  1904.  
  1905.   /**************************************************************************
  1906.    * Get the message texts.                                                 *
  1907.    **************************************************************************/
  1908.  
  1909.    ResourceString Title ( Data->Library->QueryHandle(), IDS_HMERR ) ;
  1910.  
  1911.    ResourceString Message ( Data->Library->QueryHandle(), HelpErrors[Index].StringId ) ;
  1912.  
  1913.   /**************************************************************************
  1914.    * Display the error message.                                             *
  1915.    **************************************************************************/
  1916.  
  1917.    WinMessageBox ( HWND_DESKTOP, hwnd, PSZ(Message), PSZ(Title), 0, MB_OK | MB_WARNING ) ;
  1918.  
  1919.   /**************************************************************************
  1920.    * Return zero, indicating that the message was processed.                *
  1921.    **************************************************************************/
  1922.  
  1923.    return ( MRFROMSHORT ( 0 ) ) ;
  1924. }
  1925.  
  1926. /****************************************************************************
  1927.  *                                                                          *
  1928.  *      Process "Extended Help Undefined" notification                      *
  1929.  *                                                                          *
  1930.  ****************************************************************************/
  1931.  
  1932. STATIC MRESULT APIENTRY ExtHelpUndefined ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1933.  
  1934.   /**************************************************************************
  1935.    * Find the instance data.                                                *
  1936.    **************************************************************************/
  1937.  
  1938.    PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  1939.  
  1940.   /**************************************************************************
  1941.    * Get the message texts.                                                 *
  1942.    **************************************************************************/
  1943.  
  1944.    ResourceString Title ( Data->Library->QueryHandle(), IDS_HMERR ) ;
  1945.  
  1946.    ResourceString Message ( Data->Library->QueryHandle(), IDS_HMERR_EXTHELPUNDEFINED ) ;
  1947.  
  1948.   /**************************************************************************
  1949.    * Display the error message.                                             *
  1950.    **************************************************************************/
  1951.  
  1952.    WinMessageBox ( HWND_DESKTOP, hwnd, PSZ(Message), PSZ(Title), 0, MB_OK | MB_WARNING ) ;
  1953.  
  1954.   /**************************************************************************
  1955.    * Return zero, indicating that the message was processed.                *
  1956.    **************************************************************************/
  1957.  
  1958.    return ( MRFROMSHORT ( 0 ) ) ;
  1959. }
  1960.  
  1961. /****************************************************************************
  1962.  *                                                                          *
  1963.  *      Process "Help Subitem Not Found" notification                       *
  1964.  *                                                                          *
  1965.  ****************************************************************************/
  1966.  
  1967. STATIC MRESULT APIENTRY HelpSubitemNotFound ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  1968.  
  1969.   /**************************************************************************
  1970.    * Find the instance data.                                                *
  1971.    **************************************************************************/
  1972.  
  1973.    PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  1974.  
  1975.   /**************************************************************************
  1976.    * Get the title text.                                                    *
  1977.    **************************************************************************/
  1978.  
  1979.    ResourceString Title ( Data->Library->QueryHandle(), IDS_HMERR ) ;
  1980.  
  1981.   /**************************************************************************
  1982.    * Format the error message.                                              *
  1983.    **************************************************************************/
  1984.  
  1985.    USHORT Topic = (USHORT) SHORT1FROMMP ( mp2 ) ;
  1986.    USHORT Subtopic = (USHORT) SHORT2FROMMP ( mp2 ) ;
  1987.  
  1988.    ResourceString Frame   ( Data->Library->QueryHandle(), IDS_HELPMODE_FRAME ) ;
  1989.    ResourceString Menu    ( Data->Library->QueryHandle(), IDS_HELPMODE_MENU ) ;
  1990.    ResourceString Window  ( Data->Library->QueryHandle(), IDS_HELPMODE_WINDOW ) ;
  1991.    ResourceString Unknown ( Data->Library->QueryHandle(), IDS_HELPMODE_UNKNOWN ) ; 
  1992.  
  1993.    PBYTE Mode ;
  1994.    switch ( SHORT1FROMMP ( mp1 ) ) {
  1995.       case HLPM_FRAME:
  1996.          Mode = PSZ(Frame) ;
  1997.          break ;
  1998.  
  1999.       case HLPM_MENU:
  2000.          Mode = PSZ(Menu) ;
  2001.          break ;
  2002.  
  2003.       case HLPM_WINDOW:
  2004.          Mode = PSZ(Window) ;
  2005.          break ;
  2006.  
  2007.       default:
  2008.          Mode = PSZ(Unknown) ;
  2009.    }
  2010.  
  2011.    ResourceString Format ( Data->Library->QueryHandle(), IDS_HELPSUBITEMNOTFOUND ) ;
  2012.  
  2013.    BYTE Message [200] ;
  2014.    sprintf ( PCHAR(Message), PCHAR(Format), Mode, Topic, Subtopic ) ;
  2015.  
  2016.   /**************************************************************************
  2017.    * Display the error message.                                             *
  2018.    **************************************************************************/
  2019.  
  2020.    WinMessageBox ( HWND_DESKTOP, hwnd, Message, PSZ(Title), 0, MB_OK | MB_WARNING ) ;
  2021.  
  2022.   /**************************************************************************
  2023.    * Return zero, indicating that the message was processed.                *
  2024.    **************************************************************************/
  2025.  
  2026.    return ( MRFROMSHORT ( 0 ) ) ;
  2027. }
  2028.  
  2029. /****************************************************************************
  2030.  *                                                                          *
  2031.  *      Process Refresh message.                                            *
  2032.  *                                                                          *
  2033.  ****************************************************************************/
  2034.  
  2035. STATIC MRESULT APIENTRY Refresh ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  2036.  
  2037.   /**************************************************************************
  2038.    * Find the instance data.                                                *
  2039.    **************************************************************************/
  2040.  
  2041.    PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  2042.  
  2043.   /**************************************************************************
  2044.    * If we're supposed to float the window, do so here.                     *
  2045.    **************************************************************************/
  2046.  
  2047.    if ( Data->IniData.Float )
  2048.       WinSetWindowPos ( WinQueryWindow(hwnd,QW_PARENT), HWND_TOP, 0, 0, 0, 0, SWP_ZORDER ) ;
  2049.  
  2050.   /**************************************************************************
  2051.    * Save the idle counter.                                                 *
  2052.    **************************************************************************/
  2053.  
  2054.    Data->IniData.IdleCount = LONGFROMMP ( mp1 ) ;
  2055.  
  2056.   /**************************************************************************
  2057.    * If the battery is now discharging, we must deactivate CPU Load.        *
  2058.    **************************************************************************/
  2059.  
  2060.    Battery *BatteryItem = (Battery*) Data->IniData.Items[ITEM_BATTERY] ;
  2061.    if ( BatteryItem->QueryFlag() ) {
  2062.       if ( Data->WasDischarging != BatteryItem->Discharging ( ) ) {
  2063.          if ( BatteryItem->Discharging ( ) ) {
  2064.             DosSuspendThread ( Data->CounterTID ) ;
  2065.             Data->IniData.IdleCount = 0xFFFFFFFF ;
  2066.          } else {
  2067.             Data->IniData.IdleCount = 0 ;
  2068.             DosResumeThread ( Data->CounterTID ) ;
  2069.          } /* endif */
  2070.          Data->WasDischarging = BatteryItem->Discharging ( ) ;
  2071.       } /* endif */
  2072.    } else {
  2073.       Data->WasDischarging = BatteryItem->Discharging ( ) ;
  2074.    } /* endif */
  2075.  
  2076.   /**************************************************************************
  2077.    * Determine if drive mask has changed.                                   *
  2078.    **************************************************************************/
  2079.  
  2080.    ULONG Drive ;
  2081.    ULONG Drives ;
  2082.    DosQueryCurrentDisk ( &Drive, &Drives ) ;
  2083.    Drives &= ~Data->Exclude ;
  2084.  
  2085.    if ( Drives != Data->Drives ) {
  2086.  
  2087.      /***********************************************************************
  2088.       * Update the drive item list and resize the window if necessary.      *
  2089.       ***********************************************************************/
  2090.  
  2091.       if ( UpdateDriveList ( Data->Proc->QueryAnchor(), Data->Library->QueryHandle(), Data->IniFile->QueryHandle(),
  2092.          &Data->IniData, Data->pDdeServer, Data->Drives, Drives, Data->Drives, Data->Exclude ) ) {
  2093.  
  2094.          if ( Data->DialogWindow ) 
  2095.             WinSendMsg ( Data->DialogWindow, WM_UPDATEDRIVES, MPFROMP(&Data->IniData), 0 ) ;
  2096.  
  2097.          ResizeWindow ( hwnd ) ;
  2098.  
  2099.       } /* endif */
  2100.  
  2101.    } /* endif */
  2102.  
  2103.   /**************************************************************************
  2104.    * Update the statistics.                                                 *
  2105.    **************************************************************************/
  2106.  
  2107.    UpdateWindow ( hwnd, Data, FALSE ) ;
  2108.  
  2109.   /**************************************************************************
  2110.    * Chime if we've passed the top of the hour.  Save time when done.       *
  2111.    **************************************************************************/
  2112.  
  2113.    DATETIME DateTime ;
  2114.    DosGetDateTime ( &DateTime ) ;
  2115.  
  2116.    if ( Data->IniData.Chime AND ( DateTime.hours != Data->PreviousDateTime.hours ) ) {
  2117.      if ( !WinAlarm ( HWND_DESKTOP, 11 ) ) {     // If no cuckoo clock, just beep.
  2118.         DosBeep  ( 400, 100 ) ;
  2119.         DosSleep (      100 ) ;
  2120.         DosBeep  ( 400, 100 ) ;
  2121.      } /* endif */
  2122.    } /* endif */
  2123.  
  2124.    Data->PreviousDateTime = DateTime ;
  2125.  
  2126.   /**************************************************************************
  2127.    * Return zero, indicating that the message was processed.                *
  2128.    **************************************************************************/
  2129.  
  2130.    return ( MRFROMSHORT ( 0 ) ) ;
  2131. }
  2132.  
  2133.  
  2134. /****************************************************************************
  2135.  *                                                                          *
  2136.  *      Process UpdateParms message.                                        *
  2137.  *                                                                          *
  2138.  ****************************************************************************/
  2139.  
  2140. STATIC MRESULT APIENTRY UpdateParms ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  2141.  
  2142.   /**************************************************************************
  2143.    * Find the instance data.                                                *
  2144.    **************************************************************************/
  2145.  
  2146.    PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  2147.    CONFIG_PARMS *Parms = (CONFIG_PARMS*) mp1 ;
  2148.  
  2149.   /**************************************************************************
  2150.    * Save the new monitor priority.                                         *
  2151.    **************************************************************************/
  2152.  
  2153.    Data->IniData.fMonitorPriority = TRUE ;
  2154.    Data->IniData.MonitorPriority = BYTE ( Parms->MonitorPriority ) ;
  2155.  
  2156.   /**************************************************************************
  2157.    * Save the new timer interval.                                           *
  2158.    **************************************************************************/
  2159.  
  2160.    Data->IniData.fTimerInterval = TRUE ;
  2161.    Data->IniData.TimerInterval = USHORT ( Parms->TimerInterval ) ;
  2162.  
  2163.   /**************************************************************************
  2164.    * Save the float-to-top flag.                                            *
  2165.    **************************************************************************/
  2166.  
  2167.    Data->IniData.fFloat = TRUE ;
  2168.    Data->IniData.Float = Parms->Float ;
  2169.  
  2170.   /**************************************************************************
  2171.    * Save the window animate flag.                                          *
  2172.    **************************************************************************/
  2173.  
  2174.    Data->IniData.fAnimate = TRUE ;
  2175.    Data->IniData.Animate = Parms->Animate ;
  2176.  
  2177.   /**************************************************************************
  2178.    * Save the anchor corner flag.                                           *
  2179.    **************************************************************************/
  2180.  
  2181.    Data->IniData.fAnchorCorner = TRUE ;
  2182.    Data->IniData.AnchorCorner = Parms->AnchorCorner ;
  2183.  
  2184.   /**************************************************************************
  2185.    * Save the hourly chime flag.                                            *
  2186.    **************************************************************************/
  2187.  
  2188.    Data->IniData.fChime = TRUE ;
  2189.    Data->IniData.Chime = Parms->Chime ;
  2190.  
  2191.   /**************************************************************************
  2192.    * Save the hide controls flag, and adjust the window if it changed.      *
  2193.    **************************************************************************/
  2194.  
  2195.    Data->IniData.fHideControls = TRUE ;
  2196.    if ( Data->IniData.HideControls != Parms->HideControls ) {
  2197.       HWND FrameWindow = WinQueryWindow ( hwnd, QW_PARENT ) ;
  2198.       Data->IniData.HideControls = Parms->HideControls ;
  2199.       if ( NOT ( Data->IniData.Position.fl & SWP_MINIMIZE ) )
  2200.          HideControls ( Data->IniData.HideControls, FrameWindow, Data->SysMenu, Data->TitleBar, Data->MinMax ) ;
  2201.    } /* endif */
  2202.  
  2203.   /**************************************************************************
  2204.    * If CPU load monitoring has changed, start/stop the monitoring thread.  *
  2205.    **************************************************************************/
  2206.  
  2207.    if ( Parms->ItemFlags[ITEM_CPULOAD] != Data->IniData.Items[ITEM_CPULOAD]->QueryFlag() )
  2208.       if ( Parms->ItemFlags[ITEM_CPULOAD] )
  2209.          DosResumeThread ( Data->CounterTID ) ;
  2210.       else
  2211.          DosSuspendThread ( Data->CounterTID ) ;
  2212.  
  2213.   /**************************************************************************
  2214.    * If the 24-hour clock option has changed, tell the clock item.          *
  2215.    **************************************************************************/
  2216.  
  2217.    if ( Data->IniData.Hour24 != Parms->Hour24 ) {
  2218.       ((Clock*)Data->IniData.Items[ITEM_CLOCK])->SetHour24 ( Parms->Hour24 ) ;
  2219.       Data->IniData.Hour24 = Parms->Hour24 ;
  2220.    } /* endif */
  2221.  
  2222.   /**************************************************************************
  2223.    * Determine if the display item list or its appearance has changed.      *
  2224.    *   If not, return.                                                      *
  2225.    **************************************************************************/
  2226.  
  2227.    BOOL ItemsChanged = FALSE ;
  2228.    for ( int i=0; i<Data->IniData.ItemCount; i++ ) {
  2229.       Item *pItem = Data->IniData.Items[i] ;
  2230.       if ( Parms->ItemFlags[i] != pItem->QueryFlag() ) {
  2231.          ItemsChanged = TRUE ;
  2232.          break ;
  2233.       } /* endif */
  2234.       if ( strcmp ( Parms->CurrentLabels[i], PCHAR(pItem->QueryCurrentLabel()) ) ) {
  2235.          ItemsChanged = TRUE ;
  2236.          break ;
  2237.       } /* endif */
  2238.       if ( Parms->WarningLevel[i] != pItem->QueryWarningLevel() ) {
  2239.          ItemsChanged = TRUE ;
  2240.          break ;
  2241.       } /* endif */
  2242.       if ( Parms->ErrorLevel[i] != pItem->QueryErrorLevel() ) {
  2243.          ItemsChanged = TRUE ;
  2244.          break ;
  2245.       } /* endif */
  2246.    } /* endfor */
  2247.  
  2248.    if ( NOT ItemsChanged
  2249.       AND ( Parms->NormalBackground == Data->IniData.BackColor )
  2250.       AND ( Parms->NormalForeground == Data->IniData.TextColor )
  2251.       AND ( Parms->WarningBackground == Data->IniData.WarningBackground )
  2252.       AND ( Parms->WarningForeground == Data->IniData.WarningForeground )
  2253.       AND ( Parms->ErrorBackground == Data->IniData.ErrorBackground )
  2254.       AND ( Parms->ErrorForeground == Data->IniData.ErrorForeground )
  2255.       AND ( Data->IniData.ShowFileSystemNames == Parms->ShowFileSystemNames )
  2256.       AND ( Data->IniData.ShowDiskLabels == Parms->ShowDiskLabels )
  2257.       AND ( Data->IniData.ShowSeconds == Parms->ShowSeconds )
  2258.       AND ( Data->IniData.ShowK == Parms->ShowK ) 
  2259.       AND ( Data->IniData.ShowTrueK == Parms->ShowTrueK ) 
  2260.       AND ( Data->IniData.ShowM == Parms->ShowM ) 
  2261.       AND ( Data->IniData.TableFormat == Parms->TableFormat )
  2262.       AND ( Data->IniData.ShowRemoteDrives == Parms->ShowRemoteDrives ) ) {
  2263.       return ( MRFROMSHORT ( 0 ) ) ;
  2264.    } /* endif */
  2265.  
  2266.   /**************************************************************************
  2267.    * Update the colors.                                                     *
  2268.    **************************************************************************/
  2269.  
  2270.    Data->IniData.BackColor = Parms->NormalBackground ;
  2271.    Data->IniData.TextColor = Parms->NormalForeground ;
  2272.    Data->IniData.WarningBackground = Parms->WarningBackground ;
  2273.    Data->IniData.WarningForeground = Parms->WarningForeground ;
  2274.    Data->IniData.ErrorBackground = Parms->ErrorBackground ;
  2275.    Data->IniData.ErrorForeground = Parms->ErrorForeground ;
  2276.  
  2277.    WinSetPresParam ( hwnd, PP_BACKGROUNDCOLOR,
  2278.       sizeof(Data->IniData.BackColor), &Data->IniData.BackColor ) ;
  2279.    WinSetPresParam ( hwnd, PP_FOREGROUNDCOLOR,
  2280.       sizeof(Data->IniData.TextColor), &Data->IniData.TextColor ) ;
  2281.  
  2282.   /**************************************************************************
  2283.    * Give all the items their levels and colors.                            *
  2284.    **************************************************************************/
  2285.  
  2286.    for ( i=0; i<Data->IniData.ItemCount; i++ ) {
  2287.       Item *pItem = Data->IniData.Items[i] ;
  2288.       pItem->SetWarningLevel  ( Parms->WarningLevel[i] ) ;
  2289.       pItem->SetErrorLevel    ( Parms->ErrorLevel[i] ) ;
  2290.       pItem->SetNormalColors  ( Data->IniData.BackColor, Data->IniData.TextColor ) ;
  2291.       pItem->SetWarningColors ( Data->IniData.WarningBackground, Data->IniData.WarningForeground ) ;
  2292.       pItem->SetErrorColors   ( Data->IniData.ErrorBackground, Data->IniData.ErrorForeground ) ;
  2293.    } /* endfor */
  2294.  
  2295.   /**************************************************************************
  2296.    * Save the show file-system names flag.                                  *
  2297.    **************************************************************************/
  2298.  
  2299.    Data->IniData.fShowFileSystemNames = TRUE ;
  2300.    Data->IniData.ShowFileSystemNames = Parms->ShowFileSystemNames ;
  2301.  
  2302.    for ( i=ITEM_BASE_COUNT; i<Data->IniData.ItemCount; i++ ) {
  2303.       Item *pItem = Data->IniData.Items[i] ;
  2304.       ((DriveFree*)pItem)->SetShowFileSystemName ( Data->IniData.ShowFileSystemNames ) ;
  2305.    } /* endfor */
  2306.  
  2307.   /**************************************************************************
  2308.    * Save the show disk labels flag.                                        *
  2309.    **************************************************************************/
  2310.  
  2311.    Data->IniData.fShowDiskLabels = TRUE ;
  2312.    Data->IniData.ShowDiskLabels = Parms->ShowDiskLabels ;
  2313.  
  2314.    for ( i=ITEM_BASE_COUNT; i<Data->IniData.ItemCount; i++ ) {
  2315.       Item *pItem = Data->IniData.Items[i] ;
  2316.       ((DriveFree*)pItem)->SetShowDiskLabel ( Data->IniData.ShowDiskLabels ) ;
  2317.    } /* endfor */
  2318.  
  2319.   /**************************************************************************
  2320.    * Save the show seconds flag.                                            *
  2321.    **************************************************************************/
  2322.  
  2323.    Data->IniData.fShowSeconds = TRUE ;
  2324.    Data->IniData.ShowSeconds = Parms->ShowSeconds ;
  2325.  
  2326.    ((Clock*)Data->IniData.Items[ITEM_CLOCK])->SetShowSeconds ( Data->IniData.ShowSeconds ) ;
  2327.    ((ElapsedTime*)Data->IniData.Items[ITEM_ELAPSEDTIME])->SetShowSeconds ( Data->IniData.ShowSeconds ) ;
  2328.  
  2329.   /**************************************************************************
  2330.    * Save the show 'K' flag.                                                *
  2331.    **************************************************************************/
  2332.  
  2333.    Data->IniData.fShowK = TRUE ;
  2334.    Data->IniData.ShowK = Parms->ShowK ;
  2335.  
  2336.    ((MemoryFree *)Data->IniData.Items[ITEM_MEMORYFREE   ])->SetShowK ( Data->IniData.ShowK ) ;
  2337.    ((VirtualFree*)Data->IniData.Items[ITEM_VIRTUALFREE  ])->SetShowK ( Data->IniData.ShowK ) ;
  2338.    ((SwapFree   *)Data->IniData.Items[ITEM_SWAPDISKFREE ])->SetShowK ( Data->IniData.ShowK ) ;
  2339.    ((SwapSize   *)Data->IniData.Items[ITEM_SWAPFILESIZE ])->SetShowK ( Data->IniData.ShowK ) ;
  2340.    ((SwapSlack  *)Data->IniData.Items[ITEM_SWAPFILESLACK])->SetShowK ( Data->IniData.ShowK ) ;
  2341.    ((SpoolSize  *)Data->IniData.Items[ITEM_SPOOLFILESIZE])->SetShowK ( Data->IniData.ShowK ) ;
  2342.    ((TotalFree  *)Data->IniData.Items[ITEM_TOTALFREE    ])->SetShowK ( Data->IniData.ShowK ) ;
  2343.  
  2344.    for ( i=ITEM_BASE_COUNT; i<Data->IniData.ItemCount; i++ ) {
  2345.       Item *pItem = Data->IniData.Items[i] ;
  2346.       ((DriveFree*)pItem)->SetShowK ( Data->IniData.ShowK ) ;
  2347.    } /* endfor */
  2348.  
  2349.   /**************************************************************************
  2350.    * Save the show true 'K' flag.                                           *
  2351.    **************************************************************************/
  2352.  
  2353.    Data->IniData.fShowTrueK = TRUE ;
  2354.    Data->IniData.ShowTrueK = Parms->ShowTrueK ;
  2355.  
  2356.    ((MemoryFree *)Data->IniData.Items[ITEM_MEMORYFREE   ])->SetShowTrueK ( Data->IniData.ShowTrueK ) ;
  2357.    ((VirtualFree*)Data->IniData.Items[ITEM_VIRTUALFREE  ])->SetShowTrueK ( Data->IniData.ShowTrueK ) ;
  2358.    ((SwapFree   *)Data->IniData.Items[ITEM_SWAPDISKFREE ])->SetShowTrueK ( Data->IniData.ShowTrueK ) ;
  2359.    ((SwapSize   *)Data->IniData.Items[ITEM_SWAPFILESIZE ])->SetShowTrueK ( Data->IniData.ShowTrueK ) ;
  2360.    ((SwapSlack  *)Data->IniData.Items[ITEM_SWAPFILESLACK])->SetShowTrueK ( Data->IniData.ShowTrueK ) ;
  2361.    ((SpoolSize  *)Data->IniData.Items[ITEM_SPOOLFILESIZE])->SetShowTrueK ( Data->IniData.ShowTrueK ) ;
  2362.    ((TotalFree  *)Data->IniData.Items[ITEM_TOTALFREE    ])->SetShowTrueK ( Data->IniData.ShowTrueK ) ;
  2363.  
  2364.    for ( i=ITEM_BASE_COUNT; i<Data->IniData.ItemCount; i++ ) {
  2365.       Item *pItem = Data->IniData.Items[i] ;
  2366.       ((DriveFree*)pItem)->SetShowTrueK ( Data->IniData.ShowTrueK ) ;
  2367.    } /* endfor */
  2368.  
  2369.   /**************************************************************************
  2370.    * Save the show 'M' flag.                                                *
  2371.    **************************************************************************/
  2372.  
  2373.    Data->IniData.fShowM = TRUE ;
  2374.    Data->IniData.ShowM = Parms->ShowM ;
  2375.  
  2376.    ((MemoryFree *)Data->IniData.Items[ITEM_MEMORYFREE   ])->SetShowM ( Data->IniData.ShowM ) ;
  2377.    ((VirtualFree*)Data->IniData.Items[ITEM_VIRTUALFREE  ])->SetShowM ( Data->IniData.ShowM ) ;
  2378.    ((SwapFree   *)Data->IniData.Items[ITEM_SWAPDISKFREE ])->SetShowM ( Data->IniData.ShowM ) ;
  2379.    ((SwapSize   *)Data->IniData.Items[ITEM_SWAPFILESIZE ])->SetShowM ( Data->IniData.ShowM ) ;
  2380.    ((SwapSlack  *)Data->IniData.Items[ITEM_SWAPFILESLACK])->SetShowM ( Data->IniData.ShowM ) ;
  2381.    ((SpoolSize  *)Data->IniData.Items[ITEM_SPOOLFILESIZE])->SetShowM ( Data->IniData.ShowM ) ;
  2382.    ((TotalFree  *)Data->IniData.Items[ITEM_TOTALFREE    ])->SetShowM ( Data->IniData.ShowM ) ;
  2383.  
  2384.    for ( i=ITEM_BASE_COUNT; i<Data->IniData.ItemCount; i++ ) {
  2385.       Item *pItem = Data->IniData.Items[i] ;
  2386.       ((DriveFree*)pItem)->SetShowM ( Data->IniData.ShowM ) ;
  2387.    } /* endfor */
  2388.  
  2389.   /**************************************************************************
  2390.    * Save the new item flags.                                               *
  2391.    **************************************************************************/
  2392.  
  2393.    for ( i=0; i<Data->IniData.ItemCount; i++ ) {
  2394.       Item *pItem = Data->IniData.Items[i] ;
  2395.       if ( Parms->ItemFlags[i] )
  2396.          pItem->SetFlag ( ) ;
  2397.       else
  2398.          pItem->ResetFlag ( ) ;
  2399.       pItem->SetLabel ( Parms->CurrentLabels[i] ) ;
  2400.    } /* endif */
  2401.  
  2402.   /**************************************************************************
  2403.    * Save the table format flag.                                            *
  2404.    **************************************************************************/
  2405.  
  2406.    Data->IniData.fTableFormat = TRUE ;
  2407.    Data->IniData.TableFormat = Parms->TableFormat ;
  2408.  
  2409.   /**************************************************************************
  2410.    * Save the 'Show Remote Drives' flag.                                    *
  2411.    **************************************************************************/
  2412.  
  2413.    if ( Data->IniData.ShowRemoteDrives != Parms->ShowRemoteDrives ) {
  2414.       Data->IniData.fShowRemoteDrives = TRUE ;
  2415.       Data->IniData.ShowRemoteDrives = Parms->ShowRemoteDrives ;
  2416.       ULONG Drives = 0x03FFFFFF ;
  2417.       Drives &= ~Data->Exclude ;
  2418.       if ( UpdateDriveList ( Data->Proc->QueryAnchor(), Data->Library->QueryHandle(), Data->IniFile->QueryHandle(),
  2419.          &Data->IniData, Data->pDdeServer, Data->Drives, Drives, Data->Drives, Data->Exclude ) )
  2420.          if ( Data->DialogWindow ) 
  2421.             WinSendMsg ( Data->DialogWindow, WM_UPDATEDRIVES, MPFROMP(&Data->IniData), 0 ) ;
  2422.    } /* endif */
  2423.  
  2424.   /**************************************************************************
  2425.    * Resize the display window.                                             *
  2426.    **************************************************************************/
  2427.  
  2428.    ResizeWindow ( hwnd ) ;
  2429.  
  2430.   /**************************************************************************
  2431.    * Return zero, indicating that the message was processed.                *
  2432.    **************************************************************************/
  2433.  
  2434.    return ( MRFROMSHORT ( 0 ) ) ;
  2435. }
  2436.  
  2437.  
  2438. /****************************************************************************
  2439.  *                                                                          *
  2440.  *      Process DDE Initiate request                                        *
  2441.  *                                                                          *
  2442.  ****************************************************************************/
  2443.  
  2444. STATIC MRESULT APIENTRY Dde_Initiate ( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) {
  2445.  
  2446.   /**************************************************************************
  2447.    * Find the instance data.                                                *
  2448.    **************************************************************************/
  2449.  
  2450.    PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  2451.  
  2452.   /**************************************************************************
  2453.    * Pass the request to the DDE Server.                                    *
  2454.    **************************************************************************/
  2455.  
  2456.    Data->pDdeServer->Initiate ( hwnd, HWNDFROMMP(mp1), PDDEINIT(PVOIDFROMMP(mp2)) ) ;
  2457.  
  2458.   /**************************************************************************
  2459.    * Return zero, indicating that the message was processed.                *
  2460.    **************************************************************************/
  2461.  
  2462.    return ( MRFROMSHORT ( 0 ) ) ;
  2463. }
  2464.  
  2465.  
  2466. /****************************************************************************
  2467.  *                                                                          *
  2468.  *                      Get Expanded INI Information                        *
  2469.  *                                                                          *
  2470.  ****************************************************************************/
  2471.  
  2472. STATIC int GetIniData ( HAB Anchor, HMODULE Library, HINI IniHandle, PINIDATA IniData, Dde_Server *pDdeServer, ULONG &Exclude ) {
  2473.  
  2474.   /**************************************************************************
  2475.    * Get the basic INI information.                                         *
  2476.    **************************************************************************/
  2477.  
  2478.    if ( GetIniData ( IniHandle, IniData ) )
  2479.       return ( 1 ) ;
  2480.  
  2481.   /**************************************************************************
  2482.    * Initialize the global resource strings.                                *
  2483.    **************************************************************************/
  2484.  
  2485.    IniData->Day             = new ResourceString ( Library, IDS_DAY ) ;
  2486.    IniData->Days            = new ResourceString ( Library, IDS_DAYS ) ;
  2487.    IniData->DaysOfWeek      = new ResourceString ( Library, IDS_DAYSOFWEEK ) ;
  2488.    IniData->DriveError      = new ResourceString ( Library, IDS_DRIVEERROR ) ;
  2489.    IniData->BatteryError    = new ResourceString ( Library, IDS_APM_ERROR ) ;
  2490.    IniData->BatteryAC       = new ResourceString ( Library, IDS_APM_AC ) ;
  2491.    IniData->BatteryCharging = new ResourceString ( Library, IDS_APM_CHARGING ) ;
  2492.  
  2493.   /**************************************************************************
  2494.    * Get the SWAPPATH statement from CONFIG.SYS.                            *
  2495.    **************************************************************************/
  2496.  
  2497.    PSZ Swappath = ScanSystemConfig ( Anchor, PSZ("SWAPPATH") ) ;
  2498.  
  2499.    if ( Swappath == NULL )
  2500.       Swappath = PSZ("C:\\OS2\\SYSTEM 0 0") ;
  2501.  
  2502.    char *p = CopyString ( PCHAR(IniData->SwapPath), PCHAR(Swappath) ) ;
  2503.    IniData->MinFree = 0 ;
  2504.    IniData->InitialSwap = 0 ;
  2505.    sscanf ( p, " %li %li", &IniData->MinFree, &IniData->InitialSwap ) ;
  2506.  
  2507.   /**************************************************************************
  2508.    * Find out where the spool work directory is.                            *
  2509.    **************************************************************************/
  2510.  
  2511.    IniData->SpoolPath = 0 ;
  2512.  
  2513.    ULONG Size ;
  2514.    if ( PrfQueryProfileSize ( HINI_PROFILE, PSZ("PM_SPOOLER"), PSZ("DIR"), &Size ) ) {
  2515.       IniData->SpoolPath = PSZ ( malloc ( (int)Size ) ) ;
  2516.       if ( IniData->SpoolPath ) {
  2517.          if ( PrfQueryProfileData ( HINI_PROFILE, PSZ("PM_SPOOLER"), PSZ("DIR"), IniData->SpoolPath, &Size ) ) {
  2518.             PBYTE p = PBYTE( strchr ( PCHAR(IniData->SpoolPath), ';' ) ) ;
  2519.             if ( p ) {
  2520.                *p = 0 ;
  2521.             }
  2522.          } else {
  2523.             free ( IniData->SpoolPath ) ;
  2524.             IniData->SpoolPath = 0 ;
  2525.          }
  2526.       }
  2527.    }
  2528.  
  2529.    if ( IniData->SpoolPath == 0 )
  2530.       IniData->SpoolPath = PSZ ( "C:\\SPOOL" ) ;
  2531.  
  2532.   /**************************************************************************
  2533.    * Build the fixed portion of the item list.                              *
  2534.    **************************************************************************/
  2535.  
  2536.    ResourceString ClockLabel ( Library, IDS_CLOCK ) ;
  2537.    IniData->Items[ITEM_CLOCK] = new Clock ( ITEM_CLOCK,
  2538.       "ShowClock", ClockLabel, ClockLabel, pDdeServer, "Items",
  2539.       IniData->CountryInfo, IniData->szAm, IniData->szPm,
  2540.       IniData->DaysOfWeek, IniData->ShowSeconds, IniData->Hour24 ) ;
  2541.  
  2542.    ResourceString ElapsedLabel ( Library, IDS_ELAPSED ) ;
  2543.    IniData->Items[ITEM_ELAPSEDTIME] = new ElapsedTime ( ITEM_ELAPSEDTIME,
  2544.       "ShowElapsed", ElapsedLabel, ElapsedLabel, pDdeServer, "Items",
  2545.       IniData->CountryInfo, IniData->Day,
  2546.       IniData->Days, IniData->ShowSeconds ) ;
  2547.  
  2548.    ResourceString MemoryLabel ( Library, IDS_MEMORY ) ;
  2549.    IniData->Items[ITEM_MEMORYFREE] = new MemoryFree ( ITEM_MEMORYFREE,
  2550.       "ShowMemory", MemoryLabel, MemoryLabel, pDdeServer, "Items",
  2551.       IniData->CountryInfo, IniData->ShowK, IniData->ShowTrueK, IniData->ShowM ) ;
  2552.  
  2553.    ResourceString VirtualLabel ( Library, IDS_VIRTUAL ) ;
  2554.    IniData->Items[ITEM_VIRTUALFREE] = new VirtualFree ( ITEM_VIRTUALFREE,
  2555.       "ShowVirtual", VirtualLabel, VirtualLabel, pDdeServer, "Items",
  2556.       IniData->CountryInfo, IniData->ShowK, IniData->ShowTrueK, IniData->ShowM ) ;
  2557.  
  2558.    ResourceString SwapSizeLabel ( Library, IDS_SWAPSIZE ) ;
  2559.    IniData->Items[ITEM_SWAPFILESIZE] = new SwapSize ( ITEM_SWAPFILESIZE,
  2560.       "ShowSwapsize", SwapSizeLabel, SwapSizeLabel, pDdeServer, "Items",
  2561.       IniData->CountryInfo, IniData->ShowK, IniData->ShowTrueK, IniData->ShowM, IniData->SwapPath, IniData->InitialSwap ) ;
  2562.  
  2563.    ResourceString SwapFreeLabel ( Library, IDS_SWAPFREE ) ;
  2564.    IniData->Items[ITEM_SWAPDISKFREE] = new SwapFree ( ITEM_SWAPDISKFREE,
  2565.       "ShowSwapfree", SwapFreeLabel, SwapFreeLabel, pDdeServer, "Items",
  2566.       IniData->CountryInfo, IniData->ShowK, IniData->ShowTrueK, IniData->ShowM, IniData->SwapPath, IniData->MinFree ) ;
  2567.  
  2568.    ResourceString SwapSlackLabel ( Library, IDS_SWAPSLACK ) ;
  2569.    IniData->Items[ITEM_SWAPFILESLACK] = new SwapSlack ( ITEM_SWAPFILESLACK,
  2570.       "ShowSwapSlack", SwapSlackLabel, SwapSlackLabel, pDdeServer, "Items",
  2571.       IniData->CountryInfo, IniData->ShowK, IniData->ShowTrueK, IniData->ShowM,
  2572.       (VirtualFree*)IniData->Items[ITEM_VIRTUALFREE],
  2573.       (SwapFree*)IniData->Items[ITEM_SWAPDISKFREE],
  2574.       (MemoryFree*)IniData->Items[ITEM_MEMORYFREE] ) ;
  2575.  
  2576.    ResourceString SpoolSizeLabel ( Library, IDS_SPOOLSIZE ) ;
  2577.    IniData->Items[ITEM_SPOOLFILESIZE] = new SpoolSize ( ITEM_SPOOLFILESIZE,
  2578.       "ShowSpoolSize", SpoolSizeLabel, SpoolSizeLabel, pDdeServer, "Items",
  2579.       IniData->CountryInfo, IniData->ShowK, IniData->ShowTrueK, IniData->ShowM, IniData->SpoolPath ) ;
  2580.  
  2581.    ResourceString CpuLoadLabel ( Library, IDS_CPULOAD ) ;
  2582.    IniData->Items[ITEM_CPULOAD] = new CpuLoad ( ITEM_CPULOAD,
  2583.       "ShowCpuLoad", CpuLoadLabel, CpuLoadLabel, pDdeServer, "Items",
  2584.       IniData->MaxCount, &IniData->IdleCount, IniData->BatteryError ) ;
  2585.  
  2586.    ResourceString BatteryLabel ( Library, IDS_BATTERY ) ;
  2587.    IniData->Items[ITEM_BATTERY] = new Battery ( ITEM_BATTERY,
  2588.       "ShowBattery", BatteryLabel, BatteryLabel, pDdeServer, "Items", 
  2589.       IniData->BatteryError, IniData->BatteryAC, IniData->BatteryCharging ) ;
  2590.  
  2591.    ResourceString TaskCountLabel ( Library, IDS_TASKCOUNT ) ;
  2592.    IniData->Items[ITEM_TASKCOUNT] = new TaskCount ( ITEM_TASKCOUNT,
  2593.       "ShowTaskCount", TaskCountLabel, TaskCountLabel, pDdeServer, "Items",
  2594.       Anchor ) ;
  2595.  
  2596.    ResourceString ProcessCountLabel ( Library, IDS_PROCESSCOUNT ) ;
  2597.    IniData->Items[ITEM_PROCESSCOUNT] = new ProcessCount ( ITEM_PROCESSCOUNT,
  2598.       "ShowProcessCount", ProcessCountLabel, ProcessCountLabel, pDdeServer, "Items" ) ;
  2599.  
  2600.    ResourceString ThreadCountLabel ( Library, IDS_THREADCOUNT ) ;
  2601.    IniData->Items[ITEM_THREADCOUNT] = new ThreadCount ( ITEM_THREADCOUNT,
  2602.       "ShowThreadCount", ThreadCountLabel, ThreadCountLabel, pDdeServer, "Items" ) ;
  2603.  
  2604.    ResourceString TotalFreeLabel ( Library, IDS_TOTALFREE ) ;
  2605.    IniData->Items[ITEM_TOTALFREE] = new TotalFree ( ITEM_TOTALFREE,
  2606.       "ShowTotalFree", TotalFreeLabel, TotalFreeLabel, pDdeServer, "Items",
  2607.       IniData->CountryInfo, IniData->ShowK, IniData->ShowTrueK, IniData->ShowM, 0 ) ;
  2608.  
  2609.    for ( int i=0; i<ITEM_BASE_COUNT; i++ ) 
  2610.       IniData->Items[i]->GetProfile ( IniHandle ) ;
  2611.  
  2612.   /**************************************************************************
  2613.    * Add items for each drive on the system.                                *
  2614.    **************************************************************************/
  2615.  
  2616.    ULONG Drive, Drives ;
  2617.    DosQueryCurrentDisk ( &Drive, &Drives ) ;
  2618.    Drives &= ~Exclude ;
  2619.    UpdateDriveList ( Anchor, Library, IniHandle, IniData, pDdeServer, 0, Drives, Drives, Exclude ) ;
  2620.  
  2621.    return ( 0 ) ;
  2622. }
  2623.  
  2624. /****************************************************************************
  2625.  *                                                                          *
  2626.  *      Scan CONFIG.SYS for a keyword.  Return the value.                   *
  2627.  *                                                                          *
  2628.  ****************************************************************************/
  2629.  
  2630. extern PSZ ScanSystemConfig ( HAB Anchor, PSZ Keyword ) {
  2631.  
  2632.  /***************************************************************************
  2633.   * Get the boot drive number from the global information segment.          *
  2634.   ***************************************************************************/
  2635.  
  2636.   ULONG BootDrive ;
  2637.   DosQuerySysInfo ( QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, &BootDrive, sizeof(BootDrive) ) ;
  2638.  
  2639.  /***************************************************************************
  2640.   * Convert the keyword to upper case.                                      *
  2641.   ***************************************************************************/
  2642.  
  2643.   WinUpper ( Anchor, 0, 0, Keyword ) ;
  2644.  
  2645.  /***************************************************************************
  2646.   * Build the CONFIG.SYS path.                                              *
  2647.   ***************************************************************************/
  2648.  
  2649.   char Path [_MAX_PATH] ;
  2650.   Path[0] = (char) ( BootDrive + 'A' - 1 ) ;
  2651.   Path[1] = 0 ;
  2652.   strcat ( Path, ":\\CONFIG.SYS" ) ;
  2653.  
  2654.  /***************************************************************************
  2655.   * Open CONFIG.SYS for reading.                                            *
  2656.   ***************************************************************************/
  2657.  
  2658.   FILE *File = fopen ( Path, "r" ) ;
  2659.   if ( NOT File )
  2660.     return ( 0 ) ;
  2661.  
  2662.  /***************************************************************************
  2663.   * While there're more lines in CONFIG.SYS, read a line and check it.      *
  2664.   ***************************************************************************/
  2665.  
  2666.   static char Buffer [500] ;
  2667.   while ( fgets ( Buffer, sizeof(Buffer), File ) ) {
  2668.  
  2669.    /*************************************************************************
  2670.     * Clean any trailing newline character from the input string.           *
  2671.     *************************************************************************/
  2672.  
  2673.     if ( Buffer[strlen(Buffer)-1] == '\n' )
  2674.       Buffer[strlen(Buffer)-1] = 0 ;
  2675.  
  2676.    /*************************************************************************
  2677.     * If keyword starts the line, we've found the line we want.  Close      *
  2678.     *   the file and return a pointer to the parameter text.                *
  2679.     *************************************************************************/
  2680.  
  2681.     WinUpper ( Anchor, 0, 0, PSZ(Buffer) ) ;
  2682.  
  2683.     char *p = Buffer ;
  2684.     while ( *p AND ( ( *p == ' ' ) OR ( *p == '\t' ) ) ) p++ ;
  2685.  
  2686.     if ( strncmp ( p, PCHAR(Keyword), strlen(PCHAR(Keyword)) ) )
  2687.        continue ;
  2688.  
  2689.     p += strlen(PCHAR(Keyword)) ;
  2690.     while ( *p AND ( ( *p == ' ' ) OR ( *p == '\t' ) ) ) p++ ;
  2691.  
  2692.     if ( *p++ != '=' )
  2693.        continue ;
  2694.  
  2695.     while ( *p AND ( ( *p == ' ' ) OR ( *p == '\t' ) ) ) p++ ;
  2696.  
  2697.     fclose ( File ) ;
  2698.     return ( PSZ(p) ) ;
  2699.  
  2700.   }
  2701.  
  2702.  /***************************************************************************
  2703.   * Close the file.  We haven't found the line we wanted.                   *
  2704.   ***************************************************************************/
  2705.  
  2706.   fclose ( File ) ;
  2707.  
  2708.   return ( 0 ) ;
  2709. }
  2710.  
  2711. /****************************************************************************
  2712.  *                                                                          *
  2713.  *                          Copy Quoted String                              *
  2714.  *                                                                          *
  2715.  ****************************************************************************/
  2716.  
  2717. STATIC char *CopyString ( char *Buffer, char *Original ) {
  2718.    char *p1 = PCHAR(Original), *p2 = Buffer ;
  2719.    BOOL Quoted = FALSE ;
  2720.    *p2 = 0 ;
  2721.    while ( *p1 ) {
  2722.       if ( Quoted ) {
  2723.          if ( *p1 == '"' ) {
  2724.             Quoted = FALSE ;
  2725.          } else {
  2726.             *p2++ = *p1 ;
  2727.             *p2 = 0 ;
  2728.          } /* endif */
  2729.       } else {
  2730.          if ( *p1 == '"' ) {
  2731.             Quoted = TRUE ;
  2732.          } else if ( ( *p1 == ' ' ) OR ( *p1 == '\t' ) ) {
  2733.             break ;
  2734.          } else {
  2735.             *p2++ = *p1 ;
  2736.             *p2 = 0 ;
  2737.          } /* endif */
  2738.       } /* endif */
  2739.       p1 ++ ;
  2740.    } /* endwhile */
  2741.    return ( p1 ) ;
  2742. }
  2743.  
  2744. /****************************************************************************
  2745.  *                                                                          *
  2746.  *                       Resize Client Window                               *
  2747.  *                                                                          *
  2748.  ****************************************************************************/
  2749.  
  2750. STATIC void ResizeWindow ( HWND hwnd ) {
  2751.  
  2752.   /**************************************************************************
  2753.    * Find the instance data.                                                *
  2754.    **************************************************************************/
  2755.  
  2756.    PDATA Data = PDATA ( WinQueryWindowPtr ( hwnd, QWL_USER ) ) ;
  2757.  
  2758.   /**************************************************************************
  2759.    * Determine how many items are to be displayed.                          *
  2760.    **************************************************************************/
  2761.  
  2762.    HPS hPS = WinGetPS ( hwnd ) ;
  2763.    GpiSetCp ( hPS, Data->CodePage ) ;
  2764.  
  2765.    int Count = 0 ;
  2766.    Data->MaxColumns = 0 ;
  2767.  
  2768.    RECTL Rectangles [100] ;
  2769.    memset ( Rectangles, 0, sizeof(Rectangles) ) ;
  2770.  
  2771.    for ( int i=0; i<Data->IniData.ItemCount; i++ ) {
  2772.       Item *pItem = Data->IniData.Items[i] ;
  2773.       if ( pItem->QueryFlag() ) {
  2774.          int Columns = pItem->Measure ( hPS, Rectangles[Count] ) ;
  2775.          Data->MaxColumns = max ( Data->MaxColumns, Columns ) ;
  2776.          Count ++ ;
  2777.       } /* endif */
  2778.    } /* endfor */
  2779.  
  2780.    WinReleasePS ( hPS ) ;
  2781.  
  2782.   /**************************************************************************
  2783.    * If the window is visible and minimized, restore it invisibly.          *
  2784.    **************************************************************************/
  2785.  
  2786.    HWND Frame = WinQueryWindow ( hwnd, QW_PARENT ) ;
  2787.  
  2788.    BOOL fHadToHide = FALSE ;
  2789.    BOOL fHadToRestore = FALSE ;
  2790.    if ( Data->IniData.Position.fl & SWP_MINIMIZE ) {
  2791.       if ( WinIsWindowVisible ( Frame ) ) {
  2792.          WinShowWindow ( Frame, FALSE ) ;
  2793.          fHadToHide = TRUE ;
  2794.       } /* endif */
  2795.       WinSetWindowPos ( Frame, 0, 0, 0, 0, 0, SWP_RESTORE ) ;
  2796.       fHadToRestore = TRUE ;
  2797.    } /* endif */
  2798.  
  2799.   /**************************************************************************
  2800.    * Get the entire window's current size and position.                     *
  2801.    **************************************************************************/
  2802.  
  2803.    SWP Position ;
  2804.    WinQueryWindowPos ( Frame, &Position ) ;
  2805.  
  2806.    RECTL Rectangle = { Position.x, Position.y, Position.x+Position.cx, Position.y+Position.cy } ;
  2807.  
  2808.    WinCalcFrameRect ( Frame, &Rectangle, TRUE ) ;
  2809.  
  2810.   /**************************************************************************
  2811.    * Determine the anchor point.                                            *
  2812.    **************************************************************************/
  2813.  
  2814.    POINTL Anchor ;
  2815.    switch ( Data->IniData.AnchorCorner ) {
  2816.       case CORNER_BL:
  2817.       default:
  2818.          Anchor.x = Rectangle.xLeft ;
  2819.          Anchor.y = Rectangle.yBottom ;
  2820.          break;
  2821.       case CORNER_BR:
  2822.          Anchor.x = Rectangle.xRight ;
  2823.          Anchor.y = Rectangle.yBottom ;
  2824.          break;
  2825.       case CORNER_TL:
  2826.          Anchor.x = Rectangle.xLeft ;
  2827.          Anchor.y = Rectangle.yTop ;
  2828.          break;
  2829.       case CORNER_TR:
  2830.          Anchor.x = Rectangle.xRight ;
  2831.          Anchor.y = Rectangle.yTop ;
  2832.          break;
  2833.    } /* endswitch */
  2834.  
  2835.   /**************************************************************************
  2836.    * Determine the new client window size.                                  *
  2837.    **************************************************************************/
  2838.  
  2839.    if ( Count ) {
  2840.  
  2841.       Data->ColumnWidth = 0 ;
  2842.       for ( i=0; i<Count; i++ ) 
  2843.          Data->ColumnWidth = int ( max ( Data->ColumnWidth, (Rectangles[i].xRight-Rectangles[i].xLeft+1) ) ) ;
  2844.  
  2845.       if ( Data->IniData.TableFormat ) {
  2846.          Data->ColumnWidth += Data->Height ;
  2847.          RECTL Desktop ;
  2848.          WinQueryWindowRect ( HWND_DESKTOP, &Desktop ) ;
  2849.          Data->Columns = int ( ( Desktop.xRight - Desktop.xLeft ) / Data->ColumnWidth ) ;
  2850.          Data->Rows = Count / Data->Columns + ( ( Count % Data->Columns ) ? 1 : 0 ) ;
  2851.          Data->Columns = Count / Data->Rows + ( ( Count % Data->Rows ) ? 1 : 0 ) ;
  2852.  
  2853.       } else {
  2854.          Data->ColumnWidth += Data->Height/2 ;
  2855.          Data->Columns = 1 ;
  2856.          Data->Rows = Count ;
  2857.  
  2858.       } /* endif */
  2859.  
  2860.       LONG Height = ( Rectangles[0].yTop - Rectangles[0].yBottom ) * Data->Rows ;
  2861.       Rectangle.xLeft = Rectangle.yBottom = 0 ;
  2862.       Rectangle.xRight = Data->ColumnWidth * Data->Columns ;
  2863.       Rectangle.yTop = Height ;
  2864.  
  2865.    } else {
  2866.       Rectangle.xLeft = Rectangle.yBottom = 0 ;
  2867.       Rectangle.xRight = 200 ;
  2868.       Rectangle.yTop = 0 ;
  2869.  
  2870.    } /* endif */
  2871.  
  2872.   /**************************************************************************
  2873.    * Determine the new rectangle based on the anchor corner.                *
  2874.    **************************************************************************/
  2875.  
  2876.    switch ( Data->IniData.AnchorCorner ) {
  2877.       case CORNER_BL:
  2878.       default:
  2879.          Rectangle.xRight = Anchor.x + ( Rectangle.xRight - Rectangle.xLeft ) ;
  2880.          Rectangle.xLeft = Anchor.x ;
  2881.          Rectangle.yTop = Anchor.y + ( Rectangle.yTop - Rectangle.yBottom ) ;
  2882.          Rectangle.yBottom = Anchor.y ;
  2883.          break;
  2884.       case CORNER_BR:
  2885.          Rectangle.xLeft = Anchor.x - ( Rectangle.xRight - Rectangle.xLeft ) ;
  2886.          Rectangle.xRight = Anchor.x ;
  2887.          Rectangle.yTop = Anchor.y + ( Rectangle.yTop - Rectangle.yBottom ) ;
  2888.          Rectangle.yBottom = Anchor.y ;
  2889.          break;
  2890.       case CORNER_TL:
  2891.          Rectangle.xRight = Anchor.x + ( Rectangle.xRight - Rectangle.xLeft ) ;
  2892.          Rectangle.xLeft = Anchor.x ;
  2893.          Rectangle.yBottom = Anchor.y - ( Rectangle.yTop - Rectangle.yBottom ) ;
  2894.          Rectangle.yTop = Anchor.y ;
  2895.          break;
  2896.       case CORNER_TR:
  2897.          Rectangle.xLeft = Anchor.x - ( Rectangle.xRight - Rectangle.xLeft ) ;
  2898.          Rectangle.xRight = Anchor.x ;
  2899.          Rectangle.yBottom = Anchor.y - ( Rectangle.yTop - Rectangle.yBottom ) ;
  2900.          Rectangle.yTop = Anchor.y ;
  2901.          break;
  2902.    } /* endswitch */
  2903.  
  2904.   /**************************************************************************
  2905.    * Add the frame in.                                                      *
  2906.    **************************************************************************/
  2907.  
  2908.    WinCalcFrameRect ( Frame, &Rectangle, FALSE ) ;
  2909.  
  2910.   /**************************************************************************
  2911.    * Move and size the window.                                              *
  2912.    **************************************************************************/
  2913.  
  2914.    #ifdef DEBUG_POSITION
  2915.    Log ( "Resize: Setting window position to %i,%i (%ix%i).",
  2916.       Rectangle.xLeft, Rectangle.yBottom,
  2917.       Rectangle.xRight-Rectangle.xLeft, Rectangle.yTop-Rectangle.yBottom ) ;
  2918.    #endif // DEBUG_POSITION
  2919.  
  2920.    WinSetWindowPos ( Frame, 0, Rectangle.xLeft, Rectangle.yBottom,
  2921.       Rectangle.xRight-Rectangle.xLeft, Rectangle.yTop-Rectangle.yBottom,
  2922.       SWP_MOVE | SWP_SIZE ) ;
  2923.  
  2924.   /**************************************************************************
  2925.    * Return the window to its original state.                               *
  2926.    **************************************************************************/
  2927.  
  2928.    if ( fHadToRestore ) {
  2929.       #ifdef DEBUG_POSITION
  2930.       Log ( "Resize: Restoring window position to %i,%i (%ix%i).",
  2931.          Data->IniData.Position.x, Data->IniData.Position.y,
  2932.          Data->IniData.Position.cx, Data->IniData.Position.cy ) ;
  2933.       #endif // DEBUG_POSITION
  2934.       WinSetWindowPos ( Frame, 0,
  2935.          Data->IniData.Position.x, Data->IniData.Position.y,
  2936.          Data->IniData.Position.cx, Data->IniData.Position.cy,
  2937.          SWP_MOVE | SWP_SIZE | SWP_MINIMIZE ) ;
  2938.    } /* endif */
  2939.  
  2940.    if ( fHadToHide )
  2941.       WinShowWindow ( Frame, TRUE ) ;
  2942.  
  2943.   /**************************************************************************
  2944.    * Invalidate the window so that it gets repainted.                       *
  2945.    **************************************************************************/
  2946.  
  2947.    WinInvalidateRect ( hwnd, 0, TRUE ) ;
  2948. }
  2949.  
  2950. /****************************************************************************
  2951.  *                                                                          *
  2952.  *                      Hide Window Controls                                *
  2953.  *                                                                          *
  2954.  ****************************************************************************/
  2955.  
  2956. STATIC void HideControls ( BOOL fHide, HWND Frame, HWND SysMenu, HWND TitleBar, HWND MinMax ) {
  2957.  
  2958.   /**************************************************************************
  2959.    * Get original window position and state.                                *
  2960.    **************************************************************************/
  2961.  
  2962.    SWP OldPosition ;
  2963.    WinQueryWindowPos ( Frame, &OldPosition ) ;
  2964.  
  2965.    BOOL WasActive = ( WinQueryActiveWindow ( WinQueryWindow(Frame,QW_PARENT) ) == Frame ) ;
  2966.    BOOL WasVisible = WinIsWindowVisible ( Frame ) ;
  2967.  
  2968.   /**************************************************************************
  2969.    * Restore and hide the window.                                           *
  2970.    **************************************************************************/
  2971.  
  2972.    WinSetWindowPos ( Frame, 0, 0, 0, 0, 0, SWP_RESTORE | SWP_HIDE ) ;
  2973.  
  2974.   /**************************************************************************
  2975.    * Determine client window and location.                                  *
  2976.    **************************************************************************/
  2977.  
  2978.    SWP Position ;
  2979.    WinQueryWindowPos ( Frame, &Position ) ;
  2980.  
  2981.    RECTL Rectangle ;
  2982.    Rectangle.xLeft   = Position.x ;
  2983.    Rectangle.xRight  = Position.x + Position.cx ;
  2984.    Rectangle.yBottom = Position.y ;
  2985.    Rectangle.yTop    = Position.y + Position.cy ;
  2986.  
  2987.    WinCalcFrameRect ( Frame, &Rectangle, TRUE ) ;
  2988.  
  2989.   /**************************************************************************
  2990.    * Hide or reveal the controls windows by changing their parentage.       *
  2991.    **************************************************************************/
  2992.  
  2993.    if ( fHide ) {
  2994.       WinSetParent ( SysMenu,  HWND_OBJECT, FALSE ) ;
  2995.       WinSetParent ( TitleBar, HWND_OBJECT, FALSE ) ;
  2996.       WinSetParent ( MinMax,   HWND_OBJECT, FALSE ) ;
  2997.    } else {
  2998.       WinSetParent ( SysMenu,  Frame, TRUE ) ;
  2999.       WinSetParent ( TitleBar, Frame, TRUE ) ;
  3000.       WinSetParent ( MinMax,   Frame, TRUE ) ;
  3001.       if ( WasActive ) 
  3002.          WinSendMsg ( WinWindowFromID(Frame,FID_TITLEBAR), TBM_SETHILITE, MPFROMLONG(TRUE), 0 ) ;
  3003.    } /* endif */
  3004.  
  3005.   /**************************************************************************
  3006.    * Tell the frame that things have changed.  Let it update the window.    *
  3007.    **************************************************************************/
  3008.  
  3009.    WinSendMsg ( Frame, WM_UPDATEFRAME,
  3010.       MPFROMSHORT ( FCF_TITLEBAR | FCF_SYSMENU | FCF_MINBUTTON ), 0 ) ;
  3011.  
  3012.   /**************************************************************************
  3013.    * Reposition the frame around the client window, which is left be.       *
  3014.    **************************************************************************/
  3015.  
  3016.    WinCalcFrameRect ( Frame, &Rectangle, FALSE ) ;
  3017.  
  3018.    #ifdef DEBUG_POSITION
  3019.    Log ( "HideControls: Setting window position to %i,%i (%ix%i).",
  3020.       Rectangle.xLeft, Rectangle.yBottom,
  3021.       Rectangle.xRight-Rectangle.xLeft, Rectangle.yTop-Rectangle.yBottom ) ;
  3022.    #endif // DEBUG_POSITION
  3023.  
  3024.    WinSetWindowPos ( Frame, 0,
  3025.      Rectangle.xLeft,  Rectangle.yBottom,
  3026.      Rectangle.xRight - Rectangle.xLeft,
  3027.      Rectangle.yTop - Rectangle.yBottom,
  3028.      SWP_SIZE | SWP_MOVE ) ;
  3029.  
  3030.   /**************************************************************************
  3031.    * If window was maximized, put it back that way.                         *
  3032.    **************************************************************************/
  3033.  
  3034.    if ( OldPosition.fl & SWP_MAXIMIZE ) {
  3035.       #ifdef DEBUG_POSITION
  3036.       Log ( "HideControls: Maximizing window position to %i,%i (%ix%i).",
  3037.          Rectangle.xLeft, Rectangle.yBottom,
  3038.          Rectangle.xRight-Rectangle.xLeft, Rectangle.yTop-Rectangle.yBottom ) ;
  3039.       #endif // DEBUG_POSITION
  3040.       WinSetWindowPos ( Frame, 0,
  3041.         Rectangle.xLeft,  Rectangle.yBottom,
  3042.         Rectangle.xRight-Rectangle.xLeft,
  3043.         Rectangle.yTop-Rectangle.yBottom,
  3044.         SWP_SIZE | SWP_MOVE | ( OldPosition.fl & SWP_MAXIMIZE ) ) ;
  3045.    } /* endif */
  3046.  
  3047.   /**************************************************************************
  3048.    * If the window was visible in the first place, show it.                 *
  3049.    **************************************************************************/
  3050.  
  3051.    if ( WasVisible )
  3052.       WinShowWindow ( Frame, TRUE ) ;
  3053.  
  3054.    if ( WasActive ) 
  3055.       WinSetActiveWindow ( HWND_DESKTOP, Frame ) ;
  3056. }
  3057.  
  3058. /****************************************************************************
  3059.  *                                                                          *
  3060.  *    Update Window                                                         *
  3061.  *                                                                          *
  3062.  ****************************************************************************/
  3063.  
  3064. STATIC void UpdateWindow ( HWND hwnd, PDATA Data, BOOL All ) {
  3065.  
  3066.  /***************************************************************************
  3067.   * Determine how many items are to be displayed.                           *
  3068.   ***************************************************************************/
  3069.  
  3070.   int Count = 0 ;
  3071.   for ( int i=0; i<Data->IniData.ItemCount; i++ ) 
  3072.      if ( Data->IniData.Items[i]->QueryFlag() ) 
  3073.         Count ++ ;
  3074.  
  3075.  /***************************************************************************
  3076.   * Get presentation space and make it use RGB colors.                      *
  3077.   ***************************************************************************/
  3078.  
  3079.   HPS hPS = WinGetPS ( hwnd ) ;
  3080.   GpiCreateLogColorTable ( hPS, LCOL_RESET, LCOLF_RGB, 0, 0, 0 ) ;
  3081.   GpiSetCp ( hPS, Data->CodePage ) ;
  3082.  
  3083.  /***************************************************************************
  3084.   * Review all items.  Display those changed, or all.                       *
  3085.   ***************************************************************************/
  3086.  
  3087.   int Row = 0, Column = 0 ;
  3088.   for ( i=0; i<Data->IniData.ItemCount; i++ ) {
  3089.      RECTL Rectangle ;
  3090.      Rectangle.xLeft = Data->ColumnWidth*Column + Data->Height/(Data->IniData.TableFormat?2:4) ;
  3091.      Rectangle.xRight = Rectangle.xLeft + Data->ColumnWidth - Data->Height/(Data->IniData.TableFormat?1:2) ;
  3092.      Rectangle.yBottom = Data->Height * ( Data->Rows - Row - 1 ) ;
  3093.      Rectangle.yTop = Rectangle.yBottom + Data->Height ;
  3094.      Item *pItem = Data->IniData.Items[i] ;
  3095.      if ( pItem->QueryFlag() ) {
  3096.         pItem->Repaint ( hPS, Rectangle, All ) ;
  3097.         Row ++ ;
  3098.         if ( Row >= Data->Rows ) {
  3099.            Row = 0 ;
  3100.            Column ++ ;
  3101.         } /* endif */
  3102.      } /* endif */
  3103.   } /* endfor */
  3104.  
  3105.  /***************************************************************************
  3106.   * Draw column separators in the border color.                             *
  3107.   ***************************************************************************/
  3108.  
  3109.   if ( Data->Columns > 1 ) {
  3110.      GpiSetColor ( hPS, Data->BorderColor ) ;
  3111.      RECTL Rectangle ;
  3112.      WinQueryWindowRect ( hwnd, &Rectangle ) ;
  3113.      for ( i=1; i<Data->Columns; i++ ) {
  3114.         POINTL Point = { Data->ColumnWidth*i-1, Rectangle.yBottom } ;
  3115.         GpiMove ( hPS, &Point ) ;
  3116.         Point.y = Rectangle.yTop ;
  3117.         GpiLine ( hPS, &Point ) ;
  3118.      } /* endfor */
  3119.   } /* endif */
  3120.  
  3121.  /***************************************************************************
  3122.   * Release the presentation space and return.                              *
  3123.   ***************************************************************************/
  3124.  
  3125.   WinReleasePS ( hPS ) ;
  3126. }
  3127.  
  3128.  
  3129. /****************************************************************************
  3130.  *                                                                          *
  3131.  *    Monitor Loop Thread                                                   *
  3132.  *                                                                          *
  3133.  ****************************************************************************/
  3134.  
  3135. STATIC void MonitorLoopThread ( void *Parameter ) {
  3136.  
  3137.   /**************************************************************************
  3138.    * Get the thread parameter.                                              *
  3139.    **************************************************************************/
  3140.  
  3141.    PMONITOR_PARMS Parms = PMONITOR_PARMS ( Parameter ) ;
  3142.  
  3143.   /**************************************************************************
  3144.    * Set this thread's priority.                                            *
  3145.    **************************************************************************/
  3146.  
  3147.    DosSetPriority ( PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, 0 ) ;
  3148.    DosSetPriority ( PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MINIMUM+(*Parms->Priority), 0 ) ;
  3149.  
  3150.   /**************************************************************************
  3151.    * Start up the high resolution timer, if it is available.                *
  3152.    **************************************************************************/
  3153.  
  3154.    BOOL HiResTimer = OpenTimer ( ) ;
  3155.  
  3156.   /**************************************************************************
  3157.    * Loop while active . . .                                                *
  3158.    **************************************************************************/
  3159.  
  3160.    while ( Parms->Active ) {
  3161.  
  3162.      /***********************************************************************
  3163.       * Reset the last time and count seen.                                 *
  3164.       ***********************************************************************/
  3165.  
  3166.       ULONG LastMilliseconds ;
  3167.       TIMESTAMP Time [2] ;
  3168.  
  3169.       if ( HiResTimer )
  3170.          GetTime ( &Time[0] ) ;
  3171.       else
  3172.          DosQuerySysInfo ( QSV_MS_COUNT, QSV_MS_COUNT, &LastMilliseconds, sizeof(LastMilliseconds) ) ;
  3173.  
  3174.       ULONG LastCounter = *Parms->Counter ;
  3175.  
  3176.      /***********************************************************************
  3177.       * Let the counter count.                                              *
  3178.       ***********************************************************************/
  3179.  
  3180.       DosSleep ( *Parms->Interval ) ;
  3181.  
  3182.      /***********************************************************************
  3183.       * Find out how much time and counts went by.                          *
  3184.       ***********************************************************************/
  3185.  
  3186.       ULONG CurrentCounter = *Parms->Counter ;
  3187.  
  3188.       ULONG DeltaMilliseconds ;
  3189.  
  3190.       if ( HiResTimer ) {
  3191.          GetTime ( &Time[1] ) ;
  3192.  
  3193.          ULONG Nanoseconds ;
  3194.          DeltaMilliseconds = ComputeElapsedTime ( &Time[0], &Time[1], &Nanoseconds ) ;
  3195.  
  3196.          if ( Nanoseconds >= 500000 )
  3197.             DeltaMilliseconds ++ ;
  3198.       } else {
  3199.          ULONG Milliseconds ;
  3200.          DosQuerySysInfo ( QSV_MS_COUNT, QSV_MS_COUNT, &Milliseconds, sizeof(Milliseconds) ) ;
  3201.          DeltaMilliseconds = Milliseconds - LastMilliseconds ;
  3202.       } /* endif */
  3203.  
  3204.      /***********************************************************************
  3205.       * Find out how much idle time was counted.  Adjust it to persecond.   *
  3206.       *   Tell the owner window to refresh its statistics.                  *
  3207.       ***********************************************************************/
  3208.  
  3209.       if ( DeltaMilliseconds ) {
  3210.          ULONG Counter = (ULONG) ( ( (double)(CurrentCounter-LastCounter) * 1000 ) / (double)DeltaMilliseconds ) ;
  3211.          WinPostMsg ( Parms->Owner, WM_REFRESH, MPFROMLONG(Counter), 0 ) ;
  3212.       } /* endif */
  3213.  
  3214.    } /* endwhile */
  3215.  
  3216.    MonitorThreadEvent.Post ( ) ;
  3217. }
  3218.  
  3219. /****************************************************************************
  3220.  *                                                                          *
  3221.  *      Update the Item List to reflect changes in the available drives.    *
  3222.  *                                                                          *
  3223.  ****************************************************************************/
  3224.  
  3225. STATIC BOOL UpdateDriveList ( HAB Anchor, HMODULE Library, HINI IniHandle,
  3226.    PINIDATA IniData, Dde_Server *pDdeServer, ULONG OldDrives, ULONG NewDrives, 
  3227.    ULONG &ResultDrives, ULONG &Exclude ) {
  3228.  
  3229.   /**************************************************************************
  3230.    * Get format strings.                                                    *
  3231.    **************************************************************************/
  3232.  
  3233.    ResourceString LabelFormat ( Library, IDS_DRIVE_FREE ) ;
  3234.  
  3235.   /**************************************************************************
  3236.    * Save the old item list for comparison.                                 *
  3237.    **************************************************************************/
  3238.  
  3239.    Item *OldItems [ ITEM_BASE_COUNT + MAX_DRIVES ] ;
  3240.  
  3241.    memset ( OldItems, 0, sizeof(OldItems) ) ;
  3242.  
  3243.    USHORT OldCount = 0 ;
  3244.    if ( OldDrives ) {
  3245.       OldCount = USHORT ( IniData->ItemCount ) ;
  3246.       memcpy ( OldItems, IniData->Items, sizeof(OldItems) ) ;
  3247.    } /* endif */
  3248.  
  3249.   /**************************************************************************
  3250.    * Add items for each drive on the system.                                *
  3251.    **************************************************************************/
  3252.  
  3253.    USHORT Count = ITEM_BASE_COUNT ;
  3254.    USHORT OldIndex = ITEM_BASE_COUNT ;
  3255.  
  3256.    ULONG LocalDrives = ( (TotalFree*) IniData->Items [ ITEM_TOTALFREE ] ) -> QueryMask ( ) ;
  3257.    ResultDrives = NewDrives ;
  3258.    NewDrives >>= 2 ;
  3259.    OldDrives >>= 2 ;
  3260.  
  3261.    BOOL Changed = FALSE ;
  3262.  
  3263.    for ( int Drive=3; Drive<=MAX_DRIVES; Drive++ ) {
  3264.  
  3265.       #ifdef DEBUG
  3266.          Log ( "Checking drive %c", Drive+'A'-1 ) ;
  3267.       #endif // DEBUG
  3268.  
  3269.       while ( ( OldIndex < OldCount )
  3270.          AND ( (SHORT)OldItems[OldIndex]->QueryId() < ITEM_BASE_COUNT + Drive ) ) {
  3271.          OldIndex ++ ;
  3272.          #ifdef DEBUG
  3273.             if ( OldIndex < OldCount ) {
  3274.                Log ( "OldIndex -> Drive %c", OldItems[OldIndex]->QueryId()-ITEM_BASE_COUNT+'A'-1 ) ;
  3275.             } else {
  3276.                Log ( "OldIndex -> EOL" ) ;
  3277.             } /* endif */
  3278.          #endif // DEBUG
  3279.       } /* endwhile */
  3280.  
  3281.       // If this drive exists currently . . .
  3282.       if ( NewDrives & 1 ) {
  3283.  
  3284.          // If this drive was in the old list . . . 
  3285.          if ( OldDrives & 1 ) {
  3286.  
  3287.             // If we're no longer showing remote drives, and this drive is remote . . .
  3288.             if ( !IniData->ShowRemoteDrives && !(LocalDrives&(1<<(Drive-1))) ) {
  3289.                // If the drive is in the list, remove it.
  3290.                if ( ( OldIndex < OldCount ) AND ( (SHORT)OldItems[OldIndex]->QueryId() == ITEM_BASE_COUNT + Drive ) ) {
  3291.                   #ifdef DEBUG
  3292.                      Log ( "Drive %c removed from list because no longer allowing remote drives.", Drive+'A'-1 ) ;
  3293.                   #endif // DEBUG
  3294.                   ResultDrives &= ~( 1 << (Drive-1) ) ; 
  3295.                   OldItems[OldIndex]->PutProfile ( IniHandle ) ;
  3296.                   delete OldItems[OldIndex++] ;
  3297.                   Changed = TRUE ;
  3298.                } /* endif */
  3299.  
  3300.             // Else, if we're now showing remote drives, and the drive is remote . . .
  3301.             } else if ( IniData->ShowRemoteDrives && !(LocalDrives&(1<<(Drive-1))) ) {
  3302.                // If the drive is not in the list, add it.
  3303.                if ( ( OldIndex >= OldCount ) OR ( (SHORT)OldItems[OldIndex]->QueryId() != ITEM_BASE_COUNT + Drive ) ) {
  3304.                   BYTE FileSystem [80] = { 0 } ;
  3305.                   BYTE DiskLabel [12] = { 0 } ;
  3306.                   int DriveType = CheckDrive ( USHORT(Drive), FileSystem, DiskLabel ) ;
  3307.                   if ( ( DriveType > 0 ) OR ( ( DriveType < 0 ) AND IniData->ShowRemoteDrives ) ) {
  3308.  
  3309.                      if ( DriveType > 0 )
  3310.                         LocalDrives |= ( 1 << (Drive-1) ) ;
  3311.  
  3312.                      #ifdef DEBUG
  3313.                         Log ( "Drive %c restored to list because now allowing remote drives.", Drive+'A'-1 ) ;
  3314.                      #endif // DEBUG
  3315.  
  3316.                      char Name [80] ;
  3317.                      sprintf ( Name,   "ShowDrive%c:", Drive+'A'-1 ) ;
  3318.  
  3319.                      char Label [80] ;
  3320.                      sprintf ( Label,  PCHAR(LabelFormat),  Drive+'A'-1 ) ;
  3321.  
  3322.                      IniData->Items[Count] = new DriveFree ( USHORT(ITEM_BASE_COUNT+Drive),
  3323.                         Name, Label, Label,  pDdeServer, "Items",
  3324.                         IniData->CountryInfo, IniData->ShowK, IniData->ShowTrueK, IniData->ShowM,
  3325.                         USHORT(Drive), IniData->DriveError,
  3326.                         IniData->ShowFileSystemNames, FileSystem,
  3327.                         IniData->ShowDiskLabels, DiskLabel ) ;
  3328.                      IniData->Items[Count++]->GetProfile ( IniHandle ) ;
  3329.                      Changed = TRUE ;
  3330.                   } else {
  3331.                      #ifdef DEBUG
  3332.                         Log ( "Drive %c not added to list because %s.", Drive+'A'-1, 
  3333.                            DriveType==0?"drive is not fixed":(DriveType<0?"drive is remote":"") ) ;
  3334.                      #endif // DEBUG
  3335.                      ResultDrives &= ~( 1 << (Drive-1) ) ; 
  3336.                      if ( strcmpi ( FileSystem, "CDFS" ) == 0 ) 
  3337.                         Exclude |= ( 1 << (Drive-1) ) ;
  3338.                   } /* endif */
  3339.                // Else if it was in the list, preserve it.
  3340.                } else {
  3341.                   #ifdef DEBUG
  3342.                      Log ( "Drive %c preserved in list.", Drive+'A'-1 ) ;
  3343.                   #endif // DEBUG
  3344.                   IniData->Items[Count++] = OldItems[OldIndex++] ;
  3345.                } /* endif */
  3346.  
  3347.             // Else, preserve the drive in the list, if it is there.
  3348.             } else {
  3349.                if ( ( OldIndex < OldCount ) AND ( (SHORT)OldItems[OldIndex]->QueryId() == ITEM_BASE_COUNT + Drive ) ) {
  3350.                   #ifdef DEBUG
  3351.                      Log ( "Drive %c preserved in list.", Drive+'A'-1 ) ;
  3352.                   #endif // DEBUG
  3353.                   IniData->Items[Count++] = OldItems[OldIndex++] ;
  3354.                } /* endif */
  3355.  
  3356.             } /* endif */
  3357.  
  3358.          // Else, if this drive didn't exist last time around . . .
  3359.          } else {
  3360.             BYTE FileSystem [80] = { 0 } ;
  3361.             BYTE DiskLabel [12] = { 0 } ;
  3362.             int DriveType = CheckDrive ( USHORT(Drive), FileSystem, DiskLabel ) ;
  3363.             if ( ( DriveType > 0 ) OR ( ( DriveType < 0 ) AND IniData->ShowRemoteDrives ) ) {
  3364.  
  3365.                if ( DriveType > 0 )
  3366.                   LocalDrives |= ( 1 << (Drive-1) ) ;
  3367.  
  3368.                #ifdef DEBUG
  3369.                   Log ( "Drive %c added to list.", Drive+'A'-1 ) ;
  3370.                #endif // DEBUG
  3371.  
  3372.                char Name [80] ;
  3373.                sprintf ( Name,   "ShowDrive%c:", Drive+'A'-1 ) ;
  3374.  
  3375.                char Label [80] ;
  3376.                sprintf ( Label,  PCHAR(LabelFormat),  Drive+'A'-1 ) ;
  3377.  
  3378.                IniData->Items[Count] = new DriveFree ( USHORT(ITEM_BASE_COUNT+Drive),
  3379.                   Name, Label, Label,  pDdeServer, "Items",
  3380.                   IniData->CountryInfo, IniData->ShowK, IniData->ShowTrueK, IniData->ShowM,
  3381.                   USHORT(Drive), IniData->DriveError,
  3382.                   IniData->ShowFileSystemNames, FileSystem,
  3383.                   IniData->ShowDiskLabels, DiskLabel ) ;
  3384.                IniData->Items[Count++]->GetProfile ( IniHandle ) ;
  3385.                Changed = TRUE ;
  3386.             } else {
  3387.                #ifdef DEBUG
  3388.                   Log ( "Drive %c not added to list because %s.", Drive+'A'-1, 
  3389.                      DriveType==0?"drive is not fixed":(DriveType<0?"drive is remote":"") ) ;
  3390.                #endif // DEBUG
  3391.                ResultDrives &= ~( 1 << (Drive-1) ) ; 
  3392.                if ( strcmpi ( FileSystem, "CDFS" ) == 0 ) 
  3393.                   Exclude |= ( 1 << (Drive-1) ) ;
  3394.             } /* endif */
  3395.  
  3396.          } /* endif */
  3397.  
  3398.       // Else, this drive no longer exists.
  3399.       } else {
  3400.          LocalDrives &= ~ ( 1 << (Drive-1) ) ;
  3401.          if ( OldDrives & 1 ) {
  3402.             if ( ( OldIndex < OldCount ) && ( OldItems[OldIndex]->QueryId() == ITEM_BASE_COUNT + Drive ) ) {
  3403.                #ifdef DEBUG
  3404.                   Log ( "Drive %c removed from list because it has disappeared.", Drive+'A'-1 ) ;
  3405.                #endif // DEBUG
  3406.                OldItems[OldIndex]->PutProfile ( IniHandle ) ;
  3407.                delete OldItems[OldIndex++] ;
  3408.                Changed = TRUE ;
  3409.             } else if ( OldIndex >= OldCount ) {
  3410.                #ifdef DEBUG
  3411.                   Log ( "Drive %c not removed from list because it was not there (short list).", Drive+'A'-1 ) ;
  3412.                #endif // DEBUG
  3413.             } else if ( OldItems[OldIndex]->QueryId() != ITEM_BASE_COUNT + Drive ) {
  3414.                #ifdef DEBUG
  3415.                   Log ( "Drive %c not removed from list because it was not there (missing entry).", Drive+'A'-1 ) ;
  3416.                #endif // DEBUG
  3417.             } /* endif */
  3418.          } else {
  3419.             // Do nothing.
  3420.          } /* endif */
  3421.  
  3422.       } /* endif */
  3423.  
  3424.       NewDrives >>= 1 ;
  3425.       OldDrives >>= 1 ;
  3426.  
  3427.    } /* endfor */
  3428.  
  3429.   /**************************************************************************
  3430.    * Save the new item count.                                               *
  3431.    **************************************************************************/
  3432.  
  3433.    IniData->ItemCount = Count ;
  3434.  
  3435.   /**************************************************************************
  3436.    * Update the total free space object.                                    *
  3437.    **************************************************************************/
  3438.  
  3439.    ( (TotalFree*) IniData->Items [ ITEM_TOTALFREE ] ) -> ResetMask ( LocalDrives ) ;
  3440.  
  3441.   /**************************************************************************
  3442.    * Give everyone their colors.                                            *
  3443.    **************************************************************************/
  3444.  
  3445.    for ( int i=0; i<IniData->ItemCount; i++ ) {
  3446.       Item *pItem = IniData->Items[i] ;
  3447.       pItem->SetWarningLevel  ( pItem->QueryWarningLevel() ) ;
  3448.       pItem->SetErrorLevel    ( pItem->QueryErrorLevel() ) ;
  3449.       pItem->SetNormalColors  ( IniData->BackColor, IniData->TextColor ) ;
  3450.       pItem->SetWarningColors ( IniData->WarningBackground, IniData->WarningForeground ) ;
  3451.       pItem->SetErrorColors   ( IniData->ErrorBackground, IniData->ErrorForeground ) ;
  3452.    } /* endfor */
  3453.  
  3454.   /**************************************************************************
  3455.    * Return final status: Did the list really change?                       *
  3456.    **************************************************************************/
  3457.  
  3458.    return ( Changed ) ;
  3459. }
  3460.  
  3461. /****************************************************************************
  3462.  *                                                                          *
  3463.  *      Check to see if drive should be added to display list.              *
  3464.  *                                                                          *
  3465.  ****************************************************************************/
  3466.  
  3467. STATIC int CheckDrive ( USHORT Drive, PBYTE FileSystem, PBYTE DiskLabel ) {
  3468.  
  3469.   /**************************************************************************
  3470.    * First, check to see if drive is local or remote.  Remote drives are    *
  3471.    *   always monitored.                                                    *
  3472.    **************************************************************************/
  3473.  
  3474.    BYTE Path [3] ;
  3475.    Path[0] = (BYTE) ( Drive + 'A' - 1 ) ;
  3476.    Path[1] = ':' ;
  3477.    Path[2] = 0 ;
  3478.  
  3479.    #ifdef DEBUG
  3480.       Log ( "CheckDrive() About to query drive %s for file system.", Path ) ;
  3481.    #endif
  3482.  
  3483.    DosError ( FERR_DISABLEHARDERR ) ;
  3484.  
  3485.    BYTE Buffer [1024] ;
  3486.    ULONG Size = sizeof(Buffer) ;
  3487.    ULONG Status = DosQueryFSAttach ( Path, 0, FSAIL_QUERYNAME, (PFSQBUFFER2)Buffer, &Size ) ;
  3488.    DosError ( FERR_ENABLEHARDERR ) ;
  3489.  
  3490.    if ( Status == ERROR_NOT_READY ) {
  3491.       #ifdef DEBUG
  3492.          Log ( "CheckDrive() ERROR: Drive not ready.  Will assume it is removable media.", Path, Status ) ;
  3493.       #endif
  3494.       // We'll guess this is removable media, as fixed drives should never return this status.
  3495.       strcpy ( FileSystem, "CDFS" ) ;
  3496.       return ( 0 ) ;   // Don't monitor.
  3497.    } else if ( Status ) {
  3498.       #ifdef DEBUG
  3499.          Log ( "CheckDrive() ERROR: Unable to query drive %s for file system.  Status %04X.", Path, Status ) ;
  3500.       #endif
  3501.       return ( 0 ) ;   // Don't monitor.
  3502.    } /* endif */
  3503.  
  3504.    USHORT cbName = PFSQBUFFER2(Buffer)->cbName ;
  3505.    strcpy ( PCHAR(FileSystem), PCHAR(PFSQBUFFER2(Buffer+cbName)->szFSDName) ) ;
  3506.  
  3507.    #ifdef DEBUG
  3508.       Log ( "CheckDrive() Drive %s file system '%s'.", Path, FileSystem ) ;
  3509.    #endif
  3510.  
  3511.    if ( PFSQBUFFER2(Buffer)->iType == FSAT_REMOTEDRV ) {
  3512.       #ifdef DEBUG
  3513.          Log ( "CheckDrive() Drive %s is remote.", Path ) ;
  3514.       #endif
  3515.       return ( -1 ) ;  // Monitor but don't include in the total over all drives.
  3516.    } /* endif */
  3517.  
  3518.    if ( strcmpi ( FileSystem, "CDFS" ) == 0 ) {
  3519.       #ifdef DEBUG
  3520.          Log ( "CheckDrive() Drive %s is a CD-ROM.", Path ) ;
  3521.       #endif
  3522.       return ( 0 ) ;  // Reject CDs.
  3523.    } /* endif */
  3524.  
  3525.   /**************************************************************************
  3526.    * Attempt to open the local drive as an entire device.  If unable to do  *
  3527.    *   so, we cannot monitor this drive.                                    *
  3528.    **************************************************************************/
  3529.  
  3530.    ULONG Action ;
  3531.    HFILE Handle ;
  3532.    Status = DosOpen ( Path, &Handle, &Action, 0, 0, FILE_OPEN,
  3533.       OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE |
  3534.       OPEN_FLAGS_DASD | OPEN_FLAGS_FAIL_ON_ERROR, 0 ) ;
  3535.  
  3536.    if ( Status ) {
  3537.       #ifdef DEBUG
  3538.          Log ( "CheckDrive() ERROR: Unable to open local drive %s.  Status %04X.", Path, Status ) ;
  3539.       #endif
  3540.       return ( 0 ) ;   // Don't monitor.
  3541.    } /* endif */
  3542.  
  3543.   /**************************************************************************
  3544.    * Check to see if the drive has removable media.                         *
  3545.    *   We cannot monitor true removable media because of how the media      *
  3546.    *   check function ties up the system.                                   *
  3547.    **************************************************************************/
  3548.  
  3549.    BOOL Addit = FALSE ;
  3550.    BYTE Command = 0 ;
  3551.    BYTE NonRemovable ;
  3552.  
  3553.    ULONG LengthIn = sizeof(Command) ;
  3554.    ULONG LengthOut = sizeof(NonRemovable);
  3555.  
  3556.    if ( NOT DosDevIOCtl ( Handle, 8, 0x20, &Command, sizeof(Command), &LengthIn,
  3557.       &NonRemovable, sizeof(NonRemovable), &LengthOut ) ) {
  3558.  
  3559.       Addit = NonRemovable ;
  3560.  
  3561.       #ifdef DEBUG
  3562.          Log ( "CheckDrive() Drive %s is %sremovable.", Path, NonRemovable?"non":"" ) ;
  3563.       #endif
  3564.  
  3565.       if ( !NonRemovable && IsSVDisk((UCHAR)Drive) ) {
  3566.          #ifdef DEBUG
  3567.             Log ( "CheckDrive() Drive %s is a Super Virtual Disk.", Path ) ;
  3568.          #endif
  3569.          Addit = TRUE ;
  3570.       } /* endif */
  3571.  
  3572.    } /* endif */
  3573.  
  3574.   /**************************************************************************
  3575.    * Close the drive.                                                       *
  3576.    **************************************************************************/
  3577.  
  3578.    DosClose ( Handle ) ;
  3579.  
  3580.   /**************************************************************************
  3581.    * Get the drive label.                                                   *
  3582.    **************************************************************************/
  3583.  
  3584.    #ifdef DEBUG
  3585.       Log ( "CheckDrive() Querying drive %s for label.", Path ) ;
  3586.    #endif
  3587.  
  3588.    FSINFO Info ;
  3589.    if ( DosQueryFSInfo ( Drive, FSIL_VOLSER, PBYTE(&Info), sizeof(Info) ) == 0 ) {
  3590.       #ifdef DEBUG
  3591.          Log ( "CheckDrive() Drive %s label is '%0.*s'.", Path, sizeof(Info.vol.szVolLabel), Info.vol.szVolLabel ) ;
  3592.       #endif
  3593.       strcpy ( PCHAR(DiskLabel), PCHAR(Info.vol.szVolLabel) ) ;
  3594.    } /* endif */
  3595.  
  3596.   /**************************************************************************
  3597.    * Return the final verdict.                                              *
  3598.    **************************************************************************/
  3599.  
  3600.    #ifdef DEBUG
  3601.       Log ( "CheckDrive() Drive %s will %sbe monitored.", Path, Addit?"":"not " ) ;
  3602.    #endif
  3603.  
  3604.    return ( int(Addit) ) ;    // Monitor and include in overall total if not removable.
  3605. }
  3606.  
  3607. /****************************************************************************
  3608.  *                                                                          *
  3609.  *                       Calibrate the Load Meter                           *
  3610.  *                                                                          *
  3611.  ****************************************************************************/
  3612.  
  3613. STATIC ULONG CalibrateLoadMeter ( PCOUNTER_PARMS Parms ) {
  3614.  
  3615.  /***************************************************************************
  3616.   * Set result to zero as a default.                                        *
  3617.   ***************************************************************************/
  3618.  
  3619.   double AdjustedMaxLoad = 0.0 ;
  3620.  
  3621.  /***************************************************************************
  3622.   * If HRTIMER.SYS has been installed . . .                                 *
  3623.   ***************************************************************************/
  3624.  
  3625.   if ( OpenTimer ( ) ) {
  3626.  
  3627.    /*************************************************************************
  3628.     * Increase this thread's priority to the maximum.                       *
  3629.     *************************************************************************/
  3630.  
  3631.     DosSetPriority ( PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, 0 ) ;
  3632.  
  3633.    /*************************************************************************
  3634.     * Create the calibration thread and set its priority next highest.      *
  3635.     *************************************************************************/
  3636.  
  3637.     CounterThreadEvent.Reset ( ) ;
  3638.     Parms->Active = TRUE ;
  3639.     TID tidCalibrate = StartThread ( "CounterThread", CounterThread, 0x3000, Parms ) ;
  3640.     DosSuspendThread ( tidCalibrate ) ;
  3641.     DosSetPriority ( PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, tidCalibrate ) ;
  3642.     DosSetPriority ( PRTYS_THREAD, PRTYC_TIMECRITICAL, -1, tidCalibrate ) ;
  3643.  
  3644.    /*************************************************************************
  3645.     * Reset the calibration count, get the time, and let the counter go.    *
  3646.     *************************************************************************/
  3647.  
  3648.     Parms->Counter = 0 ;
  3649.     TIMESTAMP Time[2] ;
  3650.     GetTime ( &Time[0] ) ;
  3651.     DosResumeThread ( tidCalibrate ) ;
  3652.  
  3653.    /*************************************************************************
  3654.     * Sleep for one second.                                                 *
  3655.     *************************************************************************/
  3656.  
  3657.     DosSleep ( 1000 ) ;
  3658.  
  3659.    /*************************************************************************
  3660.     * Suspend the calibration counter and get the time.                     *
  3661.     *************************************************************************/
  3662.  
  3663.     Parms->Active = FALSE ;
  3664.     CounterThreadEvent.Wait ( 10000 ) ;
  3665.     GetTime ( &Time[1] ) ;
  3666.  
  3667.    /*************************************************************************
  3668.     * Return priorities to normal.                                          *
  3669.     *************************************************************************/
  3670.  
  3671.     DosSetPriority ( PRTYS_THREAD, PRTYC_REGULAR, 0, 0 ) ;
  3672.  
  3673.    /*************************************************************************
  3674.     * Get the elapsed time and adjust the calibration count.                *
  3675.     *************************************************************************/
  3676.  
  3677.     ULONG Milliseconds ;
  3678.     ULONG Nanoseconds ;
  3679.     Milliseconds = ComputeElapsedTime ( &Time[0], &Time[1], &Nanoseconds ) ;
  3680.  
  3681.     AdjustedMaxLoad = (double)Parms->Counter * 1.0E9 ;
  3682.     AdjustedMaxLoad /= (double)Milliseconds*1.0E6L + (double)Nanoseconds ;
  3683.  
  3684.    /*************************************************************************
  3685.     * Close down the connection to HRTIMER.SYS.                             *
  3686.     *************************************************************************/
  3687.  
  3688.     CloseTimer ( ) ;
  3689.   }
  3690.  
  3691.  /***************************************************************************
  3692.   * Return the adjusted calibration count.  If HRTIMER was not there, it    *
  3693.   *   will be zero.                                                         *
  3694.   ***************************************************************************/
  3695.  
  3696.   return ( (ULONG)AdjustedMaxLoad ) ;
  3697. }
  3698.  
  3699. /****************************************************************************
  3700.  *                                                                          *
  3701.  *                    General Purpose Counter Thread                        *
  3702.  *                                                                          *
  3703.  ****************************************************************************/
  3704.  
  3705. STATIC void CounterThread ( void *Parameter ) {
  3706.  
  3707.   /*************************************************************************
  3708.    * Count like mad.                                                       *
  3709.    *************************************************************************/
  3710.  
  3711.    PCOUNTER_PARMS Parms = PCOUNTER_PARMS ( Parameter ) ;
  3712.    while ( Parms->Active ) {
  3713.       Parms->Counter ++ ;
  3714.    } /* endwhile */
  3715.  
  3716.    CounterThreadEvent.Post ( ) ;
  3717. }
  3718.  
  3719.