/*----------------------------------------------------------------------- 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 (C) 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 -----------------------------------------------------------------------*/ #define APPNAME "Leakybin" // Windows Header Files: #include // C RunTime Header Files #include #include #include #include // 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 UINT_PTR 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 strncpy_s(szAppName, 100, APPNAME, _TRUNCATE); 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 (int) (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 (ATOM)((*proc)(&wcex));//return RegisterClassEx(&wcex) with type ATOM; } } 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_BLOCK pNextMab, 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_BLOCK pMab, 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: { MEMORYSTATUS MemoryStatusData; LONGLONG llInUse; DWORD dwPercentUsed; 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; _snprintf_s(szOutputString, 100, _TRUNCATE, "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); _snprintf_s(szOutputString, 100, _TRUNCATE, "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; 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 _snprintf_s(szGetName, 256, _TRUNCATE, "%sProductName", GetStringRes(IDS_VER_INFO_LANG)); // Set the title of the dialog: bRetCode = VerQueryValue((LPVOID)lpstrVffInfo, (LPSTR)szGetName, (LPVOID)&lpVersion, (UINT *)&uVersionLen); // Notice order of version and string... if (PRIMARYLANGID(GetUserDefaultLangID()) == LANG_JAPANESE) { _snprintf_s(szResult, 256, _TRUNCATE, "%s のバージョン情報", lpVersion); } else { _snprintf_s(szResult, 256, _TRUNCATE, "About %s", 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)); _snprintf_s(szGetName, 256, _TRUNCATE, "%s%s", GetStringRes(IDS_VER_INFO_LANG), 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 strncpy_s(szResult, 256, lpVersion, _TRUNCATE); SetDlgItemText(hDlg, i, szResult); } else { dwResult = GetLastError(); _snprintf_s(szResult, 256, _TRUNCATE, GetStringRes(IDS_VERSION_ERROR), dwResult); SetDlgItemText (hDlg, i, szResult); } SendMessage (GetDlgItem (hDlg, i), WM_SETFONT, (UINT_PTR)((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 _snprintf_s(szVersion, 40, _TRUNCATE, "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 _snprintf_s(szVersion, 40, _TRUNCATE, "Microsoft Win32s %u.%u (Build: %u)", (DWORD)(LOBYTE(LOWORD(dwVersion))), (DWORD)(HIBYTE(LOWORD(dwVersion))), (DWORD)(HIWORD(dwVersion) & ~0x8000) ); } else { // Windows 95 _snprintf_s(szVersion, 40, _TRUNCATE, "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; }