LEAKYBIN.C

//THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 
//ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
//THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright 1996 - 1997 Microsoft Corporation. All Rights Reserved.
//
// PROGRAM: Leakybin.c
//
// PURPOSE: Illustrates the use of Windows NT application performance
// counters to measure GlobalAlloc usage
//
// PLATFORMS: Windows NT only
//
// FUNCTIONS:
// WinMain() - calls initialization function, processes message loop
// InitApplication() - Initializes window data nd registers window
// InitInstance() -saves instance handle and creates main window
// WindProc() Processes messages
// About() - Process menssages for "About" dialog box
// MyRegisterClass() - Registers the application's window class
// CenterWindow() - Centers one window over another
//
// SPECIAL INSTRUCTIONS: N/A
//
#define APPNAME "Leakybin"

// Windows Header Files:
#include <windows.h>

// C RunTime Header Files
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <stdio.h>

// Local Header Files
#include "leakybin.h"

// Makes it easier to determine appropriate code paths:
#define IS_WIN32 TRUE
#define IS_NT IS_WIN32 && (BOOL)(GetVersion() < 0x80000000)

// Global Variables:

HINSTANCE hInst; // current instance
char szAppName[100]; // Name of the app
char szTitle[100]; // The title bar text

static int TimerID = 0;
static BOOL TimerRunning = FALSE;
static HMENU hAppMenu, hTestMenu;
static MEMORY_ALLOC_BLOCK mabListHead = {NULL};

// Foward declarations of functions included in this code module:

ATOM MyRegisterClass(CONST WNDCLASS*);
BOOL InitApplication(HINSTANCE);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
BOOL CenterWindow (HWND, HWND);
LPTSTR GetStringRes (int id);


//
// FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
//
// PURPOSE: Entry point for the application.
//
// COMMENTS:
//
// This function initializes the application and processes the
// message loop.
//
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
HANDLE hAccelTable;

// Initialize global strings
lstrcpy (szAppName, APPNAME);
LoadString (hInstance, IDS_APP_TITLE, szTitle, 100);


if (!hPrevInstance) {
// Perform instance initialization:
if (!InitApplication(hInstance)) {
return (FALSE);
}
}

// Perform application initialization:
if (!InitInstance(hInstance, nCmdShow)) {
return (FALSE);
}

hAccelTable = LoadAccelerators (hInstance, szAppName);

// Main message loop:
while (GetMessage(&msg, NULL, 0, 0)) {
if (!TranslateAccelerator (msg.hwnd, hAccelTable, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

return (msg.wParam);

lpCmdLine; // This will prevent 'unused formal parameter' warnings
}

//
// FUNCTION: MyRegisterClass(CONST WNDCLASS*)
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage is only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
ATOM MyRegisterClass(CONST WNDCLASS *lpwc)
{
HANDLE hMod;
FARPROC proc;
WNDCLASSEX wcex;

hMod = GetModuleHandle ("USER32");
if (hMod != NULL) {

#if defined (UNICODE)
proc = GetProcAddress (hMod, "RegisterClassExW");
#else
proc = GetProcAddress (hMod, "RegisterClassExA");
#endif

if (proc != NULL) {

wcex.style = lpwc->style;
wcex.lpfnWndProc = lpwc->lpfnWndProc;
wcex.cbClsExtra = lpwc->cbClsExtra;
wcex.cbWndExtra = lpwc->cbWndExtra;
wcex.hInstance = lpwc->hInstance;
wcex.hIcon = lpwc->hIcon;
wcex.hCursor = lpwc->hCursor;
wcex.hbrBackground = lpwc->hbrBackground;
wcex.lpszMenuName = lpwc->lpszMenuName;
wcex.lpszClassName = lpwc->lpszClassName;

// Added elements for Windows 95:
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.hIconSm = LoadIcon(wcex.hInstance, "SMALL");

return (*proc)(&wcex);//return RegisterClassEx(&wcex);
}
}
return (RegisterClass(lpwc));
}


//
// FUNCTION: InitApplication(HANDLE)
//
// PURPOSE: Initializes window data and registers window class
//
// COMMENTS:
//
// In this function, we initialize a window class by filling out a data
// structure of type WNDCLASS and calling either RegisterClass or
// the internal MyRegisterClass.
//
BOOL InitApplication(HINSTANCE hInstance)
{
WNDCLASS wc;

// Fill in window class structure with parameters that describe
// the main window.
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon (hInstance, szAppName);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = szAppName;
wc.lpszClassName = szAppName;

// Register the window class and return success/failure code.
return RegisterClass(&wc);
}

//
// FUNCTION: InitInstance(HANDLE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;

hInst = hInstance; // Store instance handle in our global variable

hWnd = CreateWindow(szAppName, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
NULL, NULL, hInstance, NULL);

if (!hWnd) {
return (FALSE);
}

ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);

return (TRUE);
}
void FreeAllocatedMemory()
{
{
PMEMORY_ALLOC_BLOCKpNextMab, pMab;

pMab = mabListHead.pNext;

while (pMab != NULL) {
pNextMab = pMab->pNext;
G_FREE (pMab);
pMab = pNextMab;
}

mabListHead.pNext = NULL;
}
}
//
// FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
//
// PURPOSE: Processes messages for the main window.
//
// MESSAGES:
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
// WM_DISPLAYCHANGE - message sent to Plug & Play systems when the display changes
// WM_RBUTTONDOWN - Right mouse click -- put up context menu here if appropriate
// WM_NCRBUTTONUP - User has clicked the right button on the application's system menu
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
POINT pnt;
HMENU hMenu;
BOOL bGotHelp;

