home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / SYSINFO.ZIP / SYSINFO.C next >
C/C++ Source or Header  |  1990-10-12  |  18KB  |  698 lines

  1. /*----------------------------------
  2.    SysInfo.c - summary of system statistics
  3.  
  4.   Largest free memory block, updated every .75 seconds
  5.   Displays Free CPU cycles,  updated every .75 seconds
  6.   Time of day,               updated every .75 seconds
  7.   swap file size,            updated every 3   seconds
  8.   free disk space on 1 drv,  updated every 3   seconds
  9.  
  10.   Automatically positions itself at the top of the screen in a box 2.5
  11.   system characters high.  Double clicking anywhere in the client window
  12.   will cause the the frame controls to be hidden, or restored if already
  13.   hidden.  Keyboard accelerators will still work while the frame is hidden.
  14.  
  15.   Program can also be minimized.
  16.  
  17.   ----------------------------------*/
  18.  
  19. #define INCL_WIN
  20. #define INCL_GPI
  21. #define INCL_DOS
  22.  
  23. #include <os2.h>
  24. #include <string.h>
  25. #include <stdlib.h>
  26. #include <stdio.h>
  27. #include <ctype.h>
  28. #include <time.h>
  29. #include <process.h>
  30.  
  31. #define ID_TIMER 1
  32. #define MAX_CHILDREN 10
  33. #define CH_MEMTEXT    1
  34. #define CH_MEMVAL     0
  35. #define CH_SWAPTEXT   3
  36.  
  37. #define CH_SWAPVAL    2
  38. #define CH_CLOCKTEXT  5
  39. #define CH_CLOCKVAL   4
  40. #define CH_CPUTEXT    7
  41. #define CH_CPUVAL     6
  42. #define CH_DISKTEXT   9
  43. #define CH_DISKVAL    8
  44.  
  45. #define SWAPFILE      "c:\\os2\\system\\swapper.dat"
  46.  
  47. MRESULT EXPENTRY ClientWndProc (HWND, USHORT, MPARAM, MPARAM) ;
  48. MRESULT EXPENTRY ChildProc (HWND, USHORT, MPARAM, MPARAM) ;
  49. VOID             SizeTheWindow( HWND );
  50. void             SwitchList( HWND hwndFrame, HPOINTER hptrIcon );
  51. void far cdecl   CountCyc( PVOID nl );
  52. void             GetFontInfo(HWND hwnd, PUSHORT cyChar, PUSHORT cxChar, PUSHORT cyDesc);
  53. int              ComputeFree(short DriveNum, float *fAvail );
  54. SHORT            CreateChildren( HWND hwndParent );
  55. VOID             ToggleFrameControls( HWND hwndFrame );
  56. VOID             UpdateLong( PHWND ahwndChild );
  57. VOID             UpdateShort( PHWND ahwndChild );
  58.  
  59. // window handles for hiding frame controls and creating children
  60. HWND             hwndFrame, hwndSys, hwndMin, hwndTitle;
  61. HWND             hwndChild[ MAX_CHILDREN ];
  62. SHORT            fHidden = 0;
  63.  
  64. // font info for sizing windows
  65. SHORT            cyChar, cxChar, cyDesc;
  66.  
  67. // raw data from CPU cycles count
  68. ULONG            uCalibVal = 0, uCurVal = 0, ulLast = 1;
  69.  
  70. // params for free disk space
  71. USHORT           usDriveNum = 3, fIsRed;
  72. float            fFreeSpace = 0.0;
  73.  
  74. // size of the swap file
  75. ULONG            ulSwapSize = 0;
  76.  
  77. // largest free block
  78. ULONG            ulFrSize = 0;
  79.  
  80.  
  81. /*
  82. Function:  main
  83.  
  84. Description:
  85.     Entry point for system info program.  Creates the client window and
  86.     starts the thread for the CPU monitor.  Takes two command line params.
  87.     First param is the drive letter.  If not present it defaults to C.  This
  88.     is the drive on which the free space will be monitored.
  89.  
  90.     If a second param is present and equal to /cal, the cpu counter will
  91.     be recalibrated.  This should be done with no other programs running
  92.     to get a better idea of a true idle system.
  93.  
  94. Values Returned:
  95.     None.
  96.  
  97. Notes:
  98.  
  99. */
  100.  
  101. int main ( int argc, char **argv )
  102.  
  103. {
  104. static PSZ   pszClientClass = "System Info" ;
  105. static ULONG flFrameFlags = FCF_TITLEBAR  | FCF_SYSMENU  | FCF_ICON |
  106.                             FCF_MINBUTTON | FCF_BORDER;
  107. CHAR         achBuf[12];
  108. HPOINTER     hwndIcon;       /* handle to our programs icon */
  109. HAB          hab;
  110. HMQ          hmq;
  111. HWND         hwndClient;
  112. QMSG         qmsg;
  113.  
  114. usDriveNum = 3;
  115.  
  116. PrfQueryProfileString( HINI_USERPROFILE, "System Info",
  117.                        "Calibration Value", "0", achBuf, 12L );
  118. uCalibVal = atol( achBuf );
  119.  
  120. if ( argc >= 2 )
  121.     usDriveNum = toupper( *argv[1] ) - 'A' + 1;  // pick up a drive letter.
  122. if ( argc == 3 && !stricmp( argv[2], "/cal" ) )
  123.     uCalibVal = 0;      // mark for recal
  124.  
  125. _beginthread( CountCyc, NULL, 8000, NULL );
  126.  
  127. hab = WinInitialize( 0 );
  128. hmq = WinCreateMsgQueue( hab, 0 );
  129.  
  130. WinRegisterClass(hab, pszClientClass, ClientWndProc, CS_MOVENOTIFY, 0 );
  131. WinRegisterClass(hab, "InfoChild", ChildProc, 0, 6 );
  132.  
  133. hwndFrame = WinCreateStdWindow( HWND_DESKTOP, WS_VISIBLE,
  134.                                 &flFrameFlags, pszClientClass, pszClientClass,
  135.                                 0L, 0, 1, &hwndClient );
  136.  
  137. /* Add our title to the task list maintained by Task Manager */
  138. hwndIcon = WinLoadPointer( HWND_DESKTOP, 0, 1 );
  139. SwitchList( hwndFrame, hwndIcon );
  140.  
  141. SizeTheWindow( hwndFrame );
  142.  
  143. CreateChildren( hwndClient );
  144. ToggleFrameControls( hwndFrame );
  145.  
  146. WinStartTimer (hab, hwndClient, ID_TIMER, 750 );
  147.  
  148. while (WinGetMsg (hab, &qmsg, NULL, 0, 0 ) )
  149.     WinDispatchMsg (hab, &qmsg) ;
  150.  
  151. WinStopTimer (hab, hwndClient, ID_TIMER) ;
  152.  
  153. // store the calibration value on exit
  154. sprintf( achBuf, "%lu", uCalibVal );
  155. PrfWriteProfileString( HINI_USERPROFILE, "System Info",
  156.                                 "Calibration Value", achBuf );
  157.  
  158. WinDestroyWindow( hwndFrame );
  159. WinDestroyMsgQueue( hmq );
  160. WinDestroyPointer( hwndIcon );
  161. WinTerminate( hab );
  162. DosExit( EXIT_PROCESS, 0 );
  163. }
  164.  
  165. /*
  166. Function:  SizeTheWindow
  167.  
  168. Description:
  169.     Set the initial size of the window at 2.5 character heights and for the
  170.     entire width of the display.  Positions it at the top of the screen.
  171.  
  172. Values Returned:
  173.     None
  174.  
  175. Notes:
  176.     I stole this code from a petzold sample.
  177.  
  178. */
  179.  
  180.  
  181. VOID SizeTheWindow (HWND hwndFrame)
  182.  
  183. {
  184. USHORT        usCxScreen, usCyScreen, usCyBorder;
  185. RECTL         rcl;
  186.  
  187. usCxScreen = (USHORT)WinQuerySysValue( HWND_DESKTOP, SV_CXSCREEN );
  188. usCyScreen = (USHORT)WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN );
  189. usCyBorder = (USHORT)WinQuerySysValue( HWND_DESKTOP, SV_CYBORDER );
  190.  
  191. rcl.yBottom = 0 ;
  192. rcl.yTop    = 2 * cyChar;
  193. rcl.xLeft   = 0 ;
  194. rcl.xRight  = usCyScreen - 2 * usCyBorder;
  195.  
  196. /* now figure out the size of the frame rectangle */
  197. WinCalcFrameRect( hwndFrame, &rcl, FALSE );
  198.  
  199. /* ... and shift to the top line of the screen */
  200. rcl.yBottom = usCyScreen - (rcl.yTop - rcl.yBottom);
  201. rcl.yTop    = usCyScreen;
  202. rcl.xRight  = usCxScreen;
  203. rcl.xLeft   = 0;
  204.  
  205. WinSetWindowPos (hwndFrame, NULL, (SHORT) rcl.xLeft, (SHORT) rcl.yBottom,
  206.                 (SHORT) (rcl.xRight - rcl.xLeft),
  207.                 (SHORT) (rcl.yTop - rcl.yBottom), SWP_SIZE | SWP_MOVE) ;
  208. }
  209.  
  210. /*
  211. Function:  ClientWndProc
  212.  
  213. Description:
  214.     Window procedure for the main window.  Really does very little except
  215.     call other functions to do something useful.
  216.  
  217. Values Returned:
  218.     MRESULTS
  219.  
  220. Notes:
  221.  
  222. */
  223.  
  224. MRESULT EXPENTRY ClientWndProc(HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  225. {
  226. static SHORT   sTicks = 0;
  227.  
  228. switch (msg)
  229.     {
  230.     case WM_CREATE:
  231.        GetFontInfo( hwnd, &cyChar, &cxChar, &cyDesc );
  232.        return 0;
  233.  
  234.     case WM_BUTTON1DOWN:
  235.         if ( fHidden )
  236.             return WinSendMsg( hwndFrame, WM_TRACKFRAME,
  237.                           (MPARAM)( SHORT1FROMMP(mp2) | TF_MOVE ), NULL );
  238.         return 0;
  239.  
  240.     case WM_BUTTON1DBLCLK:
  241.         ToggleFrameControls( hwndFrame );
  242.         return 0;
  243.  
  244.     case WM_TIMER:
  245.         if ( (sTicks % 4) == 0 )    // every three seconds do the disk parms
  246.             UpdateLong( hwndChild );
  247.         UpdateShort( hwndChild );
  248.         sTicks++;
  249.         return 0;
  250.  
  251.     case WM_ERASEBACKGROUND:
  252.         return MRFROMSHORT(TRUE);
  253.     }
  254.  
  255. return WinDefWindowProc (hwnd, msg, mp1, mp2) ;
  256. }
  257.  
  258.  
  259.  
  260. /*
  261. Function:  SwitchList
  262.  
  263. Description:
  264.     Add our program name to the switch list maintained by the system.
  265.  
  266. Values Returned:
  267.     None
  268.  
  269. Notes:
  270.  
  271. */
  272.  
  273. void SwitchList( HWND hwndFrame, HPOINTER hptrIcon )
  274.  
  275. {
  276. SWCNTRL swctl;       /* switch list entry structure                  */
  277.  
  278. WinQueryWindowProcess( hwndFrame, &swctl.idProcess, NULL );
  279. swctl.idSession      = 0;
  280. swctl.fReserved      = 0;
  281. swctl.hprog          = NULL;
  282. swctl.hwnd           = hwndFrame;
  283. swctl.hwndIcon       = hptrIcon;
  284. swctl.uchVisibility  = SWL_VISIBLE;
  285. swctl.fbJump         = SWL_JUMPABLE;
  286. strcpy( swctl.szSwtitle, "System Information" );
  287.  
  288. WinAddSwitchEntry( &swctl );
  289.  
  290. return;
  291. }
  292.  
  293. /*
  294. Function:  CountCyc
  295.  
  296. Description:
  297.     Separate thread that runs at idle class, priority one.  Since the system
  298.     provides an idle class, priority zero thread, setting it to one gives
  299.     a better value for idle time.
  300.  
  301.     Simply counts iterations of a loop every 750 milliseconds. That value
  302.     is then compared to the number of iterations we were able to do when
  303.     the system was idle.
  304.  
  305. Values Returned:
  306.     None
  307.  
  308. Notes:
  309.  
  310. */
  311.  
  312.  
  313. void far cdecl CountCyc( PVOID nl )
  314.  
  315. {
  316. SEL           selGlobalSeg,     /* selector num for global info seg         */
  317.               selLocalSeg;      /* selector num for local info seg          */
  318. GINFOSEG FAR  *pgis;            /* pointer to the global info seg           */
  319. ULONG         lMils;
  320. ULONG         uBldVal;
  321.  
  322. DosGetInfoSeg(&selGlobalSeg, &selLocalSeg); /* get local & global info segs */
  323. pgis = MAKEPGINFOSEG( selGlobalSeg );   /* get a pointer to the global  */
  324.  
  325. if ( uCalibVal == 0L )
  326.     {
  327.     DosEnterCritSec();
  328.     DosSetPrty( PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, 0 );
  329.  
  330.     lMils = pgis->msecs + 3750;
  331.     while( pgis->msecs < lMils )
  332.         uCalibVal++;
  333.  
  334.     DosExitCritSec();
  335.     uCalibVal /= 5;
  336.     }
  337.  
  338. // set priority to idle, 1 so that we avoid conflict with system idle thread.
  339. DosSetPrty( PRTYS_THREAD, PRTYC_IDLETIME, PRTYD_MINIMUM, 0 );
  340. DosSetPrty( PRTYS_THREAD, PRTYC_IDLETIME, 1, 0 );
  341. while( 1 )
  342.     {
  343.     lMils = pgis->msecs + 750;
  344.     uBldVal = 0L;
  345.     while( pgis->msecs < lMils )
  346.         uBldVal++;
  347.  
  348.     uCurVal = uBldVal;
  349.     }
  350.  
  351. }
  352.  
  353.  
  354. /*
  355. Function:  ComputeFree
  356.  
  357. Description:
  358.     Compute free space on the specified drive.  Set the free space as
  359.     a float point value representing free MB.
  360.  
  361. Values Returned:
  362.     0 - drive has more the 10% free
  363.     1 - drive is within 10% of being full
  364.  
  365. Notes:
  366.  
  367. */
  368.  
  369. int ComputeFree( short DriveNum, float *fAvail )
  370.  
  371. {
  372. FSALLOCATE fsaBuf;
  373. float fTotFree;
  374.  
  375. DosQFSInfo( DriveNum, 1, (PCHAR)&fsaBuf, sizeof( fsaBuf ) );
  376. fTotFree = (float)fsaBuf.cbSector * (float)fsaBuf.cSectorUnit * 
  377.            (float)fsaBuf.cUnitAvail;
  378. fTotFree /= (float)0x100000;
  379.  
  380. *fAvail = fTotFree;
  381.        
  382. if ( fsaBuf.cUnitAvail * 10 < fsaBuf.cUnit )  
  383.     return( 1 );   /* less than 10% space free */
  384. else
  385.     return( 0 );
  386. }
  387.  
  388.  
  389. /*
  390. Function:  GetFontInfo
  391.  
  392. Description:
  393.  
  394.         Call WinQueryFontMetrics to determine information about the system font
  395.  
  396. Values Returned:
  397.     None.
  398.  
  399. Notes:
  400.  
  401. */
  402.  
  403. void GetFontInfo( HWND hwnd, USHORT *cy, USHORT *cx, USHORT *cd )
  404.  
  405. {
  406. HPS          hps;               /* need a ps before calling font metrics */
  407. FONTMETRICS  fm;               /* info about the current font      */
  408.  
  409.  
  410. hps = WinGetPS( hwnd );     /* need a PS for query Font */
  411. GpiQueryFontMetrics( hps, (LONG)sizeof(fm), &fm );
  412. WinReleasePS( hps );        /* done with the ps now */
  413.  
  414. *cy = (SHORT)fm.lMaxBaselineExt;    /* max height of one character   */
  415. *cx = (SHORT)fm.lAveCharWidth;      /* average width of a character  */
  416. *cd = (SHORT)fm.lMaxDescender;      /* max descender of a char       */
  417.  
  418. return;
  419. }
  420.  
  421.  
  422. /*
  423. Function:  CreateChildren
  424.  
  425. Description:
  426.     Create  the ten child windows in a double row.  All windows are static
  427.     text.  The leftmost windows are aligned on the left, the rightmost on the
  428.     right, all others are centered.
  429.  
  430. Values Returned:
  431.     0 - no error
  432.     1 - error
  433.  
  434. Notes:
  435.  
  436. */
  437.  
  438.  
  439. SHORT CreateChildren( HWND hwndParent )
  440.  
  441. {
  442. short i, x, y, cx, cy;
  443. SWP   swp;
  444.  
  445. WinQueryWindowPos( hwndParent, &swp );
  446.  
  447. for( i = 0; i < 10; i+= 2 )
  448.     {
  449.     x = (swp.cx / 5) * (i/2);
  450.     y = 0;
  451.     cx = swp.cx / 5;
  452.     cy = swp.cy / 2;
  453.  
  454.     hwndChild[i] = WinCreateWindow( hwndParent, "InfoChild", NULL,
  455.                    WS_VISIBLE, x, y, cx, cy, NULL, HWND_TOP, i, NULL, NULL );
  456.     WinSetWindowPtr( hwndChild[i], 2, malloc( 100 ) );
  457.  
  458.     y = swp.cy / 2;
  459.     hwndChild[i + 1] = WinCreateWindow( hwndParent, "InfoChild", NULL,
  460.                    WS_VISIBLE, x, y, cx, cy, NULL, HWND_TOP, i + 1,  NULL, NULL );
  461.     WinSetWindowPtr( hwndChild[i + 1], 2, malloc( 100 ) );
  462.     if ( hwndChild[ i ] == NULL || hwndChild[ i + 1 ] == NULL )
  463.         return 1;
  464.     }
  465.  
  466. strcpy( WinQueryWindowPtr( hwndChild[ CH_CPUTEXT ],   2 ),  "CPU Usage" );
  467. strcpy( WinQueryWindowPtr( hwndChild[ CH_MEMTEXT ],   2 ), "Free Memory" );
  468. strcpy( WinQueryWindowPtr( hwndChild[ CH_SWAPTEXT ],  2 ), "Swap File Size" );
  469. strcpy( WinQueryWindowPtr( hwndChild[ CH_DISKTEXT ],  2 ), "Free Disk Space" );
  470. strcpy( WinQueryWindowPtr( hwndChild[ CH_CLOCKTEXT ], 2 ), "Time of day" );
  471. strcpy( WinQueryWindowPtr( hwndChild[ CH_CPUVAL ],   2 ),  "" );
  472. strcpy( WinQueryWindowPtr( hwndChild[ CH_MEMVAL ],   2 ), "" );
  473. strcpy( WinQueryWindowPtr( hwndChild[ CH_SWAPVAL ],  2 ), "" );
  474. strcpy( WinQueryWindowPtr( hwndChild[ CH_DISKVAL ],  2 ), "" );
  475. strcpy( WinQueryWindowPtr( hwndChild[ CH_CLOCKVAL ], 2 ), "" );
  476.  
  477. UpdateShort( hwndChild );
  478. UpdateLong( hwndChild );
  479. return 0;
  480. }
  481.  
  482.  
  483.  
  484. /*
  485. Function:  ToggleFrameControls
  486.  
  487. Description:
  488.     if frame controls are hidden, restore them, if visible hide them.
  489.  
  490.  
  491. Values Returned:
  492.     None
  493.  
  494. Notes:
  495.     I stole this code from an MS sample
  496. */
  497.  
  498.  
  499.  
  500. VOID ToggleFrameControls( HWND hwndFrame )
  501.  
  502. {
  503.  
  504. if ( !fHidden )  // hide the controls
  505.     {
  506.     hwndTitle = WinWindowFromID( hwndFrame, FID_TITLEBAR );
  507.     hwndSys = WinWindowFromID( hwndFrame, FID_SYSMENU );
  508.     hwndMin = WinWindowFromID( hwndFrame,  FID_MINMAX );
  509.  
  510.     WinSetParent( hwndTitle, HWND_OBJECT, FALSE );
  511.     WinSetParent( hwndSys, HWND_OBJECT, FALSE );
  512.     WinSetParent( hwndMin, HWND_OBJECT, FALSE );
  513.  
  514.     WinSendMsg( hwndFrame, WM_UPDATEFRAME, (MPARAM)(FCF_TITLEBAR | FCF_SYSMENU | FCF_MINBUTTON),
  515.                 NULL ) ;
  516.     fHidden = TRUE;
  517.  
  518.     SizeTheWindow( hwndFrame );
  519.     }
  520. else
  521.     {
  522.     WinSetParent( hwndTitle, hwndFrame, FALSE );
  523.     WinSetParent( hwndSys, hwndFrame, FALSE );
  524.     WinSetParent( hwndMin, hwndFrame, FALSE );
  525.  
  526.     WinSendMsg( hwndFrame, WM_UPDATEFRAME, (MPARAM)(FCF_TITLEBAR | FCF_SYSMENU | FCF_MINBUTTON),
  527.                 NULL );
  528.     fHidden = FALSE;
  529.     SizeTheWindow( hwndFrame );
  530.     }
  531.  
  532. return;
  533. }
  534.  
  535. /*
  536. Function:  UpdateLong
  537.  
  538. Description:
  539.     Update the parameters that are done every three seconds -- swap file,
  540.     disk space.
  541.  
  542. Values Returned:
  543.     None
  544.  
  545. Notes:
  546.  
  547. */
  548.  
  549.  
  550.  
  551.  
  552. VOID UpdateLong( PHWND ahwndChild )
  553.  
  554. {
  555. float      fTmp;
  556. CHAR       achSpace[20];
  557. FILESTATUS fs;
  558.  
  559. fTmp = fFreeSpace;
  560. fIsRed = ComputeFree( usDriveNum, &fFreeSpace );
  561. if ( fFreeSpace != fTmp )   // drive space has changed
  562.     {
  563.     if ( fIsRed )
  564.         WinSetWindowUShort( ahwndChild[ CH_DISKVAL ], 0, 1 );
  565.     else
  566.         WinSetWindowUShort( ahwndChild[ CH_DISKVAL ], 0, 0 );
  567.     sprintf( achSpace, "%c: %3.1f MB", usDriveNum + 'A' - 1, fFreeSpace );
  568.     strcpy( WinQueryWindowPtr( ahwndChild[ CH_DISKVAL ], 2 ), achSpace );
  569.     WinInvalidateRect( ahwndChild[ CH_DISKVAL ], NULL, 0 );
  570.     }
  571.  
  572. DosQPathInfo( SWAPFILE, FIL_STANDARD, (PBYTE)&fs, sizeof(fs), 0L );
  573. if ( ulSwapSize != fs.cbFile )
  574.     {
  575.     ulSwapSize = fs.cbFile;
  576.     sprintf( achSpace, "%4.0f KB", (float)ulSwapSize / 1024.0 );
  577.     strcpy( WinQueryWindowPtr( ahwndChild[ CH_SWAPVAL ], 2 ), achSpace );
  578.     WinInvalidateRect( ahwndChild[ CH_SWAPVAL ], NULL, 0 );
  579.     }
  580.  
  581. return;
  582. }
  583.  
  584. /*
  585. Function:  UpdateShort
  586.  
  587. Description:  
  588.     Updates the parameters that are done on a .75 second basis - free memory,
  589.     time of day, CPU usage
  590.  
  591. Values Returned:
  592.     None
  593.  
  594. Notes:
  595.  
  596. */
  597.  
  598. VOID UpdateShort( PHWND ahwndChild )
  599.  
  600. {
  601. ULONG   ulCur;
  602. CHAR    achFmt[25];
  603. struct tm *tml;
  604. time_t  timer;
  605.  
  606. while ( uCalibVal == 0L )
  607.     DosSleep( 100L );
  608.  
  609. ulCur = (uCurVal * 100L) / uCalibVal;
  610. if ( ulLast != ulCur )
  611.     {
  612.     sprintf( achFmt, "%ld%%", 100L - ulCur );
  613.     strcpy( WinQueryWindowPtr( ahwndChild[ CH_CPUVAL ], 2 ), achFmt );
  614.     WinInvalidateRect( ahwndChild[ CH_CPUVAL ], NULL, 0 );
  615.     ulLast = ulCur;
  616.     }
  617.  
  618. time( &timer );
  619. tml = localtime( &timer );
  620. ctime( &timer );
  621. if ( tml->tm_hour == 0 )
  622.     sprintf( achFmt, "12:%02d:%02d AM", tml->tm_min, tml->tm_sec );
  623. else if ( tml->tm_hour < 12 )
  624.     sprintf( achFmt, "%02d:%02d:%02d AM", tml->tm_hour, tml->tm_min, tml->tm_sec );
  625. else if ( tml->tm_hour == 12 )
  626.     sprintf( achFmt, "12:%02d:%02d PM", tml->tm_min, tml->tm_sec );
  627. else
  628.     sprintf( achFmt, "%02d:%02d:%02d PM", tml->tm_hour - 12, tml->tm_min, tml->tm_sec );
  629. strcpy( WinQueryWindowPtr( ahwndChild[ CH_CLOCKVAL ], 2 ), achFmt );
  630. WinInvalidateRect( ahwndChild[ CH_CLOCKVAL ], NULL, 0 );
  631.  
  632. DosMemAvail( &ulCur );
  633. if ( ulCur != ulFrSize )
  634.     {
  635.     sprintf( achFmt, "%4ld KB", (ulCur + 512) / 1024 );
  636.     strcpy( WinQueryWindowPtr( ahwndChild[ CH_MEMVAL ], 2 ), achFmt );
  637.     WinInvalidateRect( ahwndChild[ CH_MEMVAL ], NULL, 0 );
  638.     ulFrSize = ulCur;
  639.     }
  640. return;
  641. }
  642.  
  643.  
  644.  
  645. /*
  646. Function:  ChildProc
  647.  
  648. Description:  
  649.     Child window that is extremely stupid -- knows how to display centered
  650.     text in its window
  651.  
  652. Values Returned:
  653.     MRESULTS
  654.  
  655. Notes:
  656.  
  657. */
  658.  
  659. MRESULT EXPENTRY ChildProc( HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2 )
  660.  
  661. {
  662. HPS     hps;
  663. RECTL   rcl;
  664. LONG    lCol;
  665. PCHAR   pch;
  666.  
  667. switch( msg )
  668.     {
  669.     case WM_CREATE:
  670.         WinSetWindowUShort( hwnd, 0, 0 );
  671.         return 0;
  672.  
  673.     case  WM_BUTTON1DBLCLK:
  674.     case  WM_BUTTON1DOWN:
  675.         WinSendMsg( WinQueryWindow( hwnd, QW_PARENT, 0 ), msg, mp1, mp2 );
  676.         return 0;
  677.  
  678.     case WM_DESTROY:
  679.         free( WinQueryWindowPtr( hwnd, 2 ) );
  680.         return 0;
  681.  
  682.     case WM_PAINT:
  683.         pch = WinQueryWindowPtr( hwnd, 2 );
  684.         WinQueryWindowRect( hwnd, &rcl );
  685.         hps = WinBeginPaint( hwnd, NULL, NULL );
  686.         if ( WinQueryWindowUShort( hwnd, 0 ) == 0 )
  687.             lCol = CLR_NEUTRAL;
  688.         else
  689.             lCol = CLR_RED;
  690.         WinDrawText( hps, -1, pch, &rcl, lCol, CLR_BACKGROUND,
  691.                      DT_VCENTER | DT_CENTER | DT_ERASERECT );
  692.         WinEndPaint( hps );
  693.         return 0;
  694.     }
  695.  
  696. return WinDefWindowProc( hwnd, msg, mp1, mp2 );
  697. }
  698.