home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / winbase / winnt / perftool / perfdlls / leakybin / leakybin.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-05  |  23.1 KB  |  720 lines

  1. //THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  2. //ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  3. //THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  4. // PARTICULAR PURPOSE.
  5. //
  6. // Copyright 1996 - 1997 Microsoft Corporation.  All Rights Reserved.
  7. //
  8. // PROGRAM: Leakybin.c
  9. //
  10. // PURPOSE: Illustrates the use of Windows NT application performance
  11. //              counters to measure GlobalAlloc usage
  12. //
  13. // PLATFORMS:  Windows NT only
  14. //
  15. // FUNCTIONS:
  16. //    WinMain() - calls initialization function, processes message loop
  17. //    InitApplication() - Initializes window data nd registers window
  18. //    InitInstance() -saves instance handle and creates main window
  19. //    WindProc() Processes messages
  20. //    About() - Process menssages for "About" dialog box
  21. //    MyRegisterClass() - Registers the application's window class
  22. //    CenterWindow() -  Centers one window over another
  23. //
  24. // SPECIAL INSTRUCTIONS: N/A
  25. //
  26. #define APPNAME "Leakybin"
  27.  
  28. // Windows Header Files:
  29. #include <windows.h>
  30.  
  31. // C RunTime Header Files
  32. #include <stdlib.h>
  33. #include <malloc.h>
  34. #include <memory.h>
  35. #include <stdio.h>
  36.  
  37. // Local Header Files
  38. #include "leakybin.h"
  39.  
  40. // Makes it easier to determine appropriate code paths:
  41. #define IS_WIN32    TRUE
  42. #define IS_NT       IS_WIN32 && (BOOL)(GetVersion() < 0x80000000)
  43.  
  44. // Global Variables:
  45.  
  46. HINSTANCE hInst;      // current instance
  47. char szAppName[100];  // Name of the app
  48. char szTitle[100];    // The title bar text
  49.  
  50. static int      TimerID = 0;
  51. static BOOL     TimerRunning = FALSE;
  52. static HMENU    hAppMenu, hTestMenu;
  53. static MEMORY_ALLOC_BLOCK   mabListHead = {NULL};
  54.  
  55. // Foward declarations of functions included in this code module:
  56.  
  57. ATOM MyRegisterClass(CONST WNDCLASS*);
  58. BOOL InitApplication(HINSTANCE);
  59. BOOL InitInstance(HINSTANCE, int);
  60. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  61. LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
  62. BOOL CenterWindow (HWND, HWND);
  63. LPTSTR   GetStringRes (int id);
  64.  
  65.  
  66. //
  67. //  FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
  68. //
  69. //  PURPOSE: Entry point for the application.
  70. //
  71. //  COMMENTS:
  72. //
  73. // This function initializes the application and processes the
  74. // message loop.
  75. //
  76. int APIENTRY WinMain(HINSTANCE hInstance,
  77.                      HINSTANCE hPrevInstance,
  78.                      LPSTR     lpCmdLine,
  79.                      int       nCmdShow)
  80. {
  81.    MSG msg;
  82.    HANDLE hAccelTable;
  83.  
  84.    // Initialize global strings
  85.    lstrcpy (szAppName, APPNAME);
  86.    LoadString (hInstance, IDS_APP_TITLE, szTitle, 100);
  87.  
  88.  
  89.    if (!hPrevInstance) {
  90.       // Perform instance initialization:
  91.       if (!InitApplication(hInstance)) {
  92.          return (FALSE);
  93.       }
  94.    }
  95.  
  96.    // Perform application initialization:
  97.    if (!InitInstance(hInstance, nCmdShow)) {
  98.       return (FALSE);
  99.    }
  100.  
  101.    hAccelTable = LoadAccelerators (hInstance, szAppName);
  102.  
  103.    // Main message loop:
  104.    while (GetMessage(&msg, NULL, 0, 0)) {
  105.       if (!TranslateAccelerator (msg.hwnd, hAccelTable, &msg)) {
  106.          TranslateMessage(&msg);
  107.          DispatchMessage(&msg);
  108.       }
  109.    }
  110.  
  111.    return (msg.wParam);
  112.  
  113.    lpCmdLine; // This will prevent 'unused formal parameter' warnings
  114. }
  115.  
  116. //
  117. //  FUNCTION: MyRegisterClass(CONST WNDCLASS*)
  118. //
  119. //  PURPOSE: Registers the window class.
  120. //
  121. //  COMMENTS:
  122. //
  123. //    This function and its usage is only necessary if you want this code
  124. //    to be compatible with Win32 systems prior to the 'RegisterClassEx'
  125. // function that was added to Windows 95. It is important to call this function
  126. //    so that the application will get 'well formed' small icons associated
  127. //    with it.
  128. //
  129. ATOM MyRegisterClass(CONST WNDCLASS *lpwc)
  130. {
  131.    HANDLE  hMod;
  132.    FARPROC proc;
  133.    WNDCLASSEX wcex;
  134.  
  135.    hMod = GetModuleHandle ("USER32");
  136.    if (hMod != NULL) {
  137.  
  138. #if defined (UNICODE)
  139.       proc = GetProcAddress (hMod, "RegisterClassExW");
  140. #else
  141.       proc = GetProcAddress (hMod, "RegisterClassExA");
  142. #endif
  143.  
  144.       if (proc != NULL) {
  145.  
  146.          wcex.style         = lpwc->style;
  147.          wcex.lpfnWndProc   = lpwc->lpfnWndProc;
  148.          wcex.cbClsExtra    = lpwc->cbClsExtra;
  149.          wcex.cbWndExtra    = lpwc->cbWndExtra;
  150.          wcex.hInstance     = lpwc->hInstance;
  151.          wcex.hIcon         = lpwc->hIcon;
  152.          wcex.hCursor       = lpwc->hCursor;
  153.          wcex.hbrBackground = lpwc->hbrBackground;
  154.                      wcex.lpszMenuName  = lpwc->lpszMenuName;
  155.          wcex.lpszClassName = lpwc->lpszClassName;
  156.  
  157.          // Added elements for Windows 95:
  158.          wcex.cbSize = sizeof(WNDCLASSEX);
  159.          wcex.hIconSm = LoadIcon(wcex.hInstance, "SMALL");
  160.  
  161.          return (*proc)(&wcex);//return RegisterClassEx(&wcex);
  162.       }
  163.    }
  164.    return (RegisterClass(lpwc));
  165. }
  166.  
  167.  
  168. //
  169. //  FUNCTION: InitApplication(HANDLE)
  170. //
  171. //  PURPOSE: Initializes window data and registers window class
  172. //
  173. //  COMMENTS:
  174. //
  175. //       In this function, we initialize a window class by filling out a data
  176. //       structure of type WNDCLASS and calling either RegisterClass or
  177. //       the internal MyRegisterClass.
  178. //
  179. BOOL InitApplication(HINSTANCE hInstance)
  180. {
  181.     WNDCLASS  wc;
  182.     HWND      hwnd;
  183.  
  184.     // Fill in window class structure with parameters that describe
  185.     // the main window.
  186.     wc.style         = CS_HREDRAW | CS_VREDRAW;
  187.     wc.lpfnWndProc   = (WNDPROC)WndProc;
  188.     wc.cbClsExtra    = 0;
  189.     wc.cbWndExtra    = 0;
  190.     wc.hInstance     = hInstance;
  191.     wc.hIcon         = LoadIcon (hInstance, szAppName);
  192.     wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  193.     wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  194.     wc.lpszMenuName  = szAppName;
  195.     wc.lpszClassName = szAppName;
  196.  
  197.     // Register the window class and return success/failure code.
  198.     return RegisterClass(&wc);
  199. }
  200.  
  201. //
  202. //   FUNCTION: InitInstance(HANDLE, int)
  203. //
  204. //   PURPOSE: Saves instance handle and creates main window
  205. //
  206. //   COMMENTS:
  207. //
  208. //        In this function, we save the instance handle in a global variable and
  209. //        create and display the main program window.
  210. //
  211. BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
  212. {
  213.    HWND hWnd;
  214.  
  215.    hInst = hInstance; // Store instance handle in our global variable
  216.  
  217.    hWnd = CreateWindow(szAppName, szTitle, WS_OVERLAPPEDWINDOW,
  218.       CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
  219.       NULL, NULL, hInstance, NULL);
  220.  
  221.    if (!hWnd) {
  222.       return (FALSE);
  223.    }
  224.  
  225.    ShowWindow(hWnd, nCmdShow);
  226.    UpdateWindow(hWnd);
  227.  
  228.    return (TRUE);
  229. }
  230. void FreeAllocatedMemory()
  231. {
  232.     {
  233.         PMEMORY_ALLOC_BLOCK    pNextMab, pMab;
  234.  
  235.         pMab = mabListHead.pNext;
  236.  
  237.         while (pMab != NULL) {
  238.             pNextMab = pMab->pNext;
  239.             G_FREE (pMab);
  240.             pMab = pNextMab;
  241.         }
  242.  
  243.         mabListHead.pNext = NULL;
  244.     }
  245. }
  246. //
  247. //  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
  248. //
  249. //  PURPOSE:  Processes messages for the main window.
  250. //
  251. //  MESSAGES:
  252. //
  253. // WM_COMMAND - process the application menu
  254. // WM_PAINT - Paint the main window
  255. // WM_DESTROY - post a quit message and return
  256. //    WM_DISPLAYCHANGE - message sent to Plug & Play systems when the display changes
  257. //    WM_RBUTTONDOWN - Right mouse click -- put up context menu here if appropriate
  258. //    WM_NCRBUTTONUP - User has clicked the right button on the application's system menu
  259. //
  260. //
  261. LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  262. {
  263.    int wmId, wmEvent;
  264.    PAINTSTRUCT ps;
  265.    HDC hdc;
  266.       POINT pnt;
  267.    HMENU hMenu;
  268.       BOOL bGotHelp;
  269.  
  270.    switch (message) {
  271.       case WM_CREATE:
  272.         // clear timer flags 
  273.         TimerID = 0;
  274.         TimerRunning = FALSE;
  275.  
  276.         // enable "Start" menu selection
  277.         hAppMenu = GetMenu (hWnd);
  278.         hTestMenu  = GetSubMenu (hAppMenu, 1);
  279.         EnableMenuItem (hTestMenu, IDM_STOP, MF_BYCOMMAND | MF_GRAYED);
  280.         EnableMenuItem (hTestMenu, IDM_START, MF_BYCOMMAND | MF_ENABLED);
  281.         break;
  282.  
  283.       case WM_COMMAND:
  284.          wmId    = LOWORD(wParam); // Remember, these are...
  285.          wmEvent = HIWORD(wParam); // ...different for Win32!
  286.  
  287.          //Parse the menu selections:
  288.          switch (wmId) {
  289.  
  290.             case IDM_EXIT:
  291.                DestroyWindow (hWnd);
  292.                break;
  293.  
  294.             case IDM_START:
  295.                 if (!TimerRunning) {
  296.                     TimerID = SetTimer (hWnd, LEAK_TIMER, TIME_INTERVAL, NULL);
  297.                     if (TimerID != 0) {
  298.                         TimerRunning = TRUE;
  299.                         EnableMenuItem (hTestMenu, IDM_START,
  300.                             MF_BYCOMMAND | MF_GRAYED);
  301.                         EnableMenuItem (hTestMenu, IDM_STOP,
  302.                             MF_BYCOMMAND | MF_ENABLED);
  303.                     } else {
  304.                         //unable to start timer
  305.                         MessageBeep (MB_ICONEXCLAMATION);
  306.                     }
  307.                 }
  308.                 InvalidateRect (hWnd, NULL, TRUE);
  309.                 break;
  310.  
  311.             case IDM_STOP:
  312.                 if (TimerRunning) {
  313.                     KillTimer (hWnd, LEAK_TIMER);
  314.                     TimerID = 0;
  315.                     TimerRunning = FALSE;
  316.                     EnableMenuItem (hTestMenu, IDM_STOP,
  317.                         MF_BYCOMMAND | MF_GRAYED);
  318.                     EnableMenuItem (hTestMenu, IDM_START,
  319.                         MF_BYCOMMAND | MF_ENABLED);
  320.                 }
  321.                 InvalidateRect (hWnd, NULL, TRUE);
  322.                 break;
  323.  
  324.             case IDM_RESET:
  325.                 FreeAllocatedMemory();
  326.                 InvalidateRect (hWnd, NULL, TRUE);
  327.                 break;
  328.  
  329.             case IDM_ABOUT:
  330.                DialogBox(hInst, "AboutBox", hWnd, (DLGPROC)About);
  331.                break;
  332.  
  333.             case IDM_HELPTOPICS: // Only called in Windows 95
  334.                bGotHelp = WinHelp (hWnd, APPNAME".HLP", HELP_FINDER,(DWORD)0);
  335.                if (!bGotHelp)
  336.                {
  337.                   MessageBox (GetFocus(), GetStringRes(IDS_NO_HELP),
  338.                               szAppName, MB_OK|MB_ICONHAND);
  339.                }
  340.                break;
  341.  
  342.             default:
  343.                return (DefWindowProc(hWnd, message, wParam, lParam));
  344.          }
  345.          break;
  346.  
  347.       case WM_TIMER:
  348.         {
  349.             PMEMORY_ALLOC_BLOCK    pMab, pNewMab;
  350.  
  351.             pNewMab = (PMEMORY_ALLOC_BLOCK)G_ALLOC (GPTR, ALLOCATION_SIZE);
  352.  
  353.             if (pNewMab != NULL) {
  354.                 // save this pointer 
  355.                 pNewMab->pNext = NULL;
  356.                 if (mabListHead.pNext == NULL) {
  357.                     // this is the first entry
  358.                     mabListHead.pNext = pNewMab;
  359.                 } else {
  360.                     // go to end of list
  361.                     pMab = mabListHead.pNext;
  362.                     while (pMab->pNext != NULL) pMab = pMab->pNext;
  363.                     pMab->pNext = pNewMab;
  364.                 }
  365.                 InvalidateRect (hWnd, NULL, TRUE);
  366.             }
  367.         }
  368.         break;
  369.  
  370.       case WM_RBUTTONDOWN: // RightClick in windows client area...
  371.             pnt.x = LOWORD(lParam);
  372.             pnt.y = HIWORD(lParam);
  373.             ClientToScreen(hWnd, (LPPOINT) &pnt);
  374.       // This is where you would determine the appropriate 'context'
  375.       // menu to bring up. Since this app has no real functionality,
  376.       // we will just bring up the 'Help' menu:
  377.             hMenu = GetSubMenu (GetMenu (hWnd), 2);
  378.             if (hMenu) {
  379.                 TrackPopupMenu (hMenu, 0, pnt.x, pnt.y, 0, hWnd, NULL);
  380.             } else {
  381.             // Couldn't find the menu...
  382.                 MessageBeep(0);
  383.             }
  384.             break;
  385.  
  386.  
  387.       case WM_DISPLAYCHANGE: // Only comes through on plug'n'play systems
  388.       {
  389.          SIZE  szScreen;
  390.          DWORD dwBitsPerPixel = (DWORD)wParam;
  391.  
  392.          szScreen.cx = LOWORD(lParam);
  393.          szScreen.cy = HIWORD(lParam);
  394.  
  395.          MessageBox (GetFocus(), GetStringRes(IDS_DISPLAYCHANGED),
  396.                      szAppName, 0);
  397.       }
  398.       break;
  399.  
  400.       case WM_PAINT:
  401.         {
  402.             MEMORYSTATUS    MemoryStatusData;
  403.             LONGLONG        llInUse;
  404.             DWORD            dwPercentUsed;
  405.  
  406.             int     nX, nY;
  407.             LONG    lTextOutReturn;
  408.             int     nStringLength;
  409.             CHAR            szOutputString[100];
  410.  
  411.             hdc = BeginPaint (hWnd, &ps);
  412.             // Add any drawing code here...
  413.             GlobalMemoryStatus (&MemoryStatusData);
  414.  
  415.             llInUse = (LONGLONG)(MemoryStatusData.dwTotalPageFile -
  416.                 MemoryStatusData.dwAvailPageFile + 5 );
  417.             llInUse *= 1000;
  418.             llInUse /= MemoryStatusData.dwTotalPageFile;
  419.             llInUse /= 10;
  420.  
  421.             dwPercentUsed = (DWORD)llInUse;
  422.  
  423.             nX = 0;
  424.             nY = 0;
  425.             sprintf (szOutputString, "Reported Memory Load: \t%3.1d%%",
  426.                 MemoryStatusData.dwMemoryLoad);
  427.             nStringLength = lstrlen (szOutputString) * sizeof (CHAR);
  428.             lTextOutReturn = TabbedTextOut (hdc, nX, nY,
  429.                 szOutputString, nStringLength, 0, NULL, 0);
  430.             nY += HIWORD (lTextOutReturn);
  431.  
  432.             sprintf (szOutputString, "Page file in use:  \t%3.1d%%",
  433.                 dwPercentUsed);
  434.             nStringLength = lstrlen (szOutputString) * sizeof (CHAR);
  435.             lTextOutReturn = TabbedTextOut (hdc, nX, nY,
  436.                 szOutputString, nStringLength, 0, NULL, 0);
  437.             nY += HIWORD (lTextOutReturn);
  438.  
  439.             EndPaint (hWnd, &ps);
  440.         }
  441.         break;
  442.  
  443.       case WM_DESTROY:
  444.          FreeAllocatedMemory();
  445.          // Tell WinHelp we don't need it any more...
  446.                WinHelp (hWnd, APPNAME".HLP", HELP_QUIT,(DWORD)0);
  447.          PostQuitMessage(0);
  448.          break;
  449.  
  450.       default:
  451.          return (DefWindowProc(hWnd, message, wParam, lParam));
  452.    }
  453.    return (0);
  454. }
  455.  
  456. //
  457. //  FUNCTION: About(HWND, unsigned, WORD, LONG)
  458. //
  459. //  PURPOSE:  Processes messages for "About" dialog box
  460. //       This version allows greater flexibility over the contents of the 'About' box,
  461. //       by pulling out values from the 'Version' resource.
  462. //
  463. //  MESSAGES:
  464. //
  465. // WM_INITDIALOG - initialize dialog box
  466. // WM_COMMAND    - Input received
  467. //
  468. //
  469. LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  470. {
  471.    static  HFONT hfontDlg;    // Font for dialog text
  472.    static   HFONT hFinePrint; // Font for 'fine print' in dialog
  473.    DWORD   dwVerInfoSize;     // Size of version information block
  474.    LPSTR   lpVersion;         // String pointer to 'version' text
  475.    DWORD   dwVerHnd=0;        // An 'ignored' parameter, always '0'
  476.    UINT    uVersionLen;
  477.    WORD    wRootLen;
  478.    BOOL    bRetCode;
  479.    int     i;
  480.    char    szFullPath[256];
  481.    char    szResult[256];
  482.    char    szGetName[256];
  483.    DWORD dwVersion;
  484.    char  szVersion[40];
  485.    DWORD dwResult;
  486.  
  487.    switch (message) {
  488.         case WM_INITDIALOG:
  489.          ShowWindow (hDlg, SW_HIDE);
  490.  
  491.          if (PRIMARYLANGID(GetUserDefaultLangID()) == LANG_JAPANESE)
  492.          {
  493.             hfontDlg = CreateFont(14, 0, 0, 0, 0, 0, 0, 0, SHIFTJIS_CHARSET, 0, 0, 0,
  494.                                   VARIABLE_PITCH | FF_DONTCARE, "");
  495.             hFinePrint = CreateFont(11, 0, 0, 0, 0, 0, 0, 0, SHIFTJIS_CHARSET, 0, 0, 0,
  496.                                     VARIABLE_PITCH | FF_DONTCARE, "");
  497.          }
  498.          else
  499.          {
  500.             hfontDlg = CreateFont(14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  501.                                   VARIABLE_PITCH | FF_SWISS, "");
  502.             hFinePrint = CreateFont(11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  503.                                     VARIABLE_PITCH | FF_SWISS, "");
  504.          }
  505.  
  506.          CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
  507.          GetModuleFileName (hInst, szFullPath, sizeof(szFullPath));
  508.  
  509.          // Now lets dive in and pull out the version information:
  510.          dwVerInfoSize = GetFileVersionInfoSize(szFullPath, &dwVerHnd);
  511.          if (dwVerInfoSize) {
  512.             LPSTR   lpstrVffInfo;
  513.             HANDLE  hMem;
  514.             hMem = GlobalAlloc(GMEM_MOVEABLE, dwVerInfoSize);
  515.             lpstrVffInfo  = GlobalLock(hMem);
  516.             GetFileVersionInfo(szFullPath, dwVerHnd, dwVerInfoSize, lpstrVffInfo);
  517.             // The below 'hex' value looks a little confusing, but
  518.             // essentially what it is, is the hexidecimal representation
  519.             // of a couple different values that represent the language
  520.             // and character set that we are wanting string values for.
  521.             // 040904E4 is a very common one, because it means:
  522.             //   US English, Windows MultiLingual characterset
  523.             // Or to pull it all apart:
  524.             // 04------        = SUBLANG_ENGLISH_USA
  525.             // --09----        = LANG_ENGLISH
  526.             // --11----        = LANG_JAPANESE
  527.             // ----04E4 = 1252 = Codepage for Windows:Multilingual
  528.  
  529.             lstrcpy(szGetName, GetStringRes(IDS_VER_INFO_LANG));
  530.  
  531.             wRootLen = lstrlen(szGetName); // Save this position
  532.  
  533.             // Set the title of the dialog:
  534.             lstrcat (szGetName, "ProductName");
  535.             bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
  536.                (LPSTR)szGetName,
  537.                (LPVOID)&lpVersion,
  538.                (UINT *)&uVersionLen);
  539.  
  540.             // Notice order of version and string...
  541.             if (PRIMARYLANGID(GetUserDefaultLangID()) == LANG_JAPANESE)
  542.             {
  543.                lstrcpy(szResult, lpVersion);
  544.                lstrcat(szResult, " é╠âoü[âWâçâôÅεò±");
  545.             }
  546.             else
  547.             {
  548.                lstrcpy(szResult, "About ");
  549.                lstrcat(szResult, lpVersion);
  550.             }
  551.  
  552.             // -----------------------------------------------------
  553.  
  554.             SetWindowText (hDlg, szResult);
  555.  
  556.             // Walk through the dialog items that we want to replace:
  557.             for (i = DLG_VERFIRST; i <= DLG_VERLAST; i++) {
  558.                GetDlgItemText(hDlg, i, szResult, sizeof(szResult));
  559.                szGetName[wRootLen] = (char)0;
  560.                lstrcat (szGetName, szResult);
  561.                uVersionLen   = 0;
  562.                lpVersion     = NULL;
  563.                bRetCode      =  VerQueryValue((LPVOID)lpstrVffInfo,
  564.                   (LPSTR)szGetName,
  565.                   (LPVOID)&lpVersion,
  566.                   (UINT *)&uVersionLen);
  567.  
  568.                if ( bRetCode && uVersionLen && lpVersion) {
  569.                // Replace dialog item text with version info
  570.                   lstrcpy(szResult, lpVersion);
  571.                   SetDlgItemText(hDlg, i, szResult);
  572.                }
  573.                else
  574.                {
  575.                   dwResult = GetLastError();
  576.  
  577.                   wsprintf(szResult, GetStringRes(IDS_VERSION_ERROR), dwResult);
  578.                   SetDlgItemText (hDlg, i, szResult);
  579.                }
  580.                SendMessage (GetDlgItem (hDlg, i), WM_SETFONT,
  581.                   (UINT)((i==DLG_VERLAST)?hFinePrint:hfontDlg),
  582.                   TRUE);
  583.             } // for (i = DLG_VERFIRST; i <= DLG_VERLAST; i++)
  584.  
  585.  
  586.             GlobalUnlock(hMem);
  587.             GlobalFree(hMem);
  588.  
  589.          } else {
  590.             // No version information available.
  591.          } // if (dwVerInfoSize)
  592.  
  593.             SendMessage (GetDlgItem (hDlg, IDC_LABEL), WM_SETFONT,
  594.             (WPARAM)hfontDlg,(LPARAM)TRUE);
  595.  
  596.          // We are  using GetVersion rather then GetVersionEx
  597.          // because earlier versions of Windows NT and Win32s
  598.          // didn't include GetVersionEx:
  599.          dwVersion = GetVersion();
  600.  
  601.          if (dwVersion < 0x80000000) {
  602.             // Windows NT
  603.             wsprintf (szVersion, "Microsoft Windows NT %u.%u (Build: %u)",
  604.                (DWORD)(LOBYTE(LOWORD(dwVersion))),
  605.                (DWORD)(HIBYTE(LOWORD(dwVersion))),
  606.                     (DWORD)(HIWORD(dwVersion)) );
  607.          } else if (LOBYTE(LOWORD(dwVersion))<4) {
  608.             // Win32s
  609.                 wsprintf (szVersion, "Microsoft Win32s %u.%u (Build: %u)",
  610.                (DWORD)(LOBYTE(LOWORD(dwVersion))),
  611.                (DWORD)(HIBYTE(LOWORD(dwVersion))),
  612.                     (DWORD)(HIWORD(dwVersion) & ~0x8000) );
  613.          } else {
  614.             // Windows 95
  615.                 wsprintf (szVersion, "Microsoft Windows 95 %u.%u",
  616.                     (DWORD)(LOBYTE(LOWORD(dwVersion))),
  617.                     (DWORD)(HIBYTE(LOWORD(dwVersion))) );
  618.          }
  619.  
  620.           SetWindowText (GetDlgItem(hDlg, IDC_OSVERSION), szVersion);
  621.          ShowWindow (hDlg, SW_SHOW);
  622.          return (TRUE);
  623.  
  624.       case WM_COMMAND:
  625.          if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
  626.             EndDialog(hDlg, TRUE);
  627.             DeleteObject (hfontDlg);
  628.             DeleteObject (hFinePrint);
  629.             return (TRUE);
  630.          }
  631.          break;
  632.    }
  633.  
  634.     return FALSE;
  635. }
  636.  
  637. //
  638. //   FUNCTION: CenterWindow(HWND, HWND)
  639. //
  640. //   PURPOSE: Centers one window over another.
  641. //
  642. //   COMMENTS:
  643. //
  644. //        In this function, we save the instance handle in a global variable and
  645. //        create and display the main program window.
  646. //
  647. //       This functionwill center one window over another ensuring that
  648. //    the placement of the window is within the 'working area', meaning
  649. //    that it is both within the display limits of the screen, and not
  650. //    obscured by the tray or other framing elements of the desktop.
  651. BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
  652. {
  653.    RECT    rChild, rParent, rWorkArea;
  654.    int     wChild, hChild, wParent, hParent;
  655.    int     xNew, yNew;
  656.    BOOL  bResult;
  657.  
  658.    // Get the Height and Width of the child window
  659.    GetWindowRect (hwndChild, &rChild);
  660.    wChild = rChild.right - rChild.left;
  661.    hChild = rChild.bottom - rChild.top;
  662.  
  663.    // Get the Height and Width of the parent window
  664.    GetWindowRect (hwndParent, &rParent);
  665.    wParent = rParent.right - rParent.left;
  666.    hParent = rParent.bottom - rParent.top;
  667.  
  668.    // Get the limits of the 'workarea'
  669.    bResult = SystemParametersInfo(
  670.       SPI_GETWORKAREA,  // system parameter to query or set
  671.       sizeof(RECT),
  672.       &rWorkArea,
  673.       0);
  674.    if (!bResult) {
  675.       rWorkArea.left = rWorkArea.top = 0;
  676.       rWorkArea.right = GetSystemMetrics(SM_CXSCREEN);
  677.       rWorkArea.bottom = GetSystemMetrics(SM_CYSCREEN);
  678.    }
  679.  
  680.    // Calculate new X position, then adjust for workarea
  681.    xNew = rParent.left + ((wParent - wChild) /2);
  682.    if (xNew < rWorkArea.left) {
  683.       xNew = rWorkArea.left;
  684.    } else if ((xNew+wChild) > rWorkArea.right) {
  685.       xNew = rWorkArea.right - wChild;
  686.    }
  687.  
  688.    // Calculate new Y position, then adjust for workarea
  689.    yNew = rParent.top  + ((hParent - hChild) /2);
  690.    if (yNew < rWorkArea.top) {
  691.       yNew = rWorkArea.top;
  692.    } else if ((yNew+hChild) > rWorkArea.bottom) {
  693.       yNew = rWorkArea.bottom - hChild;
  694.    }
  695.  
  696.    // Set it, and return
  697.    return SetWindowPos (hwndChild, NULL, xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
  698. }
  699.  
  700.  
  701. //---------------------------------------------------------------------------
  702. //
  703. // FUNCTION:    GetStringRes (int id INPUT ONLY)
  704. //
  705. // COMMENTS:    Load the resource string with the ID given, and return a
  706. //              pointer to it.  Notice that the buffer is common memory so
  707. //              the string must be used before this call is made a second time.
  708. //
  709. //---------------------------------------------------------------------------
  710.  
  711. LPTSTR   GetStringRes (int id)
  712. {
  713.   static TCHAR buffer[MAX_PATH];
  714.  
  715.   buffer[0]=0;
  716.   LoadString (GetModuleHandle (NULL), id, buffer, MAX_PATH);
  717.   return buffer;
  718. }
  719.  
  720.