switch (message) {
case WM_CREATE:
// clear timer flags
TimerID = 0;
TimerRunning = FALSE;

// enable "Start" menu selection
hAppMenu = GetMenu (hWnd);
hTestMenu = GetSubMenu (hAppMenu, 1);
EnableMenuItem (hTestMenu, IDM_STOP, MF_BYCOMMAND | MF_GRAYED);
EnableMenuItem (hTestMenu, IDM_START, MF_BYCOMMAND | MF_ENABLED);
break;

case WM_COMMAND:
wmId = LOWORD(wParam); // Remember, these are...
wmEvent = HIWORD(wParam); // ...different for Win32!

//Parse the menu selections:
switch (wmId) {

case IDM_EXIT:
DestroyWindow (hWnd);
break;

case IDM_START:
if (!TimerRunning) {
TimerID = SetTimer (hWnd, LEAK_TIMER, TIME_INTERVAL, NULL);
if (TimerID != 0) {
TimerRunning = TRUE;
EnableMenuItem (hTestMenu, IDM_START,
MF_BYCOMMAND | MF_GRAYED);
EnableMenuItem (hTestMenu, IDM_STOP,
MF_BYCOMMAND | MF_ENABLED);
} else {
//unable to start timer
MessageBeep (MB_ICONEXCLAMATION);
}
}
InvalidateRect (hWnd, NULL, TRUE);
break;

case IDM_STOP:
if (TimerRunning) {
KillTimer (hWnd, LEAK_TIMER);
TimerID = 0;
TimerRunning = FALSE;
EnableMenuItem (hTestMenu, IDM_STOP,
MF_BYCOMMAND | MF_GRAYED);
EnableMenuItem (hTestMenu, IDM_START,
MF_BYCOMMAND | MF_ENABLED);
}
InvalidateRect (hWnd, NULL, TRUE);
break;

case IDM_RESET:
FreeAllocatedMemory();
InvalidateRect (hWnd, NULL, TRUE);
break;

case IDM_ABOUT:
DialogBox(hInst, "AboutBox", hWnd, (DLGPROC)About);
break;

case IDM_HELPTOPICS: // Only called in Windows 95
bGotHelp = WinHelp (hWnd, APPNAME".HLP", HELP_FINDER,(DWORD)0);
if (!bGotHelp)
{
MessageBox (GetFocus(), GetStringRes(IDS_NO_HELP),
szAppName, MB_OK|MB_ICONHAND);
}
break;

default:
return (DefWindowProc(hWnd, message, wParam, lParam));
}
break;

case WM_TIMER:
{
PMEMORY_ALLOC_BLOCKpMab, pNewMab;

pNewMab = (PMEMORY_ALLOC_BLOCK)G_ALLOC (GPTR, ALLOCATION_SIZE);

if (pNewMab != NULL) {
// save this pointer
pNewMab->pNext = NULL;
if (mabListHead.pNext == NULL) {
// this is the first entry
mabListHead.pNext = pNewMab;
} else {
// go to end of list
pMab = mabListHead.pNext;
while (pMab->pNext != NULL) pMab = pMab->pNext;
pMab->pNext = pNewMab;
}
InvalidateRect (hWnd, NULL, TRUE);
}
}
break;

case WM_RBUTTONDOWN: // RightClick in windows client area...
pnt.x = LOWORD(lParam);
pnt.y = HIWORD(lParam);
ClientToScreen(hWnd, (LPPOINT) &pnt);
// This is where you would determine the appropriate 'context'
// menu to bring up. Since this app has no real functionality,
// we will just bring up the 'Help' menu:
hMenu = GetSubMenu (GetMenu (hWnd), 2);
if (hMenu) {
TrackPopupMenu (hMenu, 0, pnt.x, pnt.y, 0, hWnd, NULL);
} else {
// Couldn't find the menu...
MessageBeep(0);
}
break;


case WM_DISPLAYCHANGE: // Only comes through on plug'n'play systems
{
SIZE szScreen;
DWORD dwBitsPerPixel = (DWORD)wParam;

szScreen.cx = LOWORD(lParam);
szScreen.cy = HIWORD(lParam);

MessageBox (GetFocus(), GetStringRes(IDS_DISPLAYCHANGED),
szAppName, 0);
}
break;

case WM_PAINT:
{
MEMORYSTATUSMemoryStatusData;
LONGLONGllInUse;
DWORDdwPercentUsed;

int nX, nY;
LONG lTextOutReturn;
int nStringLength;
CHAR szOutputString[100];

hdc = BeginPaint (hWnd, &ps);
// Add any drawing code here...
GlobalMemoryStatus (&MemoryStatusData);

llInUse = (LONGLONG)(MemoryStatusData.dwTotalPageFile -
MemoryStatusData.dwAvailPageFile + 5 );
llInUse *= 1000;
llInUse /= MemoryStatusData.dwTotalPageFile;
llInUse /= 10;

dwPercentUsed = (DWORD)llInUse;

nX = 0;
nY = 0;
sprintf (szOutputString, "Reported Memory Load: \t%3.1d%%",
MemoryStatusData.dwMemoryLoad);
nStringLength = lstrlen (szOutputString) * sizeof (CHAR);
lTextOutReturn = TabbedTextOut (hdc, nX, nY,
szOutputString, nStringLength, 0, NULL, 0);
nY += HIWORD (lTextOutReturn);

sprintf (szOutputString, "Page file in use: \t%3.1d%%",
dwPercentUsed);
nStringLength = lstrlen (szOutputString) * sizeof (CHAR);
lTextOutReturn = TabbedTextOut (hdc, nX, nY,
szOutputString, nStringLength, 0, NULL, 0);
nY += HIWORD (lTextOutReturn);

EndPaint (hWnd, &ps);
}
break;

case WM_DESTROY:
FreeAllocatedMemory();
// Tell WinHelp we don't need it any more...
WinHelp (hWnd, APPNAME".HLP", HELP_QUIT,(DWORD)0);
PostQuitMessage(0);
break;

default:
return (DefWindowProc(hWnd, message, wParam, lParam));
}
return (0);
}

