One use of a Windows timer is to periodically update a status report displayed on the screen. The program can relinquish control until the next WM_TIMER message and thus not hog precious processing time. The FREEMEM program, shown in Figure 5-6 on the following pages, displays the amount of free memory available in Windows in megabytes. The free memory value is updated every second and is consistent with the figure shown in the Program Manager's and File Manager's About box. FREEMEM can let you know how close Windows is to running out of memory. While testing a new Windows program, you may want to keep an eye on FREEMEM for a rough indication of how your program is allocating and freeing memory.
FREEMEM.MAK
#-----------------------
# FREEMEM.MAK make file
#-----------------------
freemem.exe : freemem.obj freemem.def
link freemem, /align:16, NUL, /nod slibcew win87em libw, freemem
rc freemem.exe
freemem.obj : freemem.c
cl -c -Gsw -Ow -W2 -Zp freemem.c
FREEMEM.C
/*------------------------------------------
FREEMEM.C -- Free Memory Display Program
(c) Charles Petzold, 1990
------------------------------------------*/
#include <windows.h>
#include <stdio.h>
#define ID_TIMER 1
long FAR PASCAL WndProc (HWND, WORD, WORD, LONG) ;
int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
static char szAppName[] = "FreeMem" ;
HDC hdc ;
HWND hwnd ;
MSG msg ;
TEXTMETRIC tm ;
WNDCLASS wndclass ;
if (hPrevInstance)
return FALSE ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = NULL ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
RegisterClass (&wndclass) ;
hwnd = CreateWindow (szAppName, "Free Memory",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
hdc = GetDC (hwnd) ;
GetTextMetrics (hdc, &tm) ;
ReleaseDC (hwnd, hdc) ;
if (4 * tm.tmAveCharWidth > GetSystemMetrics (SM_CXICON) ||
2 * tm.tmHeight > GetSystemMetrics (SM_CYICON))
{
MessageBox (hwnd, "Icon size too small for display!",
szAppName, MB_ICONEXCLAMATION | MB_OK) ;
return FALSE ;
}
if (!SetTimer (hwnd, ID_TIMER, 1000, NULL))
{
MessageBox (hwnd, "Too many clocks or timers!",
szAppName, MB_ICONEXCLAMATION | MB_OK) ;
return FALSE ;
}
ShowWindow (hwnd, SW_SHOWMINNOACTIVE) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
long FAR PASCAL WndProc (HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
static DWORD dwFreeMem, dwPrevMem ;
static RECT rect ;
char cBuffer [20] ;
HDC hdc ;
PAINTSTRUCT ps ;
switch (message)
{
case WM_TIMER :
dwFreeMem = GetFreeSpace (0) ;
if (dwFreeMem != dwPrevMem)
InvalidateRect (hwnd, NULL, TRUE) ;
dwPrevMem = dwFreeMem ;
return 0 ;
case WM_SIZE :
GetClientRect (hwnd, &rect) ;
return 0 ;
case WM_PAINT :
hdc = BeginPaint (hwnd, &ps) ;
DrawText (hdc, cBuffer,
sprintf (cBuffer, "%.2f megs",
dwFreeMem / 1024.0 / 1024.0),
&rect, DT_WORDBREAK) ;
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_QUERYOPEN :
return 0 ;
case WM_DESTROY :
KillTimer (hwnd, ID_TIMER) ;
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
FREEMEM.DEF
;------------------------------------
; FREEMEM.DEF module definition file
;------------------------------------
NAME FREEMEM
DESCRIPTION 'Free Memory Display (c) Charles Petzold, 1990'
EXETYPE WINDOWS
STUB 'WINSTUB.EXE'
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE MULTIPLE
HEAPSIZE 1024
STACKSIZE 8192
EXPORTS WndProc
Because FREEMEM doesn't need much display space, I've written it to appear as an icon at the bottom of the Windows screen. (See Figure 5-7.) This is about as unobtrusive a window as you can create in Windows.
Although FREEMEM's use of the timer is simple enough, the program illustrates some interesting tricks that admittedly have nothing to do with the timer.