home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / mslang / memwat / memwatch.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-13  |  15.3 KB  |  511 lines

  1. // MemWatch 1.1 is a small programmer utility that allows you to watch the memory usage of any
  2. // Windows application. If works by peeking into an applications memory at timed intervals. This
  3. // is initially set to .10 or 1/10 of a second. You can change this interval from the system pull
  4. // down menu. MemWatch is written in Microsoft Visual C++ 1.0 using the Microsoft Foundation Class
  5. // Library 2.0. By Todd Osborne - CompuServe ID 71431,2243
  6.  
  7. #include <afxwin.h>
  8. #include <afxext.h>
  9. #include <dos.h>
  10. #include "resourc2.h"
  11.  
  12. // The One and Only CWinApp
  13. class CMemwatchApp : public CWinApp
  14. {
  15. public:
  16.     virtual BOOL InitInstance();
  17. };
  18.  
  19. // CMainDlgWindow is a dialog box that is the main window
  20. class CMainDlgWindow : public CDialog
  21. {
  22. private:
  23.     void     dds_walk();
  24.     float     m_nTiming;
  25. public:
  26.     //{{AFX_DATA(CMainDlgWindow)
  27.          enum { IDD = IDD_MAIN };
  28.     //}}AFX_DATA
  29.     CMainDlgWindow();
  30. protected:
  31.     //{{AFX_MSG(CMainDlgWindow)
  32.     afx_msg void OnClose();
  33.     afx_msg void OnOK();
  34.     afx_msg void OnTimer(UINT nIDEvent);
  35.     afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
  36.     virtual BOOL OnInitDialog();
  37.     virtual void OnCancel();
  38.     //}}AFX_MSG
  39.     DECLARE_MESSAGE_MAP()
  40. };
  41.  
  42. // CTimingDlg is a dialog box that allow you to change the timing interval
  43. class CTimingDlg : public CDialog
  44. {
  45. public:
  46.     CTimingDlg(CWnd* pParent, float* Timing);
  47.     float* m_pTiming;
  48. // Dialog Data
  49.     //{{AFX_DATA(CTimingDlg)
  50.     enum { IDD = IDD_TIMING };
  51.     float    m_TB_TIMING;
  52.     //}}AFX_DATA
  53. // Implementation
  54. protected:
  55.     virtual void DoDataExchange(CDataExchange* pDX);
  56.     // Generated message map functions
  57.     //{{AFX_MSG(CTimingDlg)
  58.     virtual BOOL OnInitDialog();
  59.     afx_msg void OnClickOK();
  60.     //}}AFX_MSG
  61.     DECLARE_MESSAGE_MAP()
  62. };
  63.  
  64. // About Box
  65. class CAboutDlg : public CDialog
  66. {
  67. public:
  68.     CAboutDlg(CWnd* pParent = NULL);
  69.     // Dialog Data
  70.     //{{AFX_DATA(CAboutDlg)
  71.     enum { IDD = IDD_ABOUT };
  72.         // NOTE: the ClassWizard will add data members here
  73.     //}}AFX_DATA
  74. protected:
  75.     // Generated message map functions
  76.     //{{AFX_MSG(CAboutDlg)
  77.     virtual BOOL OnInitDialog();
  78.     //}}AFX_MSG
  79.     DECLARE_MESSAGE_MAP()
  80. };
  81.  
  82. typedef struct tagDEFAULTDATASEGMENT
  83.     {
  84.     HANDLE hinstActive; // instance handle of active app
  85.     HWND   hwndActive;  // window   handle of active app 
  86.     WORD wSize,         // size (bytes) of Data Segment.              
  87.          wStaticData,   // size (bytes) of static data.                     
  88.          wStackMax,     // size (bytes) of stack size defined in .DEF   
  89.          wStackUsed,    // size (bytes) of stack actually used.         
  90.          wHeapMoveable, // size (bytes) of heap allocation (moveable).  
  91.          wHeapFixed,    // size (bytes) of heap allocation (fixed).     
  92.          wHeapFree,     // size (bytes) of free space in heap.          
  93.          wOther,        // size (bytes) of remaining allocated space in DS.
  94.          wUnused;       // size (bytes) of heap unused.                 
  95.     } DEFAULTDATASEGMENT;
  96.  
  97. static DEFAULTDATASEGMENT DDS ;
  98.  
  99. // The one and only CWinApp object
  100. CMemwatchApp ThisApp;
  101.  
  102. // Initialize this instance
  103. BOOL CMemwatchApp::InitInstance()
  104. {
  105.     // Return pointer to main windows. In this case it is a dialog box
  106.     m_pMainWnd = new CMainDlgWindow();
  107.     
  108.     // Use SetClassWord to attach an icon to a dialog box
  109.     SetClassWord(m_pMainWnd->m_hWnd,GCW_HICON, (WORD)LoadIcon(AFX_IDI_STD_FRAME));
  110.     
  111.     return TRUE;
  112. }
  113.  
  114. CMainDlgWindow::CMainDlgWindow()
  115. {
  116.     // Call Create to create the main window dialog
  117.     Create(IDD_MAIN);
  118.     
  119.     // Set initial timing to 1/10 of a second
  120.     m_nTiming = .10;
  121. }
  122.  
  123. void CMainDlgWindow::OnOK()
  124. {
  125.     // Do nothing. Override default processing that closes window
  126. }
  127.  
  128. void CMainDlgWindow::OnCancel()
  129. {
  130.     // Do nothing. Override default processing that closes window
  131. }
  132.  
  133. void CMainDlgWindow::OnClose()
  134. {
  135.     // Clean up and end app
  136.     KillTimer(1);                                // Remove the timer set in WM_INITDIALOG
  137.     DestroyWindow();                            // Destroy the dialog box window
  138.     delete this;                                // Delete 'this' dialog box object
  139.     PostQuitMessage(0);                            // End the application
  140. }
  141.  
  142. BEGIN_MESSAGE_MAP(CMainDlgWindow, CDialog)
  143.     //{{AFX_MSG_MAP(CMainDlgWindow)
  144.     ON_WM_CLOSE()
  145.     ON_WM_TIMER()
  146.     ON_WM_SYSCOMMAND()
  147.     //}}AFX_MSG_MAP
  148. END_MESSAGE_MAP()
  149.  
  150. BOOL CMainDlgWindow::OnInitDialog()
  151. {
  152.     CDialog::OnInitDialog();
  153.     
  154.     CenterWindow();
  155.         
  156.     HMENU hMenu = ::GetSystemMenu (m_hWnd, FALSE);
  157.     
  158.     // Add Always On Top to System Menu
  159.     ::AppendMenu (hMenu, MF_SEPARATOR, 0, "");
  160.     ::AppendMenu (hMenu, MF_ENABLED, IDM_ALWAYSONTOP, "Always on &Top");
  161.     
  162.     // Add Exit Windows to System Menu
  163.     ::AppendMenu (hMenu, MF_ENABLED, IDM_EXITWINDOWS, "E&xit Windows");
  164.     
  165.     // Add Restart Windows to System Menu
  166.     ::AppendMenu (hMenu, MF_ENABLED, IDM_RESTARTWINDOWS, "&Restart Windows");
  167.     
  168.     // Add Timing to System Menu
  169.     ::AppendMenu (hMenu, MF_ENABLED, IDM_TIMING, "Set T&iming...");
  170.     
  171.     // Add About to System Menu
  172.        ::AppendMenu (hMenu, MF_ENABLED, IDM_ABOUT, "&About Memory Watcher...");
  173.                
  174.     // Set Timer to 1/10 second. NULL is used instead of callback function. CWnd object handles the WM_TIMER calls.
  175.     if ( !SetTimer(1, m_nTiming * 1000, NULL) ) MessageBox ("Too many Timers or Clocks have been set.", "Memory Watcher", MB_ICONSTOP | MB_OK);
  176.         
  177.     return TRUE;  // return TRUE  unless you set the focus to a control
  178. }
  179.  
  180.  
  181. void CMainDlgWindow::OnTimer(UINT nIDEvent)
  182. {
  183.     // Get Memory Information and Display if changed
  184.     dds_walk();
  185.         
  186.     CDialog::OnTimer(nIDEvent);
  187. }
  188.  
  189. void CMainDlgWindow::OnSysCommand(UINT nID, LPARAM lParam)
  190. {
  191.     // Handle menu commands from the system menu
  192.     switch (nID)
  193.     {
  194.         case IDM_ABOUT:
  195.             {
  196.             CAboutDlg dlg;
  197.             dlg.DoModal();
  198.             break;
  199.             }
  200.             
  201.         case IDM_ALWAYSONTOP:
  202.             {
  203.             HMENU hMenu= ::GetSystemMenu (m_hWnd, FALSE);
  204.             // Toggle State of Menu Item
  205.             int CurVal = GetMenuState(hMenu, IDM_ALWAYSONTOP, MF_BYCOMMAND);
  206.             if ( MF_CHECKED & CurVal )
  207.                 {
  208.                 ::SetWindowPos(m_hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
  209.                 ::CheckMenuItem(hMenu, IDM_ALWAYSONTOP, MF_BYCOMMAND | MF_UNCHECKED);
  210.                 }
  211.             else
  212.                 {
  213.                 ::SetWindowPos(m_hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
  214.                 ::CheckMenuItem(hMenu, IDM_ALWAYSONTOP, MF_BYCOMMAND | MF_CHECKED);
  215.                 }
  216.             break;
  217.             }
  218.         
  219.         case IDM_EXITWINDOWS:
  220.             ExitWindows(0,0);
  221.             break;
  222.             
  223.         case IDM_RESTARTWINDOWS:
  224.             ExitWindows(EW_RESTARTWINDOWS,0);
  225.             break;
  226.         
  227.         case IDM_TIMING:
  228.             {
  229.             CTimingDlg dlg(this, &m_nTiming);
  230.             dlg.DoModal();
  231.             KillTimer(1);
  232.             SetTimer(1, m_nTiming * 1000, NULL);
  233.             break;
  234.             }
  235.     }
  236.             
  237.     CDialog::OnSysCommand(nID, lParam);
  238. }
  239.  
  240. void CMainDlgWindow::dds_walk ()
  241. {
  242.     /*     Original Code by: Chiverton Graphics, Inc. 1991
  243.         Modified by Todd Osborne January 1994 to MFC 2.0 C++
  244.         application with new features. CompuServe ID: 71431,2243
  245.     */
  246.     
  247.     static DEFAULTDATASEGMENT OldDDS;
  248.     
  249.     WORD  wRecordSize,          // size in bytes of heap record.          
  250.           wStatus;              // type of heap record.
  251.  
  252.     LPSTR lpInstance,           // far pointer to Default Data Segment.      
  253.           lpHeapRecord,         // far pointer to heap record.            
  254.           lpNextHeapRecord;     // far pointer to next heap record.       
  255.  
  256.     #define PREV_POINTER (*(WORD FAR*) lpHeapRecord)     // Backward "pointer" 
  257.     #define NEXT_POINTER (*(WORD FAR*)(lpHeapRecord+2))  // Forward "pointer" 
  258.  
  259.     #define PSTACKBOTTOM (*(WORD FAR*)(lpInstance+14))
  260.     #define PSTACKMIN    (*(WORD FAR*)(lpInstance+12))
  261.     #define PSTACKTOP    (*(WORD FAR*)(lpInstance+10))
  262.     #define PLOCALHEAP   (*(WORD FAR*)(lpInstance+ 6))
  263.     
  264.     // First, initialize the data segment values.
  265.     DDS.wSize         = 0;
  266.     DDS.wStaticData   = 0;
  267.     DDS.wStackMax     = 0;
  268.     DDS.wStackUsed    = 0;
  269.     DDS.wHeapMoveable = 0;
  270.     DDS.wHeapFixed    = 0;
  271.     DDS.wHeapFree     = 0;
  272.     DDS.wOther        = 0;
  273.     DDS.wUnused       = 0;
  274.  
  275.     // Now, get the window that has the focus.
  276.     DDS.hwndActive = ::GetActiveWindow ();
  277.     
  278.     // Is it a valid window?
  279.     if ( !IsWindow (DDS.hwndActive) )  return;
  280.  
  281.     //   If this is a different window than before, get a new instance handle.
  282.     if (DDS.hwndActive != OldDDS.hwndActive)
  283.         {
  284.         DDS.hinstActive = (HANDLE) GetWindowWord (DDS.hwndActive, GWW_HINSTANCE);
  285.         if (!DDS.hinstActive) return;
  286.         }
  287.  
  288.     //    Lock down the Data Segment
  289.     if ( !(lpInstance = (LPSTR)GlobalLock (DDS.hinstActive))) return;
  290.  
  291.     /*
  292.      *  The Data Segment is a global memory object - created by WINDOWS
  293.      *  with a GlobalAlloc. It's comprised of 4 components: header,
  294.      *  Static, stack, and local heap. All 4 components are offset
  295.      *  into the segment, with the header at DS:0000.
  296.      *
  297.      *
  298.      *  The header occupies the first 16 bytes of a Default Data Segment.
  299.      *  Within the Header area are 3 pointers to the stack:
  300.      *
  301.      *  pStackBottom - (highest physical address) beginning of stack.
  302.      *  pStackMin    - High-Water mark of actual stack use.
  303.      *  pStackTop    - (lowest physical address) end of stack.
  304.      *
  305.      *  Remember, the stack grows "down" (higher to lower address), so
  306.      *  to compute the stack sizes, we use these equations:
  307.      *
  308.      *   wStackMax  = pStackBottom - pStackTop ;
  309.      *   wStackUsed = pStackBottom - pStackMin ;
  310.      *
  311.      *
  312.      */
  313.     DDS.wStackMax   = PSTACKBOTTOM - PSTACKTOP ;
  314.     DDS.wStackUsed  = PSTACKBOTTOM - PSTACKMIN ;
  315.     DDS.wStaticData = PSTACKTOP ; 
  316.  
  317.     // First test for a heap. (It's possible there isn't one.)
  318.     if (PLOCALHEAP == 0)
  319.         {
  320.         GlobalUnlock (DDS.hinstActive);
  321.         return;
  322.         }
  323.  
  324.     /*
  325.      *  The heap begins where the
  326.      *  stack ends. The offset that represents the
  327.      *  beginning of the heap is stored in the header area, 6 bytes from
  328.      *  DS:0000. Actually, the heap begins 4 bytes before this offset.
  329.      *
  330.      *  Now we'll get a far pointer (lpHeapRecord) to the 1st record in the heap.
  331.      *
  332.      */
  333.     lpHeapRecord = lpInstance + PLOCALHEAP - 4;
  334.  
  335.  
  336.     /*
  337.      *  Traverse the local heap. The heap is implemented as a doubly-linked
  338.      *  list. The 1st WORD is a backward "pointer" (ie, offset) to the
  339.      *  previous record. The 2nd WORD is the forward pointer to the next record.
  340.      *  When the forward pointer points to itself we are done.
  341.      *
  342.      */
  343.     DDS.wSize = (WORD)GlobalSize (DDS.hinstActive);
  344.  
  345.     while (FP_OFF(lpHeapRecord) < DDS.wSize)
  346.         {
  347.         lpNextHeapRecord = (lpInstance + NEXT_POINTER);
  348.         if (lpNextHeapRecord == lpHeapRecord) break;
  349.         wRecordSize = lpNextHeapRecord - lpHeapRecord; //includes ptr overhead
  350.         wStatus     = (PREV_POINTER & 0x0003);
  351.  
  352.     switch (wStatus)
  353.         {
  354.         case 0: DDS.wHeapFree     += wRecordSize; break;
  355.         case 1: DDS.wHeapFixed    += wRecordSize; break;
  356.         case 3: DDS.wHeapMoveable += wRecordSize; break;
  357.         }
  358.  
  359.          lpHeapRecord = lpNextHeapRecord;
  360.          }
  361.  
  362.     /*
  363.      *  At this point, heap traversal is done.
  364.      *  However, the heap can grow until the size of DS is 64K (0xFFFF).
  365.      *  Determine how many additional bytes the heap can grow.
  366.     */
  367.     DDS.wUnused = 0xFFFF   - DDS.wSize;
  368.      
  369.     // Anything else we didn't account for?
  370.     DDS.wOther  = DDS.wSize - DDS.wStaticData
  371.                             - DDS.wStackMax
  372.                             - DDS.wHeapFixed
  373.                             - DDS.wHeapFree
  374.                             - DDS.wHeapMoveable ;
  375.     
  376.     GlobalUnlock (DDS.hinstActive);
  377.  
  378.     //   If anything has changed since last walk, update client window.
  379.     if (DDS.hwndActive    != OldDDS.hwndActive    ||
  380.         DDS.wHeapFree     != OldDDS.wHeapFree     ||
  381.         DDS.wHeapFixed    != OldDDS.wHeapFixed    ||
  382.         DDS.wHeapMoveable != OldDDS.wHeapMoveable ||
  383.         DDS.wOther        != OldDDS.wOther        ||
  384.         DDS.wSize         != OldDDS.wSize         ||
  385.         DDS.wStackUsed    != OldDDS.wStackUsed)
  386.        {
  387.         // Update Dialog Box Values
  388.         char sz[80];
  389.         
  390.         // Get Active Window Title
  391.         char Title[80];
  392.         ::GetWindowText(DDS.hwndActive, Title, 80);
  393.         sprintf(sz, "Watching: %s", Title);
  394.         SetDlgItemText(LBL_WATCHING, sz);
  395.         
  396.         // Fill in Memory Information
  397.         sprintf(sz, "%u", DDS.wSize);
  398.         SetDlgItemText(LBL_DATA0, sz);
  399.         
  400.         sprintf(sz, "%u", DDS.wStaticData);
  401.         SetDlgItemText(LBL_DATA1, sz);
  402.         
  403.         sprintf(sz, "%u", DDS.wStackMax);
  404.         SetDlgItemText(LBL_DATA2, sz);
  405.         
  406.         sprintf(sz, "%u", DDS.wStackUsed);
  407.         SetDlgItemText(LBL_DATA3, sz);
  408.         
  409.         sprintf(sz, "%u", DDS.wHeapMoveable);
  410.         SetDlgItemText(LBL_DATA4, sz);
  411.         
  412.         sprintf(sz, "%u", DDS.wHeapFixed);
  413.         SetDlgItemText(LBL_DATA5, sz);
  414.         
  415.         sprintf(sz, "%u", DDS.wHeapFree);
  416.         SetDlgItemText(LBL_DATA6, sz);
  417.         
  418.         sprintf(sz, "%u", DDS.wOther);
  419.         SetDlgItemText(LBL_DATA7, sz);
  420.         
  421.         sprintf(sz, "%u", DDS.wUnused);
  422.         SetDlgItemText(LBL_DATA8, sz);
  423.                 
  424.         sprintf(sz, "%.3f", m_nTiming);
  425.         SetDlgItemText(LBL_DATA9, sz);
  426.         
  427.         OldDDS = DDS;
  428.     }
  429. }
  430.  
  431.  
  432. /////////////////////////////////////////////////////////////////////////////
  433. // CAboutDlg dialog
  434. CAboutDlg::CAboutDlg(CWnd* pParent /*=NULL*/)
  435.     : CDialog(CAboutDlg::IDD, pParent)
  436. {
  437. }
  438.  
  439. BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
  440.     //{{AFX_MSG_MAP(CAboutDlg)
  441.     //}}AFX_MSG_MAP
  442. END_MESSAGE_MAP()
  443.  
  444. BOOL CAboutDlg::OnInitDialog()
  445. {
  446.     CDialog::OnInitDialog();
  447.     CenterWindow();
  448.         
  449.     // Get and Display System Resources in LBL_SYS_RESOURCES ID
  450.     UINT System = GetFreeSystemResources(GFSR_SYSTEMRESOURCES);
  451.     UINT GDI    = GetFreeSystemResources(GFSR_GDIRESOURCES);
  452.     UINT User   = GetFreeSystemResources(GFSR_USERRESOURCES);
  453.     
  454.     char str[256];
  455.     sprintf(str, "System: %u%c  GDI: %u%c  User: %u%c", System, 37, GDI, 37,  User, 37); 
  456.     SetDlgItemText(LBL_SYS_RESOURCES,str);
  457.     
  458.     return TRUE;  // return TRUE  unless you set the focus to a control
  459. }
  460.  
  461.  
  462. /////////////////////////////////////////////////////////////////////////////
  463. // CTimingDlg dialog
  464. CTimingDlg::CTimingDlg(CWnd* pParent /*=NULL*/, float* Timing)
  465.     : CDialog(CTimingDlg::IDD, pParent)
  466. {
  467.     // The parent passed in a pointer to m_nTiming
  468.     // Save this so that a new variable can be places at the same
  469.     // memory location on exit of this dialog box
  470.     
  471.     //{{AFX_DATA_INIT(CTimingDlg)
  472.     m_TB_TIMING = *Timing;
  473.     m_pTiming = Timing;
  474.     //}}AFX_DATA_INIT
  475. }
  476.  
  477. void CTimingDlg::DoDataExchange(CDataExchange* pDX)
  478. {
  479.     CDialog::DoDataExchange(pDX);
  480.     //{{AFX_DATA_MAP(CTimingDlg)
  481.     DDX_Text(pDX, TB_TIMING, m_TB_TIMING);
  482.     //}}AFX_DATA_MAP
  483. }
  484.  
  485. BEGIN_MESSAGE_MAP(CTimingDlg, CDialog)
  486.     //{{AFX_MSG_MAP(CTimingDlg)
  487.     ON_BN_CLICKED(IDOK, OnClickOK)
  488.     //}}AFX_MSG_MAP
  489. END_MESSAGE_MAP()
  490.  
  491. /////////////////////////////////////////////////////////////////////////////
  492. // CTimingDlg message handlers
  493.  
  494. BOOL CTimingDlg::OnInitDialog()
  495. {
  496.     CDialog::OnInitDialog();
  497.     this->CenterWindow();
  498.     return TRUE;  // return TRUE  unless you set the focus to a control
  499. }
  500.  
  501. void CTimingDlg::OnClickOK()
  502. {
  503.     if ( this->UpdateData(TRUE) )
  504.         {
  505.         // Copy new timing info to address passed in constructor
  506.         *m_pTiming = m_TB_TIMING;
  507.         this->EndDialog(0);
  508.         }
  509.     else MessageBox("You must enter a decimal value.", "Error", MB_ICONSTOP | MB_OK);
  510. }
  511.