//
// FUNCTION: About(HWND, unsigned, WORD, LONG)
//
// PURPOSE: Processes messages for "About" dialog box
// This version allows greater flexibility over the contents of the 'About' box,
// by pulling out values from the 'Version' resource.
//
// MESSAGES:
//
// WM_INITDIALOG - initialize dialog box
// WM_COMMAND - Input received
//
//
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
static HFONT hfontDlg; // Font for dialog text
static HFONT hFinePrint; // Font for 'fine print' in dialog
DWORD dwVerInfoSize; // Size of version information block
LPSTR lpVersion; // String pointer to 'version' text
DWORD dwVerHnd=0; // An 'ignored' parameter, always '0'
UINT uVersionLen;
WORD wRootLen;
BOOL bRetCode;
int i;
char szFullPath[256];
char szResult[256];
char szGetName[256];
DWORD dwVersion;
char szVersion[40];
DWORD dwResult;

switch (message) {
case WM_INITDIALOG:
ShowWindow (hDlg, SW_HIDE);

if (PRIMARYLANGID(GetUserDefaultLangID()) == LANG_JAPANESE)
{
hfontDlg = CreateFont(14, 0, 0, 0, 0, 0, 0, 0, SHIFTJIS_CHARSET, 0, 0, 0,
VARIABLE_PITCH | FF_DONTCARE, "");
hFinePrint = CreateFont(11, 0, 0, 0, 0, 0, 0, 0, SHIFTJIS_CHARSET, 0, 0, 0,
VARIABLE_PITCH | FF_DONTCARE, "");
}
else
{
hfontDlg = CreateFont(14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
VARIABLE_PITCH | FF_SWISS, "");
hFinePrint = CreateFont(11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
VARIABLE_PITCH | FF_SWISS, "");
}

CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
GetModuleFileName (hInst, szFullPath, sizeof(szFullPath));

// Now lets dive in and pull out the version information:
dwVerInfoSize = GetFileVersionInfoSize(szFullPath, &dwVerHnd);
if (dwVerInfoSize) {
LPSTR lpstrVffInfo;
HANDLE hMem;
hMem = GlobalAlloc(GMEM_MOVEABLE, dwVerInfoSize);
lpstrVffInfo = GlobalLock(hMem);
GetFileVersionInfo(szFullPath, dwVerHnd, dwVerInfoSize, lpstrVffInfo);
// The below 'hex' value looks a little confusing, but
// essentially what it is, is the hexidecimal representation
// of a couple different values that represent the language
// and character set that we are wanting string values for.
// 040904E4 is a very common one, because it means:
// US English, Windows MultiLingual characterset
// Or to pull it all apart:
// 04------ = SUBLANG_ENGLISH_USA
// --09---- = LANG_ENGLISH
// --11---- = LANG_JAPANESE
// ----04E4 = 1252 = Codepage for Windows:Multilingual

lstrcpy(szGetName, GetStringRes(IDS_VER_INFO_LANG));

wRootLen = lstrlen(szGetName); // Save this position

// Set the title of the dialog:
lstrcat (szGetName, "ProductName");
bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
(LPSTR)szGetName,
(LPVOID)&lpVersion,
(UINT *)&uVersionLen);

// Notice order of version and string...
if (PRIMARYLANGID(GetUserDefaultLangID()) == LANG_JAPANESE)
{
lstrcpy(szResult, lpVersion);
lstrcat(szResult, " o [ W ");
}
else
{
lstrcpy(szResult, "About ");
lstrcat(szResult, lpVersion);
}

// -----------------------------------------------------

SetWindowText (hDlg, szResult);

// Walk through the dialog items that we want to replace:
for (i = DLG_VERFIRST; i <= DLG_VERLAST; i++) {
GetDlgItemText(hDlg, i, szResult, sizeof(szResult));
szGetName[wRootLen] = (char)0;
lstrcat (szGetName, szResult);
uVersionLen = 0;
lpVersion = NULL;
bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
(LPSTR)szGetName,
(LPVOID)&lpVersion,
(UINT *)&uVersionLen);

if ( bRetCode && uVersionLen && lpVersion) {
// Replace dialog item text with version info
lstrcpy(szResult, lpVersion);
SetDlgItemText(hDlg, i, szResult);
}
else
{
dwResult = GetLastError();

wsprintf(szResult, GetStringRes(IDS_VERSION_ERROR), dwResult);
SetDlgItemText (hDlg, i, szResult);
}
SendMessage (GetDlgItem (hDlg, i), WM_SETFONT,
(UINT)((i==DLG_VERLAST)?hFinePrint:hfontDlg),
TRUE);
} // for (i = DLG_VERFIRST; i <= DLG_VERLAST; i++)


GlobalUnlock(hMem);
GlobalFree(hMem);

} else {
// No version information available.
} // if (dwVerInfoSize)

SendMessage (GetDlgItem (hDlg, IDC_LABEL), WM_SETFONT,
(WPARAM)hfontDlg,(LPARAM)TRUE);

// We are using GetVersion rather then GetVersionEx
// because earlier versions of Windows NT and Win32s
// didn't include GetVersionEx:
dwVersion = GetVersion();

if (dwVersion < 0x80000000) {
// Windows NT
wsprintf (szVersion, "Microsoft Windows NT %u.%u (Build: %u)",
(DWORD)(LOBYTE(LOWORD(dwVersion))),
(DWORD)(HIBYTE(LOWORD(dwVersion))),
(DWORD)(HIWORD(dwVersion)) );
} else if (LOBYTE(LOWORD(dwVersion))<4) {
// Win32s
wsprintf (szVersion, "Microsoft Win32s %u.%u (Build: %u)",
(DWORD)(LOBYTE(LOWORD(dwVersion))),
(DWORD)(HIBYTE(LOWORD(dwVersion))),
(DWORD)(HIWORD(dwVersion) & ~0x8000) );
} else {
// Windows 95
wsprintf (szVersion, "Microsoft Windows 95 %u.%u",
(DWORD)(LOBYTE(LOWORD(dwVersion))),
(DWORD)(HIBYTE(LOWORD(dwVersion))) );
}

SetWindowText (GetDlgItem(hDlg, IDC_OSVERSION), szVersion);
ShowWindow (hDlg, SW_SHOW);
return (TRUE);

case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
EndDialog(hDlg, TRUE);
DeleteObject (hfontDlg);
DeleteObject (hFinePrint);
return (TRUE);
}
break;
}

return FALSE;
}

//
// FUNCTION: CenterWindow(HWND, HWND)
//
// PURPOSE: Centers one window over another.
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
// This functionwill center one window over another ensuring that
// the placement of the window is within the 'working area', meaning
// that it is both within the display limits of the screen, and not
// obscured by the tray or other framing elements of the desktop.
BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
{
RECT rChild, rParent, rWorkArea;
int wChild, hChild, wParent, hParent;
int xNew, yNew;
BOOL bResult;

// Get the Height and Width of the child window
GetWindowRect (hwndChild, &rChild);
wChild = rChild.right - rChild.left;
hChild = rChild.bottom - rChild.top;

// Get the Height and Width of the parent window
GetWindowRect (hwndParent, &rParent);
wParent = rParent.right - rParent.left;
hParent = rParent.bottom - rParent.top;

// Get the limits of the 'workarea'
bResult = SystemParametersInfo(
SPI_GETWORKAREA, // system parameter to query or set
sizeof(RECT),
&rWorkArea,
0);
if (!bResult) {
rWorkArea.left = rWorkArea.top = 0;
rWorkArea.right = GetSystemMetrics(SM_CXSCREEN);
rWorkArea.bottom = GetSystemMetrics(SM_CYSCREEN);
}

// Calculate new X position, then adjust for workarea
xNew = rParent.left + ((wParent - wChild) /2);
if (xNew < rWorkArea.left) {
xNew = rWorkArea.left;
} else if ((xNew+wChild) > rWorkArea.right) {
xNew = rWorkArea.right - wChild;
}

// Calculate new Y position, then adjust for workarea
yNew = rParent.top + ((hParent - hChild) /2);
if (yNew < rWorkArea.top) {
yNew = rWorkArea.top;
} else if ((yNew+hChild) > rWorkArea.bottom) {
yNew = rWorkArea.bottom - hChild;
}

// Set it, and return
return SetWindowPos (hwndChild, NULL, xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
}


//---------------------------------------------------------------------------
//
// FUNCTION: GetStringRes (int id INPUT ONLY)
//
// COMMENTS: Load the resource string with the ID given, and return a
// pointer to it. Notice that the buffer is common memory so
// the string must be used before this call is made a second time.
//
//---------------------------------------------------------------------------

LPTSTR GetStringRes (int id)
{
static TCHAR buffer[MAX_PATH];

buffer[0]=0;
LoadString (GetModuleHandle (NULL), id, buffer, MAX_PATH);
return buffer;
}