home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c480 / 17.ddi / SAMPLES / TOOLHELP / THSAMPLE.C_ / THSAMPLE.C
Encoding:
C/C++ Source or Header  |  1993-02-08  |  48.4 KB  |  1,619 lines

  1. /**************************************************************************
  2.  *  THSAMPLE.C
  3.  *
  4.  *      TOOLHELP.DLL Sample program
  5.  *
  6.  **************************************************************************/
  7.  
  8. #include <stdio.h>
  9. #undef NULL
  10. #include <windows.h>
  11. #include <string.h>
  12. #include <toolhelp.h>
  13. #include "thsample.h"
  14.  
  15. /* ----- Symbols ----- */
  16. #define LIST_WIDTH      70
  17. #define LIST_NONE       0
  18. #define LIST_GLOBAL     1
  19. #define LIST_MODULE     2
  20. #define LIST_TASK       3
  21. #define LIST_HEAP       4
  22. #define LIST_TOOLHELP   5
  23. #define LIST_MEMMAN     6
  24. #define LIST_CLASS      7
  25. #define BUTTON_WIDTH    (10 * xChar)
  26. #define BUTTON_MARGIN   xChar
  27. #define IDM_WRITE       100
  28. #define IDM_WRITEBP     101
  29.  
  30. #ifndef SHORT
  31. typedef short int SHORT;
  32. #endif
  33.  
  34. /* ----- Memory window extra values ----- */
  35. #define MEM_BLOCK       0
  36. #define MEM_GLOBALENTRY 2
  37. #define MEM_LPOURBLOCK  4
  38. #define MEM_HOURBLOCK   8
  39.  
  40. /* ----- Macros ----- */
  41. #define MAXLINES(dwSize,yClient) \
  42.     max((SHORT)(dwSize / 16) - ((SHORT)yClient) / yChar, 0)
  43.  
  44. /* ----- Function prototypes ----- */
  45.  
  46. LONG __export CALLBACK WndProc            (HWND hWnd, UINT wMessage, WPARAM wParam, LPARAM lParam);
  47. LONG __export CALLBACK MemWndProc        (HWND hWnd, UINT wMessage, WPARAM wParam, LPARAM lParam);
  48. void PASCAL DumpMem                        (HWND hwnd, HDC hDC, SHORT nScrollPos, SHORT nPos);
  49. LONG WalkGlobalHeap                        (HWND hwnd);
  50. LONG WalkFreeList                        (HWND hwnd);
  51. LONG WalkLRUList                        (HWND hwnd);
  52. LONG WalkLocalHeap                        (HWND hwnd, HANDLE hBlock);
  53. LONG WalkModuleList                        (HWND hwnd);
  54. LONG WalkTaskList                        (HWND hwnd);
  55. LONG WalkClassList                        (HWND hwnd);
  56. LONG DoStackTrace                        (HWND hwnd);
  57. LONG DoHeapInfo                            (HWND hwnd);
  58. LONG DoMemManInfo                        (HWND hwnd);
  59. LONG DoGlobalEntryModuleTest            (HWND hwnd);
  60. LONG ReadMemoryTest                        (HWND hwnd, HANDLE hBlock);
  61. LONG TimerCountTest                        (HWND hwnd);
  62. BOOL __export CALLBACK MyNotifyHandler    (WORD wID, DWORD dwData);
  63.  
  64. WORD __export _cdecl MyCFaultHandler(WORD wES, WORD wDS, WORD wDI, WORD wSI, WORD wBP, WORD wSP, WORD wBX,
  65.         WORD wDX, WORD wCX, WORD wOldAX, WORD wOldBP, WORD wRetIP, WORD wRetCS, WORD wRealAX,
  66.         WORD wNumber, WORD wHandle, WORD wIP, WORD wCS, WORD wFlags);
  67.  
  68. BOOL __export CALLBACK FaultDialogProc    (HWND hDlg, WORD wMessage, WORD wParam, DWORD dwParam);
  69.  
  70. /* ----- Global variables ----- */
  71. short xScreen;
  72. short yScreen;
  73. short xChar;
  74. short yChar;
  75. HANDLE hInst;
  76. HWND hwndList;
  77. HWND hwndListLocal;
  78. HWND hwndListStatic;
  79. WORD wListStatus = LIST_NONE;
  80. char szText[80];
  81. HWND hwndMain;
  82. WORD wNotifyIn;
  83. WORD wNotifyOut;
  84. WORD wNotifyState;
  85. WORD wFilterState;
  86. WORD wsCS;
  87. WORD wsIP;
  88. WORD wsFault;
  89. WORD wsFaultTask;
  90. WORD wsProgramTask;
  91. char szAppName[] = "THTest";
  92. char szMemName[] = "THMemPopup";
  93. extern BYTE _AHINCR;
  94.  
  95. char *szBlockTypes[] =
  96. {
  97.     "Private", "DGroup", "Data", "Code", "Task", "Resource",
  98.     "Module", "Free", "Internal", "Sentinel", "BMaster"
  99. };
  100. char bHasData[] = { 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0 };
  101. char *szLocalFlags[] = { "", "Fixed", "Free", "", "Moveable" };
  102. char *szGDI[] =
  103. {
  104.     "Unknown", "Pen", "Brush", "Font", "Palette", "Bitmap", "Region",
  105.     "DC", "DisabledDC", "MetaDC", "Metafile", ""
  106. };
  107. char *szUser[] =
  108. {
  109.     "Unknown", "Class", "Window", "String", "Menu", "Clip", "CBox",
  110.     "Palette", "Ed", "Bwl", "OwnerDraw", "SPB", "CheckPoint", "DCE",
  111.     "MWP", "PROP", "LBIV", "Misc", "Atoms", "LockInp", "HookList",
  112.     "UserSeeUserDo", "HotKeyList", "PopupMenu", "HandleTab", ""
  113. };
  114. char *szNotify[] =
  115. {
  116.     "Unknown", "LoadSeg", "FreeSeg", "StartDLL", "StartTask",
  117.     "ExitTask", "DelModule", "RIP", "TaskIn", "TaskOut", "InChar",
  118.     "OutStr", "LogErr", "LogPError"
  119. };
  120.  
  121.  
  122. /*  WinMain
  123.  */
  124.  
  125. int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
  126. {
  127.     HWND hwnd;
  128.     MSG msg;
  129.     WNDCLASS wndclass;
  130.  
  131.     /* Register the interrupt handler */
  132.     wsProgramTask = GetCurrentTask();
  133.  
  134.     if (!InterruptRegister(NULL, (FARPROC)MyCFaultHandler))
  135.     {
  136.         OutputDebugString("THTest: Interrupt hook failed!!\r\n");
  137.         return 1;
  138.     }
  139.  
  140.     /* Register the notification handler */
  141.  
  142.     if (!NotifyRegister(
  143.     NULL, (LPFNNOTIFYCALLBACK)MyNotifyHandler, (WORD)NF_TASKSWITCH | NF_RIP))
  144.     {
  145.         OutputDebugString("THTest: Notification hook failed!!\r\n");
  146.         return 1;
  147.     }
  148.  
  149.     xScreen = GetSystemMetrics(SM_CXSCREEN);
  150.     yScreen = GetSystemMetrics(SM_CYSCREEN);
  151.     hInst = hInstance;
  152.  
  153.     if (!hPrevInstance)
  154.     {
  155.         wndclass.style = 0L;
  156.         wndclass.lpfnWndProc = WndProc;
  157.         wndclass.cbClsExtra = 0;
  158.         wndclass.cbWndExtra = 0;
  159.         wndclass.hInstance = hInstance;
  160.         wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(1));
  161.         wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  162.         wndclass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  163.         wndclass.lpszMenuName = MAKEINTRESOURCE(ID_MENU);
  164.         wndclass.lpszClassName = szAppName;
  165.  
  166.         if (!RegisterClass(&wndclass))
  167.             return FALSE;
  168.  
  169.         wndclass.style = 0L;
  170.         wndclass.lpfnWndProc = MemWndProc;
  171.         wndclass.cbClsExtra = 0;
  172.         wndclass.cbWndExtra = 10;
  173.         wndclass.hInstance = hInstance;
  174.         wndclass.hIcon = NULL;
  175.         wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  176.         wndclass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  177.         wndclass.lpszMenuName = NULL;
  178.         wndclass.lpszClassName = szMemName;
  179.  
  180.         if (!RegisterClass(&wndclass))
  181.             return FALSE;
  182.     }
  183.  
  184.     hwnd = CreateWindow(
  185.         szAppName,              /* Window class name */
  186.         "TOOLHELP.DLL Test",    /* Window caption */
  187.         WS_OVERLAPPEDWINDOW,    /* Window style */
  188.         CW_USEDEFAULT,          /* Initial X position */
  189.         0,                      /* Initial Y position */
  190.         CW_USEDEFAULT,          /* Initial X size */
  191.         0,                      /* Initial Y size */
  192.         NULL,                   /* Parent window handle */
  193.         NULL,                   /* Window menu handle */
  194.         hInstance,              /* Program instance handle */
  195.         NULL);                  /* Create parameters */
  196.  
  197.     ShowWindow(hwnd, nCmdShow);
  198.     UpdateWindow(hwnd);
  199.  
  200.     hwndMain = hwnd;
  201.  
  202.     while (GetMessage(&msg, NULL, 0, 0))
  203.     {
  204.         TranslateMessage(&msg);
  205.         DispatchMessage(&msg);
  206.     }
  207.  
  208.     /* Get rid of our Fault handler and our notification handler */
  209.     InterruptUnRegister(NULL);
  210.     NotifyUnRegister(NULL);
  211.  
  212.     return msg.wParam;
  213. }
  214.  
  215.  
  216. /*  WndProc
  217.  *      Main controlling window for sample program
  218.  */
  219.  
  220. LONG __export CALLBACK WndProc(HWND hwnd, UINT wMessage, WPARAM wParam, LPARAM lParam)
  221. {
  222.     HDC hDC;
  223.     TEXTMETRIC tm;
  224.     HANDLE hTask;
  225.     static HFONT hFont;
  226.  
  227.     switch (wMessage)
  228.     {
  229.     case WM_CREATE:
  230.  
  231.         /* Get static constants */
  232.         hDC = GetDC(hwnd);
  233.         GetTextMetrics(hDC, &tm);
  234.         xChar = tm.tmAveCharWidth;
  235.         yChar = tm.tmHeight + tm.tmExternalLeading;
  236.         ReleaseDC(hwnd, hDC);
  237.  
  238.         /* Create child controls */
  239.         hwndListStatic = CreateWindow(
  240.             "static",
  241.             NULL,
  242.             WS_CHILD | WS_VISIBLE | SS_LEFT,
  243.             xChar, 4 * yChar, 0, 0,
  244.             hwnd, 1, hInst, NULL);
  245.         hwndList = CreateWindow(
  246.             "listbox",
  247.             NULL,
  248.             WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | LBS_USETABSTOPS |
  249.             LBS_NOTIFY,
  250.             xChar, 5 * yChar + 2, 0, 0,
  251.             hwnd, 2, hInst, NULL);
  252.         hwndListLocal = CreateWindow(
  253.             "listbox",
  254.             NULL,
  255.             WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | LBS_USETABSTOPS |
  256.             LBS_NOTIFY,
  257.             xChar, 0, 0, 0,
  258.             hwnd, 3, hInst, NULL);
  259.  
  260.         /* Put a small non-proportional font in the box */
  261.            hFont = GetStockObject(SYSTEM_FIXED_FONT);
  262.         SendMessage(hwndList, WM_SETFONT, hFont, NULL);
  263.         SendMessage(hwndListLocal, WM_SETFONT, hFont, NULL);
  264.         break;
  265.  
  266.     case WM_SIZE:
  267.     if ((short)HIWORD(lParam) < 8 * yChar || (short)LOWORD(lParam) < 10 * xChar)
  268.         {
  269.             ShowWindow(hwndList, SW_HIDE);
  270.             ShowWindow(hwndListLocal, SW_HIDE);
  271.             ShowWindow(hwndListStatic, SW_HIDE);
  272.         }
  273.         else
  274.         {
  275.             short nHeight;
  276.             short nWidth;
  277.  
  278.             nHeight = (HIWORD(lParam) - 2 * yChar) / 2 - yChar / 2;
  279.             nWidth = LOWORD(lParam) - 2 * xChar;
  280.             ShowWindow(hwndList, SW_SHOWNORMAL);
  281.             ShowWindow(hwndListStatic, SW_SHOWNORMAL);
  282.             ShowWindow(hwndListLocal, SW_SHOWNORMAL);
  283.             MoveWindow(hwndList, xChar, yChar, nWidth, nHeight, TRUE);
  284.             MoveWindow(hwndListLocal, xChar, yChar + nHeight + yChar,
  285.                 nWidth, nHeight, TRUE);
  286.             MoveWindow(hwndListStatic, 2 * xChar, 0, nWidth - 2 * xChar,
  287.                 yChar, TRUE);
  288.             UpdateWindow(hwndList);
  289.             UpdateWindow(hwndListLocal);
  290.         }
  291.         return 0L;
  292.  
  293.     case WM_USER:
  294.         /* Only handle the notifications we know about */
  295.         if (wParam > 15)
  296.             wParam = 0;
  297.  
  298.         /* Make a nice message to put in the box */
  299.         wsprintf(szText, "%-12s\t| %08lX",
  300.             (LPSTR)szNotify[wParam], lParam);
  301.         SendMessage(hwndListLocal, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  302.         return 0L;
  303.  
  304.     case WM_COMMAND:
  305.         switch (wParam)
  306.         {
  307.         case 2:     /* List box notification message */
  308.             if (HIWORD(lParam) != LBN_DBLCLK)
  309.                 return 0L;
  310.  
  311.             if (wListStatus == LIST_GLOBAL)
  312.             {
  313.                 HANDLE hBlock;
  314.                 GLOBALENTRY Global;
  315.  
  316.                 /* Get the global handle from the list box */
  317.                 SendMessage(hwndList, LB_GETTEXT,
  318.                     (WORD)SendMessage(hwndList, LB_GETCURSEL, 0, 0L),
  319.                     (LONG)(LPSTR)szText);
  320.                 sscanf(szText, "%*2c%*lx %*2c%x", &hBlock);
  321.  
  322.                 /* See if this block has a local heap, if not, call the
  323.                  *  memory dump routine to test the memory functions.
  324.                  */
  325.                 if (hBlock)
  326.                 {
  327.                     Global.dwSize = sizeof (GLOBALENTRY);
  328.                     GlobalEntryHandle(&Global, hBlock);
  329.                 }
  330.                 if (!hBlock)
  331.                     return 0L;
  332.                 else if (Global.wHeapPresent)
  333.                     return WalkLocalHeap(hwnd, hBlock);
  334.                 else
  335.                     return ReadMemoryTest(hwnd, hBlock);
  336.             }
  337.             else if (wListStatus == LIST_TASK)
  338.                 return DoStackTrace(hwnd);
  339.             else
  340.                 return 0L;
  341.  
  342.         case IDM_TEST_1:
  343.             return WalkGlobalHeap(hwnd);
  344.  
  345.         case IDM_TEST_2:
  346.             return WalkFreeList(hwnd);
  347.  
  348.         case IDM_TEST_3:
  349.             return WalkLRUList(hwnd);
  350.  
  351.         case IDM_TEST_4:
  352.             return WalkModuleList(hwnd);
  353.  
  354.         case IDM_TEST_5:
  355.             return WalkTaskList(hwnd);
  356.  
  357.         case IDM_TEST_10:
  358.             return WalkClassList(hwnd);
  359.  
  360.         case IDM_TEST_6:
  361.             return DoHeapInfo(hwnd);
  362.  
  363.         case IDM_TEST_8:
  364.             return DoGlobalEntryModuleTest(hwnd);
  365.  
  366.         case IDM_TEST_9:
  367.             return DoMemManInfo(hwnd);
  368.  
  369.         case IDM_TEST_11:
  370.             if (wListStatus != LIST_TASK)
  371.                 return 0L;
  372.  
  373.             /* Get the task handle from the list box */
  374.             SendMessage(hwndList, LB_GETTEXT,
  375.                 (WORD)SendMessage(hwndList, LB_GETCURSEL, 0, 0L),
  376.                 (LONG)(LPSTR)szText);
  377.             sscanf(szText, "%*6c%x", &hTask);
  378.  
  379.             /* Nuke the task if it is not the current one */
  380.             if (hTask != wsProgramTask)
  381.                 TerminateApp(hTask, NO_UAE_BOX);
  382.  
  383.             /* Update the task list and get out */
  384.             return WalkTaskList(hwnd);
  385.  
  386.         case IDM_TEST_12:
  387.             return TimerCountTest(hwnd);
  388.  
  389.         case IDM_EXIT:
  390.             SendMessage(hwnd, WM_CLOSE, 0, 0L);
  391.             break;
  392.  
  393.         case IDM_FAULT_1:
  394.         case IDM_FAULT_2:
  395.         case IDM_FAULT_3:
  396.         case IDM_FAULT_4:
  397.         case IDM_FAULT_5:
  398.         case IDM_FAULT_6:
  399.         case IDM_FAULT_7:
  400.         case IDM_FAULT_8:
  401.             Fault(wParam);
  402.             return 0L;
  403.  
  404.         case IDM_NOTIFY_ENABLE:
  405.             if (GetMenuState(GetMenu(hwnd), IDM_NOTIFY_ENABLE, 0) & MF_CHECKED)
  406.             {
  407.                 wNotifyState = FALSE;
  408.                 CheckMenuItem(GetMenu(hwnd), IDM_NOTIFY_ENABLE, MF_UNCHECKED);
  409.             }
  410.             else
  411.             {
  412.                 wNotifyState = TRUE;
  413.                 CheckMenuItem(GetMenu(hwnd), IDM_NOTIFY_ENABLE, MF_CHECKED);
  414.             }
  415.             return 0L;
  416.  
  417.         case IDM_FILTER_ENABLE:
  418.             if (GetMenuState(GetMenu(hwnd), IDM_FILTER_ENABLE, 0) & MF_CHECKED)
  419.             {
  420.                 wFilterState = FALSE;
  421.                 CheckMenuItem(GetMenu(hwnd), IDM_FILTER_ENABLE, MF_UNCHECKED);
  422.             }
  423.             else
  424.             {
  425.                 wFilterState = TRUE;
  426.                 CheckMenuItem(GetMenu(hwnd), IDM_FILTER_ENABLE, MF_CHECKED);
  427.             }
  428.             return 0L;
  429.  
  430.         case IDM_NOTIFY_CLEAR:
  431.             SendMessage(hwndListLocal, WM_SETREDRAW, FALSE, 0L);
  432.             SendMessage(hwndListLocal, LB_RESETCONTENT, 0, 0L);
  433.             SendMessage(hwndListLocal, WM_SETREDRAW, TRUE, 0L);
  434.             InvalidateRect(hwndListLocal, NULL, TRUE);
  435.             return 0L;
  436.         }
  437.         break;
  438.  
  439.     case WM_DESTROY:
  440.         PostQuitMessage(0);
  441.         break;
  442.  
  443.     default:
  444.         return DefWindowProc(hwnd, wMessage, wParam, lParam);
  445.     }
  446.  
  447.     return 0L;
  448. }
  449.  
  450. /*  MemWndProc
  451.  *      Window proc for memory browser.
  452.  */
  453.  
  454. LONG __export CALLBACK MemWndProc(HWND hwnd, UINT wMessage, WPARAM wParam, LPARAM lParam)
  455. {
  456.     GLOBALENTRY *pGlobal;
  457.     WORD w;
  458.     LPSTR lpBlock;
  459.     RECT rect;
  460.     HMENU hMenu;
  461.     DWORD dwReturn;
  462.  
  463.     switch (wMessage)
  464.     {
  465.     case WM_CREATE:
  466.         /* Save the block pointer as window WORD 0 */
  467.         SetWindowWord(hwnd, MEM_BLOCK,
  468.             LOWORD((LONG)((LPCREATESTRUCT)lParam)->lpCreateParams));
  469.  
  470.         /* Get information about this block */
  471.         pGlobal = (GLOBALENTRY *)LocalAlloc(LMEM_FIXED, sizeof (GLOBALENTRY));
  472.         if (!pGlobal)
  473.         {
  474.             PostMessage(hwnd, WM_CLOSE, 0, 0L);
  475.             break;
  476.         }
  477.         pGlobal->dwSize = sizeof (GLOBALENTRY);
  478.         if (!GlobalEntryHandle(pGlobal, GetWindowWord(hwnd, MEM_BLOCK)))
  479.         {
  480.             MessageBox(hwnd, "Block Handle is invalid", "Browser", IDOK);
  481.             PostMessage(hwnd, WM_CLOSE, 0, 0L);
  482.             break;
  483.         }
  484.  
  485.         /* Save GLOBALENTRY pointer as window WORD 2 */
  486.         SetWindowWord(hwnd, MEM_GLOBALENTRY, (WORD)pGlobal);
  487.  
  488.         /* Now read the memory into our global block */
  489.         w = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, pGlobal->dwBlockSize);
  490.         if (!w)
  491.         {
  492.             MessageBox(hwnd, "Not enough memory to copy block",
  493.                 "Browser", IDOK);
  494.             PostMessage(hwnd, WM_CLOSE, 0, 0L);
  495.             return 0L;
  496.         }
  497.         lpBlock = GlobalLock(w);
  498.         SetWindowWord(hwnd, MEM_HOURBLOCK, w);
  499.         SetWindowLong(hwnd, MEM_LPOURBLOCK, (LONG)lpBlock);
  500.         MemoryRead(GetWindowWord(hwnd, MEM_BLOCK), 0L, lpBlock,
  501.             pGlobal->dwBlockSize);
  502.  
  503.         /* Put a new item on the system menu to rewrite the block */
  504.         hMenu = GetSystemMenu(hwnd, 0);
  505.         AppendMenu(hMenu, MF_STRING, IDM_WRITE, "&Write");
  506.         AppendMenu(hMenu, MF_STRING, IDM_WRITEBP, "Write &BP");
  507.  
  508.         break;
  509.  
  510.     case WM_SIZE:
  511.     {
  512.         SHORT nScrollMax;
  513.  
  514.         /* Compute the scroll bar maximum and position */
  515.         pGlobal = (GLOBALENTRY *)GetWindowWord(hwnd, MEM_GLOBALENTRY);
  516.         nScrollMax = MAXLINES(pGlobal->dwBlockSize, HIWORD(lParam));
  517.         SetScrollRange(hwnd, SB_VERT, 0, nScrollMax, FALSE);
  518.         SetScrollPos(hwnd, SB_VERT, min(GetScrollPos(hwnd, SB_VERT),
  519.             nScrollMax), FALSE);
  520.  
  521.         /* Force the whole thing to repaint */
  522.         InvalidateRect(hwnd, NULL, TRUE);
  523.         break;
  524.     }
  525.  
  526.     case WM_VSCROLL:
  527.     {
  528.         SHORT nScrollInc;
  529.         SHORT nScrollPos;
  530.         SHORT nScrollMin;
  531.         SHORT nScrollMax;
  532.  
  533.         /* Get the current position */
  534.         nScrollPos = GetScrollPos(hwnd, SB_VERT);
  535.         GetScrollRange(hwnd, SB_VERT, &nScrollMin, &nScrollMax);
  536.         GetClientRect(hwnd, &rect);
  537.  
  538.         /* Decode the various forms of scrolling */
  539.         switch (wParam)
  540.         {
  541.         case SB_TOP:
  542.             nScrollInc = -nScrollPos;
  543.             break;
  544.  
  545.         case SB_BOTTOM:
  546.             nScrollInc = nScrollMax - nScrollPos;
  547.             break;
  548.  
  549.         case SB_LINEUP:
  550.             nScrollInc = -1;
  551.             break;
  552.  
  553.         case SB_LINEDOWN:
  554.             nScrollInc = 1;
  555.             break;
  556.  
  557.         case SB_PAGEUP:
  558.             nScrollInc = min(-1, -rect.bottom / yChar);
  559.             break;
  560.  
  561.         case SB_PAGEDOWN:
  562.             nScrollInc = max(1, rect.bottom / yChar);
  563.             break;
  564.  
  565.         case SB_THUMBTRACK:
  566.             nScrollInc = LOWORD(lParam) - nScrollPos;
  567.             break;
  568.  
  569.         default:
  570.             nScrollInc = 0;
  571.             break;
  572.         }
  573.  
  574.         /* Now do the scroll */
  575.         if (nScrollInc = max(-nScrollPos,
  576.             min(nScrollInc, nScrollMax - nScrollPos)))
  577.         {
  578.             ScrollWindow(hwnd, 0, -yChar * nScrollInc, NULL, NULL);
  579.             SetScrollPos(hwnd, SB_VERT, nScrollPos + nScrollInc, TRUE);
  580.             UpdateWindow(hwnd);
  581.         }
  582.         break;
  583.     }
  584.  
  585.     case WM_PAINT:
  586.     {
  587.         PAINTSTRUCT ps;
  588.         SHORT nScrollMin;
  589.         SHORT nScrollMax;
  590.         SHORT nScrollPos;
  591.         SHORT nStart;
  592.         SHORT nEnd;
  593.         HFONT hFont;
  594.         HFONT hOldFont;
  595.  
  596.         BeginPaint(hwnd, &ps);
  597.  
  598.         /* Compute the number of lines to paint */
  599.         pGlobal = (GLOBALENTRY *)GetWindowWord(hwnd, MEM_GLOBALENTRY);
  600.         nScrollPos = GetScrollPos(hwnd, SB_VERT);
  601.         GetScrollRange(hwnd, SB_VERT, &nScrollMin, &nScrollMax);
  602.         nStart = max(0, nScrollPos + ps.rcPaint.top / yChar - 1);
  603.         nEnd = min((SHORT)(pGlobal->dwBlockSize / 16) + 1,
  604.             nScrollPos + ps.rcPaint.bottom / yChar + 1);
  605.  
  606.         /* Get a font to use */
  607.            hFont = GetStockObject(SYSTEM_FIXED_FONT);
  608.         hOldFont = SelectObject(ps.hdc, hFont);
  609.  
  610.         /* Loop through and draw all lines */
  611.         for (; nStart < nEnd ; ++nStart)
  612.             DumpMem(hwnd, ps.hdc, nScrollPos, nStart);
  613.  
  614.         /* Delete the font that is no longer needed */
  615.         DeleteObject(SelectObject(ps.hdc, hOldFont));
  616.  
  617.         EndPaint(hwnd, &ps);
  618.         break;
  619.     }
  620.  
  621.     case WM_DESTROY:
  622.         /* Free memory associated with this window */
  623.         LocalFree(GetWindowWord(hwnd, MEM_GLOBALENTRY));
  624.         w = GetWindowWord(hwnd, MEM_HOURBLOCK);
  625.         GlobalUnlock(w);
  626.         GlobalFree(w);
  627.         return 0L;
  628.  
  629.     case WM_COMMAND:
  630.         switch (wParam)
  631.         {
  632.         case 1:     /* Close button */
  633.             SendMessage(hwnd, WM_CLOSE, 0, 0L);
  634.             return 0L;
  635.  
  636.         case 2:     /* Write button */
  637.             return 0L;
  638.  
  639.         default:
  640.             return DefWindowProc(hwnd, wMessage, wParam, lParam);
  641.         }
  642.  
  643.     case WM_SYSCOMMAND:
  644.         if (wParam == IDM_WRITE)
  645.         {
  646.             /* Write the block */
  647.             pGlobal = (GLOBALENTRY *)GetWindowWord(hwnd, MEM_GLOBALENTRY);
  648.             lpBlock = (LPSTR)GetWindowLong(hwnd, MEM_LPOURBLOCK);
  649.             dwReturn = MemoryWrite(GetWindowWord(hwnd, MEM_BLOCK),
  650.                 0L, lpBlock, pGlobal->dwBlockSize);
  651.             wsprintf(szText, "%lXh bytes written", dwReturn);
  652.             MessageBox(hwnd, szText, "Memory Browser Write", MB_OK);
  653.             InvalidateRect(hwnd, NULL, TRUE);
  654.             break;
  655.         }
  656.         else if (wParam == IDM_WRITEBP)
  657.         {
  658.             /* Write the breakpoint only if it's code */
  659.             pGlobal = (GLOBALENTRY *)GetWindowWord(hwnd, MEM_GLOBALENTRY);
  660.             if (pGlobal->wType != GT_CODE)
  661.             {
  662.                 MessageBox(hwnd, "Breakpoints only go in code segments",
  663.                     "Memory Browser Breakpoint", MB_OK);
  664.                 return 0L;
  665.             }
  666.             lpBlock = (LPSTR)GetWindowLong(hwnd, MEM_LPOURBLOCK);
  667.         *lpBlock =(WORD) 0xcc;
  668.             dwReturn = MemoryWrite(GetWindowWord(hwnd, MEM_BLOCK),
  669.                 0L, lpBlock, 1);
  670.             wsprintf(szText, "%lXh bytes written", dwReturn);
  671.             MessageBox(hwnd, szText, "Memory Browser Write", MB_OK);
  672.             InvalidateRect(hwnd, NULL, TRUE);
  673.             break;
  674.         }
  675.         else
  676.             return DefWindowProc(hwnd, wMessage, wParam, lParam);
  677.  
  678.     default:
  679.         return DefWindowProc(hwnd, wMessage, wParam, lParam);
  680.     }
  681.  
  682.     return 0L;
  683. }
  684.  
  685.  
  686. /*  DumpMem
  687.  *      Dumps memory to the memory window.  This routine is called once
  688.  *      per memory line to dump in the middle of the paint message.
  689.  */
  690.  
  691. void PASCAL DumpMem(HWND hwnd, HDC hDC, SHORT nScrollPos, SHORT nPos)
  692. {
  693.     LPSTR lpMem;
  694.     DWORD dwOffset;
  695.     WORD i;
  696.     PSTR pstr;
  697.     BYTE by;
  698.     BYTE byCount;
  699.     BYTE byBadCount;
  700.     GLOBALENTRY *pGlobal;
  701.  
  702.     /* Get a pointer to the memory */
  703.     dwOffset = ((DWORD)(WORD)nPos) << 4;
  704.     lpMem = (LPSTR)MAKELONG(LOWORD(dwOffset),
  705.         GetWindowWord(hwnd, MEM_LPOURBLOCK + 2) +
  706.         HIWORD(dwOffset) * (WORD)&_AHINCR);
  707.  
  708.     /* How many real characters are there to draw? */
  709.     pGlobal = (GLOBALENTRY *)GetWindowWord(hwnd, MEM_GLOBALENTRY);
  710.     if (pGlobal->dwBlockSize < dwOffset + 16)
  711.     {
  712.         if (pGlobal->dwBlockSize < dwOffset)
  713.         {
  714.             byCount = 0;
  715.             byBadCount = 16;
  716.         }
  717.         else
  718.         {
  719.         byCount = (BYTE)(pGlobal->dwBlockSize - dwOffset);
  720.         byBadCount = (BYTE)(16 - byCount);
  721.         }
  722.     }
  723.     else
  724.     {
  725.         byCount = 16;
  726.         byBadCount = 0;
  727.     }
  728.  
  729.     /* Put into a string so we can see it */
  730.     pstr = szText;
  731.     pstr += wsprintf(pstr, "%06lX:", dwOffset);
  732.     for (i = 0 ; i < (WORD)byCount ; ++i)
  733.         pstr += wsprintf(pstr, "%02X ",
  734.             (WORD)*(unsigned char FAR *)(lpMem + i));
  735.     for (i = 0 ; i < (WORD)byBadCount ; ++i)
  736.         pstr += wsprintf(pstr, "?? ");
  737.     for (i = 0 ; i < (WORD)byCount ; ++i)
  738.     {
  739.         by = *(lpMem + i);
  740.         pstr += wsprintf(pstr, "%c", by >= ' ' ? by : '.');
  741.     }
  742.     for (i = 0 ; i < (WORD)byBadCount ; ++i)
  743.         pstr += wsprintf(pstr, "?");
  744.  
  745.     /* Draw the text */
  746.     TextOut(hDC, xChar, yChar * (nPos - nScrollPos), szText,
  747.         strlen(szText));
  748. }
  749.  
  750.  
  751. /*  WalkGlobalHeap
  752.  *      Walks the global heap in the list box.  Returns the WndProc return
  753.  *      value.
  754.  */
  755.  
  756. LONG WalkGlobalHeap(HWND hwnd)
  757. {
  758.     GLOBALINFO GlobalInf;
  759.     GLOBALENTRY Global;
  760.     MODULEENTRY Module;
  761.     TASKENTRY Task;
  762.     char *npText;
  763.     char *npstr;
  764.     int i;
  765.     HCURSOR hCursor;
  766.  
  767.     /* Turn on the hourglass */
  768.     hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  769.     ShowCursor(TRUE);
  770.     wListStatus = LIST_GLOBAL;
  771.  
  772.     /* Allocate a buffer to store this stuff in.  Pad this number
  773.      *  because the LocalAlloc corrupts the walk.
  774.      */
  775.     GlobalInf.dwSize = sizeof (GLOBALINFO);
  776.     GlobalInfo(&GlobalInf);
  777.     npText = npstr = (char *)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
  778.         (GlobalInf.wcItems + 10) * (LIST_WIDTH + 1));
  779.     if (!npText)
  780.         return 0L;
  781.  
  782.     /* Loop through the global heap */
  783.     Global.dwSize = sizeof (GLOBALENTRY);
  784.     Module.dwSize = sizeof (MODULEENTRY);
  785.     Task.dwSize = sizeof (TASKENTRY);
  786.     if (GlobalFirst(&Global, GLOBAL_ALL))
  787.     {
  788.         char temp[30];
  789.  
  790.         i = 0;
  791.         do
  792.         {
  793.             /* Get the module name */
  794.             if (!Global.hOwner)
  795.                 lstrcpy(Module.szModule, "FREE");
  796.             else if (!ModuleFindHandle(&Module, Global.hOwner))
  797.             {
  798.                 if (TaskFindHandle(&Task, Global.hOwner))
  799.                     lstrcpy(Module.szModule, Task.szModule);
  800.                 else
  801.                     *Module.szModule = '\0';
  802.             }
  803.  
  804.             /* Put some fun garbage in the text buffer */
  805.             if (bHasData[Global.wType])
  806.                 sprintf(temp, "%s %d",
  807.                     szBlockTypes[Global.wType], Global.wData);
  808.             else
  809.                 lstrcpy(temp,szBlockTypes[Global.wType]);
  810.             sprintf(npstr,
  811.                 "A=%08lX h=%04X S=%08lX O=%04X pglk=%d %c %-8s %s",
  812.                 Global.dwAddress, Global.hBlock, Global.dwBlockSize,
  813.                 Global.hOwner, Global.wcPageLock,
  814.                 Global.wHeapPresent ? 'Y' : 'N',
  815.                 Module.szModule,
  816.                 temp);
  817.  
  818.             /* Bump to the next spot */
  819.             npstr += LIST_WIDTH + 1;
  820.             ++i;
  821.         }
  822.         while (GlobalNext(&Global, GLOBAL_ALL));
  823.     }
  824.  
  825.     /* Create number of items string */
  826.     sprintf(szText, "GLOBAL_ALL:  Items = %u Really = %u",
  827.         GlobalInf.wcItems, i);
  828.  
  829.     /* Clear list box */
  830.     SendMessage(hwndList, WM_SETREDRAW, FALSE, 0L);
  831.     SendMessage(hwndList, LB_RESETCONTENT, 0, 0L);
  832.  
  833.     /* Loop through all blocks, putting them in list box */
  834.     for (i = 0, npstr = npText ; i < (int)GlobalInf.wcItems ;
  835.         ++i, npstr += LIST_WIDTH + 1)
  836.         if (*npstr)
  837.             SendMessage(hwndList, LB_ADDSTRING, 0,
  838.                 (LONG)(LPSTR)npstr);
  839.     LocalFree((HANDLE)npText);
  840.  
  841.     /* OK to redraw list box now.  Also draw its title */
  842.     SendMessage(hwndList, WM_SETREDRAW, TRUE, 0L);
  843.     InvalidateRect(hwndList, NULL, TRUE);
  844.     SetWindowText(hwndListStatic, szText);
  845.     InvalidateRect(hwndListStatic, NULL, TRUE);
  846.  
  847.     /* Done with hourglass */
  848.     ShowCursor(FALSE);
  849.     SetCursor(hCursor);
  850.  
  851.     return 0L;
  852. }
  853.  
  854.  
  855. /*  WalkFreeList
  856.  *      Walks the free list, putting the result in a list box.
  857.  */
  858.  
  859. LONG WalkFreeList(HWND hwnd)
  860. {
  861.     GLOBALINFO GlobalInf;
  862.     GLOBALENTRY Global;
  863.     MODULEENTRY Module;
  864.     char *npText;
  865.     char *npstr;
  866.     int i;
  867.     HCURSOR hCursor;
  868.  
  869.     /* Turn on the hourglass */
  870.     hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  871.     ShowCursor(TRUE);
  872.     wListStatus = LIST_GLOBAL;
  873.  
  874.     /* Allocate a buffer to store this stuff in */
  875.     GlobalInf.dwSize = sizeof (GLOBALINFO);
  876.     GlobalInfo(&GlobalInf);
  877.     npText = npstr = (char *)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
  878.         (GlobalInf.wcItemsFree + 10) * (LIST_WIDTH + 1));
  879.     if (!npText)
  880.         return 0L;
  881.  
  882.     /* Loop through the global heap */
  883.     Global.dwSize = sizeof (GLOBALENTRY);
  884.     if (GlobalFirst(&Global, GLOBAL_FREE))
  885.     {
  886.         i = 0;
  887.         do
  888.         {
  889.             /* Get the module name */
  890.             Module.dwSize = sizeof (MODULEENTRY);
  891.             if (!Global.hOwner)
  892.                 lstrcpy(Module.szModule, "FREE");
  893.             else if (!ModuleFindHandle(&Module, Global.hOwner))
  894.                 *Module.szModule = '\0';
  895.  
  896.             /* Put some fun garbage in the text buffer */
  897.             sprintf(npstr, "A=%08lX h=%04X S=%08lX O=%04X f=%02X T=%2d %c %s",
  898.                 Global.dwAddress, Global.hBlock, Global.dwBlockSize,
  899.                 Global.hOwner, Global.wFlags, Global.wType,
  900.                 Global.wHeapPresent ? 'Y' : 'N', Module.szModule);
  901.  
  902.             /* Bump to the next spot */
  903.             npstr += LIST_WIDTH + 1;
  904.             ++i;
  905.         }
  906.         while (GlobalNext(&Global, GLOBAL_FREE));
  907.     }
  908.  
  909.     /* Create number of items string */
  910.     sprintf(szText, "GLOBAL_FREE:  Items = %u Really = %u",
  911.         GlobalInf.wcItemsFree, i);
  912.  
  913.     /* Clear list box */
  914.     SendMessage(hwndList, WM_SETREDRAW, FALSE, 0L);
  915.     SendMessage(hwndList, LB_RESETCONTENT, 0, 0L);
  916.  
  917.     /* Loop through all blocks, putting them in list box */
  918.     for (i = 0, npstr = npText ; i < (int)GlobalInf.wcItemsFree ;
  919.         ++i, npstr += LIST_WIDTH + 1)
  920.         if (*npstr)
  921.             SendMessage(hwndList, LB_ADDSTRING, 0,
  922.                 (LONG)(LPSTR)npstr);
  923.     LocalFree((HANDLE)npText);
  924.  
  925.     /* OK to redraw list box now.  Also draw its title */
  926.     SendMessage(hwndList, WM_SETREDRAW, TRUE, 0L);
  927.     InvalidateRect(hwndList, NULL, TRUE);
  928.     SetWindowText(hwndListStatic, szText);
  929.     InvalidateRect(hwndListStatic, NULL, TRUE);
  930.  
  931.     /* Done with hourglass */
  932.     ShowCursor(FALSE);
  933.     SetCursor(hCursor);
  934.  
  935.     return 0L;
  936. }
  937.  
  938.  
  939. /*  WalkLRUList
  940.  *      Walks the LRU list, putting the result in a list box.
  941.  */
  942.  
  943. LONG WalkLRUList(HWND hwnd)
  944. {
  945.     GLOBALINFO GlobalInf;
  946.     GLOBALENTRY Global;
  947.     MODULEENTRY Module;
  948.     char *npText;
  949.     char *npstr;
  950.     int i;
  951.     HCURSOR hCursor;
  952.  
  953.     /* Turn on the hourglass */
  954.     hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  955.     ShowCursor(TRUE);
  956.     wListStatus = LIST_GLOBAL;
  957.  
  958.     /* Allocate a buffer to store this stuff in */
  959.     GlobalInf.dwSize = sizeof (GLOBALINFO);
  960.     GlobalInfo(&GlobalInf);
  961.     npText = npstr = (char *)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
  962.         (GlobalInf.wcItemsLRU + 10) * (LIST_WIDTH + 1));
  963.     if (!npText)
  964.         return 0L;
  965.  
  966.     /* Loop through the global heap */
  967.     Global.dwSize = sizeof (GLOBALENTRY);
  968.     if (GlobalFirst(&Global, GLOBAL_LRU))
  969.     {
  970.         i = 0;
  971.         do
  972.         {
  973.             /* Get the module name */
  974.             Module.dwSize = sizeof (MODULEENTRY);
  975.             if (!Global.hOwner)
  976.                 lstrcpy(Module.szModule, "FREE");
  977.             else if (!ModuleFindHandle(&Module, Global.hOwner))
  978.                 *Module.szModule = '\0';
  979.  
  980.             /* Put some fun garbage in the text buffer */
  981.             sprintf(npstr, "A=%08lX h=%04X S=%08lX O=%04X f=%02X T=%2d %c %s",
  982.                 Global.dwAddress, Global.hBlock, Global.dwBlockSize,
  983.                 Global.hOwner, Global.wFlags, Global.wType,
  984.                 Global.wHeapPresent ? 'Y' : 'N', Module.szModule);
  985.  
  986.             /* Bump to the next spot */
  987.             npstr += LIST_WIDTH + 1;
  988.             ++i;
  989.         }
  990.         while (GlobalNext(&Global, GLOBAL_LRU));
  991.     }
  992.  
  993.     /* Create number of items string */
  994.     sprintf(szText, "GLOBAL_LRU:  Items = %u Really = %u",
  995.         GlobalInf.wcItemsLRU, i);
  996.  
  997.     /* Clear list box */
  998.     SendMessage(hwndList, WM_SETREDRAW, FALSE, 0L);
  999.     SendMessage(hwndList, LB_RESETCONTENT, 0, 0L);
  1000.  
  1001.     /* Loop through all blocks, putting them in list box */
  1002.     for (i = 0, npstr = npText ; i < (int)GlobalInf.wcItemsLRU ;
  1003.         ++i, npstr += LIST_WIDTH + 1)
  1004.         if (*npstr)
  1005.             SendMessage(hwndList, LB_ADDSTRING, 0,
  1006.                 (LONG)(LPSTR)npstr);
  1007.     LocalFree((HANDLE)npText);
  1008.  
  1009.     /* OK to redraw list box now.  Also draw its title */
  1010.     SendMessage(hwndList, WM_SETREDRAW, TRUE, 0L);
  1011.     InvalidateRect(hwndList, NULL, TRUE);
  1012.     SetWindowText(hwndListStatic, szText);
  1013.     InvalidateRect(hwndListStatic, NULL, TRUE);
  1014.  
  1015.     /* Done with hourglass */
  1016.     ShowCursor(FALSE);
  1017.     SetCursor(hCursor);
  1018.  
  1019.     return 0L;
  1020. }
  1021.  
  1022.  
  1023. /*  WalkLocalHeap
  1024.  *      Walks the local heap into the second list box
  1025.  */
  1026.  
  1027. LONG WalkLocalHeap(HWND hwnd, HANDLE hBlock)
  1028. {
  1029.     LOCALENTRY Local;
  1030.     LOCALINFO LocalInf;
  1031.     char *npText;
  1032.     char *npstr;
  1033.     HCURSOR hCursor;
  1034.     WORD i;
  1035.  
  1036.     /* Turn on the hourglass */
  1037.     hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1038.     ShowCursor(TRUE);
  1039.  
  1040.     /* Allocate a buffer to do the local heapwalk */
  1041.     LocalInf.dwSize = sizeof (LOCALINFO);
  1042.     LocalInfo(&LocalInf, hBlock);
  1043.     npText = npstr = (char *)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
  1044.         LocalInf.wcItems * (LIST_WIDTH + 1));
  1045.     if (!npText)
  1046.         return 0L;
  1047.  
  1048.     /* Loop through the local heap */
  1049.     Local.dwSize = sizeof (LOCALENTRY);
  1050.     if (LocalFirst(&Local, hBlock))
  1051.     {
  1052.         char temp[30];
  1053.  
  1054.         do
  1055.         {
  1056.             /* Get the type string */
  1057.             if (Local.wFlags & LF_FREE)
  1058.                 strcpy(temp, "Free");
  1059.             else if (Local.wHeapType == GDI_HEAP &&
  1060.                 Local.wType <= LT_GDI_MAX)
  1061.                 strcpy(temp, szGDI[Local.wType]);
  1062.             else if (Local.wHeapType == USER_HEAP &&
  1063.                 Local.wType <= LT_USER_MAX)
  1064.                 strcpy(temp, szUser[Local.wType]);
  1065.             else
  1066.                 strcpy(temp, "Unknown");
  1067.  
  1068.             /* Put some fun garbage in the text buffer */
  1069.             sprintf(npstr, "Ad=%04X h=%04X Sz=%04X %-8s L=%02X %s",
  1070.                 Local.wAddress, Local.hHandle, Local.wSize,
  1071.                 szLocalFlags[Local.wFlags & 7], Local.wcLock, temp);
  1072.  
  1073.             /* Bump to the next spot */
  1074.             npstr += LIST_WIDTH + 1;
  1075.         }
  1076.         while (LocalNext(&Local));
  1077.     }
  1078.  
  1079.     /* Clear list box */
  1080.     SendMessage(hwndListLocal, WM_SETREDRAW, FALSE, 0L);
  1081.     SendMessage(hwndListLocal, LB_RESETCONTENT, 0, 0L);
  1082.  
  1083.     /* Loop through all blocks, putting them in list box */
  1084.     for (i = 0, npstr = npText ; i < LocalInf.wcItems ;
  1085.         ++i, npstr += LIST_WIDTH + 1)
  1086.         if (*npstr)
  1087.             SendMessage(hwndListLocal, LB_ADDSTRING, 0,
  1088.                 (LONG)(LPSTR)npstr);
  1089.     LocalFree((HANDLE)npText);
  1090.  
  1091.     /* OK to redraw list box now */
  1092.     SendMessage(hwndListLocal, WM_SETREDRAW, TRUE, 0L);
  1093.     InvalidateRect(hwndListLocal, NULL, TRUE);
  1094.  
  1095.     /* Done with hourglass */
  1096.     ShowCursor(FALSE);
  1097.     SetCursor(hCursor);
  1098.  
  1099.     return 0L;
  1100. }
  1101.  
  1102.  
  1103.  
  1104. /*  WalkModuleList
  1105.  *      Walks the module list into the list box
  1106.  */
  1107.  
  1108. LONG WalkModuleList(HWND hwnd)
  1109. {
  1110.     MODULEENTRY Module;
  1111.     HCURSOR hCursor;
  1112.  
  1113.     /* Turn on the hourglass */
  1114.     hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1115.     ShowCursor(TRUE);
  1116.     wListStatus = LIST_MODULE;
  1117.  
  1118.     /* Clear list box */
  1119.     SendMessage(hwndList, WM_SETREDRAW, FALSE, 0L);
  1120.     SendMessage(hwndList, LB_RESETCONTENT, 0, 0L);
  1121.  
  1122.     /* Loop through the module list */
  1123.     Module.dwSize = sizeof (MODULEENTRY);
  1124.     if (ModuleFirst(&Module))
  1125.         do
  1126.         {
  1127.             /* Put some fun garbage in the text buffer */
  1128.             sprintf(szText, "Mod=%s Path=%s",
  1129.                 Module.szModule, Module.szExePath);
  1130.  
  1131.             /* Put the string in the list box */
  1132.             SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1133.         }
  1134.         while (ModuleNext(&Module));
  1135.  
  1136.     /* OK to redraw list box now.  Also draw its title */
  1137.     SendMessage(hwndList, WM_SETREDRAW, TRUE, 0L);
  1138.     InvalidateRect(hwndList, NULL, TRUE);
  1139.     SetWindowText(hwndListStatic, "Module List");
  1140.     InvalidateRect(hwndListStatic, NULL, TRUE);
  1141.  
  1142.     /* Done with hourglass */
  1143.     ShowCursor(FALSE);
  1144.     SetCursor(hCursor);
  1145.  
  1146.     return 0L;
  1147. }
  1148.  
  1149.  
  1150.  
  1151. /*  WalkTaskList
  1152.  *      Walks the module list into the list box
  1153.  */
  1154.  
  1155. LONG WalkTaskList(HWND hwnd)
  1156. {
  1157.     TASKENTRY Task;
  1158.     HCURSOR hCursor;
  1159.  
  1160.     /* Turn on the hourglass */
  1161.     hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1162.     ShowCursor(TRUE);
  1163.     wListStatus = LIST_TASK;
  1164.  
  1165.     /* Clear list box */
  1166.     SendMessage(hwndList, WM_SETREDRAW, FALSE, 0L);
  1167.     SendMessage(hwndList, LB_RESETCONTENT, 0, 0L);
  1168.  
  1169.     /* Loop through the task list */
  1170.     Task.dwSize = sizeof (TASKENTRY);
  1171.     if (TaskFirst(&Task))
  1172.         do
  1173.         {
  1174.             /* Put some fun garbage in the text buffer */
  1175.             sprintf(szText,
  1176.                 "hTask=%04X Par=%04X hInst=%04X Mod=%04X szMod=%s",
  1177.                 Task.hTask, Task.hTaskParent, Task.hInst, Task.hModule,
  1178.                 Task.szModule);
  1179.  
  1180.             /* Put the string in the list box */
  1181.             SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1182.         }
  1183.         while (TaskNext(&Task));
  1184.  
  1185.     /* OK to redraw list box now.  Also draw its title */
  1186.     SendMessage(hwndList, WM_SETREDRAW, TRUE, 0L);
  1187.     InvalidateRect(hwndList, NULL, TRUE);
  1188.     SetWindowText(hwndListStatic, "Task List");
  1189.     InvalidateRect(hwndListStatic, NULL, TRUE);
  1190.  
  1191.     /* Done with hourglass */
  1192.     ShowCursor(FALSE);
  1193.     SetCursor(hCursor);
  1194.  
  1195.     return 0L;
  1196. }
  1197.  
  1198.  
  1199.  
  1200. /*  WalkClassList
  1201.  *      Walks the module list into the list box
  1202.  */
  1203.  
  1204. LONG WalkClassList(HWND hwnd)
  1205. {
  1206.     CLASSENTRY Class;
  1207.     HCURSOR hCursor;
  1208.  
  1209.     /* Turn on the hourglass */
  1210.     hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1211.     ShowCursor(TRUE);
  1212.     wListStatus = LIST_CLASS;
  1213.  
  1214.     /* Clear list box */
  1215.     SendMessage(hwndList, WM_SETREDRAW, FALSE, 0L);
  1216.     SendMessage(hwndList, LB_RESETCONTENT, 0, 0L);
  1217.  
  1218.     /* Loop through the class list */
  1219.     Class.dwSize = sizeof (CLASSENTRY);
  1220.     if (ClassFirst(&Class))
  1221.         do
  1222.         {
  1223.             /* Put some fun garbage in the text buffer */
  1224.             sprintf(szText, "Name = %s  hInst = %04X",
  1225.                 Class.szClassName, Class.hInst);
  1226.  
  1227.             /* Put the string in the list box */
  1228.             SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1229.         }
  1230.         while (ClassNext(&Class));
  1231.  
  1232.     /* OK to redraw list box now.  Also draw its title */
  1233.     SendMessage(hwndList, WM_SETREDRAW, TRUE, 0L);
  1234.     InvalidateRect(hwndList, NULL, TRUE);
  1235.     SetWindowText(hwndListStatic, "Class List");
  1236.     InvalidateRect(hwndListStatic, NULL, TRUE);
  1237.  
  1238.     /* Done with hourglass */
  1239.     ShowCursor(FALSE);
  1240.     SetCursor(hCursor);
  1241.  
  1242.     return 0L;
  1243. }
  1244.  
  1245.  
  1246.  
  1247. /*  DoStackTrace
  1248.  *      Does a stack trace for the current module in the lower box
  1249.  */
  1250.  
  1251. LONG DoStackTrace(HWND hwnd)
  1252. {
  1253.     STACKTRACEENTRY StackTrace;
  1254.     MODULEENTRY ModuleEntry;
  1255.     HCURSOR hCursor;
  1256.     HANDLE hTask;
  1257.     WORD wCS;
  1258.     HANDLE hModule;
  1259.  
  1260.     /* Turn on the hourglass */
  1261.     hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1262.     ShowCursor(TRUE);
  1263.  
  1264.     /* Get the task handle from the list box */
  1265.     SendMessage(hwndList, LB_GETTEXT,
  1266.         (WORD)SendMessage(hwndList, LB_GETCURSEL, 0, 0L),
  1267.         (LONG)(LPSTR)szText);
  1268.     sscanf(szText, "%*6c%x", &hTask);
  1269.  
  1270.     /* Clear list box */
  1271.     SendMessage(hwndListLocal, WM_SETREDRAW, FALSE, 0L);
  1272.     SendMessage(hwndListLocal, LB_RESETCONTENT, 0, 0L);
  1273.  
  1274.     /* Do the stack trace */
  1275.     StackTrace.dwSize = sizeof (STACKTRACEENTRY);
  1276.     wCS = 0;
  1277.     hModule = NULL;
  1278.     if (StackTraceFirst(&StackTrace, hTask))
  1279.         do
  1280.         {
  1281.             /* Get the module name */
  1282.             ModuleEntry.dwSize = sizeof (MODULEENTRY);
  1283.             if (!ModuleFindHandle(&ModuleEntry, StackTrace.hModule))
  1284.                 ModuleEntry.szModule[0] = '\0';
  1285.  
  1286.             /* Put some fun garbage in the text buffer */
  1287.             sprintf(szText, "BP=%04X CS:IP=%04X:%04X (Mod=%s Seg=%u)",
  1288.                 StackTrace.wBP, StackTrace.wCS, StackTrace.wIP,
  1289.                 ModuleEntry.szModule, StackTrace.wSegment);
  1290.  
  1291.             /* Set the last wCS in case we're using a near frame */
  1292.             if (StackTrace.wCS)
  1293.             {
  1294.                 wCS = StackTrace.wCS;
  1295.                 hModule = StackTrace.hModule;
  1296.             }
  1297.  
  1298.             /* Put the string in the list box */
  1299.             SendMessage(hwndListLocal, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1300.         }
  1301.         while (StackTraceNext(&StackTrace));
  1302.  
  1303.     /* OK to redraw list box now */
  1304.     SendMessage(hwndListLocal, WM_SETREDRAW, TRUE, 0L);
  1305.     InvalidateRect(hwndListLocal, NULL, TRUE);
  1306.  
  1307.     /* Done with hourglass */
  1308.     ShowCursor(FALSE);
  1309.     SetCursor(hCursor);
  1310.  
  1311.     return 0L;
  1312. }
  1313.  
  1314.  
  1315. /*  DoHeapInfo
  1316.  *      Displays the data from a call to SystemHeapInfo()
  1317.  */
  1318.  
  1319. LONG DoHeapInfo(HWND hwnd)
  1320. {
  1321.     SYSHEAPINFO SysHeap;
  1322.  
  1323.     wListStatus = LIST_HEAP;
  1324.  
  1325.     /* Clear list box */
  1326.     SendMessage(hwndList, WM_SETREDRAW, FALSE, 0L);
  1327.     SendMessage(hwndList, LB_RESETCONTENT, 0, 0L);
  1328.  
  1329.     /* Get the user information */
  1330.     SysHeap.dwSize = sizeof (SYSHEAPINFO);
  1331.     SystemHeapInfo(&SysHeap);
  1332.  
  1333.     /* Display the User information */
  1334.     wsprintf(szText, "hUserSegment = %04X", SysHeap.hUserSegment);
  1335.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1336.     wsprintf(szText, "hGDISegment = %04X", SysHeap.hGDISegment);
  1337.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1338.     wsprintf(szText, "Free User Resources = %u%%", SysHeap.wUserFreePercent);
  1339.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1340.     wsprintf(szText, "Free GDI Resources = %u%%", SysHeap.wGDIFreePercent);
  1341.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1342.  
  1343.     /* OK to redraw list box now.  Also draw its title */
  1344.     SendMessage(hwndList, WM_SETREDRAW, TRUE, 0L);
  1345.     InvalidateRect(hwndList, NULL, TRUE);
  1346.     SetWindowText(hwndListStatic, "System Heap Information");
  1347.     InvalidateRect(hwndListStatic, NULL, TRUE);
  1348.  
  1349.     return 0L;
  1350. }
  1351.  
  1352.  
  1353. /*  DoMemManInfo
  1354.  *      Displays the data from a call to UserInfo()
  1355.  */
  1356.  
  1357. LONG DoMemManInfo(HWND hwnd)
  1358. {
  1359.     MEMMANINFO MemMan;
  1360.  
  1361.     wListStatus = LIST_MEMMAN;
  1362.  
  1363.     /* Clear list box */
  1364.     SendMessage(hwndList, WM_SETREDRAW, FALSE, 0L);
  1365.     SendMessage(hwndList, LB_RESETCONTENT, 0, 0L);
  1366.  
  1367.     /* Get the Memory manager information */
  1368.     MemMan.dwSize = sizeof (MEMMANINFO);
  1369.     MemManInfo(&MemMan);
  1370.  
  1371.     /* Display the MemMan information */
  1372.     wsprintf(szText, "Largest Free Block = %08lXh", MemMan.dwLargestFreeBlock);
  1373.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1374.     wsprintf(szText, "Max Pages Available = %08lXh", MemMan.dwMaxPagesAvailable);
  1375.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1376.     wsprintf(szText, "Max Pages Lockable = %08lXh", MemMan.dwMaxPagesLockable);
  1377.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1378.     wsprintf(szText, "Total Linear Space = %08lXh", MemMan.dwTotalLinearSpace);
  1379.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1380.     wsprintf(szText, "Total Unlocked Pages = %08lXh", MemMan.dwTotalUnlockedPages);
  1381.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1382.     wsprintf(szText, "Free Pages = %08lXh", MemMan.dwFreePages);
  1383.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1384.     wsprintf(szText, "Total Pages = %08lXh", MemMan.dwTotalPages);
  1385.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1386.     wsprintf(szText, "Free Linear Space = %08lXh", MemMan.dwFreeLinearSpace);
  1387.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1388.     wsprintf(szText, "Swap File Pages = %08lXh", MemMan.dwSwapFilePages);
  1389.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1390.     wsprintf(szText, "Page Size = %04Xh", MemMan.wPageSize);
  1391.     SendMessage(hwndList, LB_ADDSTRING, 0, (LONG)(LPSTR)szText);
  1392.  
  1393.     /* OK to redraw list box now.  Also draw its title */
  1394.     SendMessage(hwndList, WM_SETREDRAW, TRUE, 0L);
  1395.     InvalidateRect(hwndList, NULL, TRUE);
  1396.     SetWindowText(hwndListStatic, "Memory Manager Information");
  1397.     InvalidateRect(hwndListStatic, NULL, TRUE);
  1398.  
  1399.     return 0L;
  1400. }
  1401.  
  1402. /*  DoGlobalEntryModuleTest
  1403.  *      Tests the GlobalEntryModule API for correctness.
  1404.  */
  1405.  
  1406. LONG DoGlobalEntryModuleTest(HWND hwnd)
  1407. {
  1408.     GLOBALENTRY Global;
  1409.     HANDLE hModule;
  1410.  
  1411.     /* Get an interesting module handle */
  1412.     hModule = GetModuleHandle("USER");
  1413.  
  1414.     /* Find out about the segment */
  1415.     Global.dwSize = sizeof (GLOBALENTRY);
  1416.     if (!GlobalEntryModule(&Global, hModule, 14))
  1417.     {
  1418.     MessageBox(hwnd, "Error returned!", "GlobalEntryModule Test",
  1419.             MB_OK | MB_ICONEXCLAMATION);
  1420.     return(0);
  1421.     }
  1422.     else
  1423.     {
  1424.         wsprintf(szText, "USER Code Seg 14 has handle %04X", Global.hBlock);
  1425.         MessageBox(hwnd, szText, "GlobalEntryModule Test",
  1426.             MB_OK | MB_ICONINFORMATION);
  1427.     return(1);
  1428.     }
  1429.  
  1430. }
  1431.  
  1432.  
  1433. /*  ReadMemoryTest
  1434.  *      Opens a popup window and allows the user to scroll through the
  1435.  *      contents of the memory block.
  1436.  */
  1437.  
  1438. LONG ReadMemoryTest(HWND hwnd, HANDLE hBlock)
  1439. {
  1440.     HWND hwndPopup;
  1441.     GLOBALENTRY Global;
  1442.  
  1443.     /* Make a popup window to handle the data */
  1444.     Global.dwSize = sizeof (GLOBALENTRY);
  1445.     GlobalEntryHandle(&Global, hBlock);
  1446.     wsprintf(szText,"Handle = %4Xh  Length = %8lXh",
  1447.         hBlock, Global.dwBlockSize);
  1448.     hwndPopup = CreateWindow(
  1449.         szMemName,
  1450.         szText,
  1451.         WS_POPUP | WS_CAPTION |
  1452.         WS_SYSMENU | WS_THICKFRAME | WS_MAXIMIZEBOX | WS_VSCROLL,
  1453.         xScreen / 2 - 45 * xChar,
  1454.         yScreen / 8,
  1455.         90 * xChar,
  1456.         2 * yScreen / 3,
  1457.         hwnd,
  1458.         NULL,
  1459.         hInst,
  1460.         (LPSTR)MAKELONG(hBlock, 0));
  1461.  
  1462.     /* Display the window */
  1463.     ShowWindow(hwndPopup, SW_SHOWNORMAL);
  1464.     UpdateWindow(hwndPopup);
  1465.  
  1466.     return 0L;
  1467. }
  1468.  
  1469.  
  1470. /*  TimerCountTest
  1471.  *      Tests the timer count function.
  1472.  */
  1473.  
  1474. LONG TimerCountTest(HWND hwnd)
  1475. {
  1476.     TIMERINFO TimerInfo;
  1477.  
  1478.     /* Get the tick count */
  1479.     TimerInfo.dwSize = sizeof (TIMERINFO);
  1480.     if (!TimerCount(&TimerInfo))
  1481.     {
  1482.         MessageBox(hwnd, "Error calling TimerCount()", "Timer Count Test",
  1483.             MB_OK);
  1484.         return 0L;
  1485.     }
  1486.  
  1487.     /* Display it */
  1488.     wsprintf(szText, "Milliseconds since Windows started = %ld\r\n"
  1489.         "Milliseconds in this VM = %ld",
  1490.         TimerInfo.dwmsSinceStart, TimerInfo.dwmsThisVM);
  1491.     MessageBox(hwnd, szText, "Timer Count Test", MB_OK | MB_ICONINFORMATION);
  1492.  
  1493.     /* Return success */
  1494.     return 0L;
  1495. }
  1496.  
  1497.  
  1498. /*  MyNotifyHandler
  1499.  *      Notification message callback
  1500.  */
  1501.  
  1502. BOOL __export CALLBACK MyNotifyHandler(WORD wID, DWORD dwData)
  1503. {
  1504.     /* See if we should process this notification */
  1505.     if (!wNotifyState)
  1506.         return FALSE;
  1507.  
  1508.     /* Filter out task switch notifications if necessary */
  1509.     if (wFilterState && (wID == NFY_TASKIN || wID == NFY_TASKOUT))
  1510.         return FALSE;
  1511.  
  1512.     /* Put the information in a message */
  1513.     PostMessage(hwndMain, WM_USER, wID, dwData);
  1514.  
  1515.     /* Only return that we handled RIPs */
  1516.     if (wID == NFY_RIP)
  1517.         return TRUE;
  1518.     else
  1519.         return FALSE;
  1520. }
  1521.  
  1522.  
  1523. /*  MyCFaultHandler
  1524.  *      This routine is used to prove that C routines can be used to
  1525.  *      make fault handlers.  As can be seen here, the parameters are
  1526.  *      actually pointing into the stack frame.  Two important notes:
  1527.  *          1) This function MUST be declared as _cdecl so that the
  1528.  *              parameters are not popped off the stack!
  1529.  *          2) This function may change these values with the understanding
  1530.  *              that they are actually passed "by value" implying that
  1531.  *              any changes are for real.
  1532.  *      As defined in MyFaultHandler (TEST2.ASM), 0 nukes app, 1 restarts
  1533.  *      the instruction, 2 chains on.
  1534.  */
  1535.  
  1536. WORD __export _cdecl MyCFaultHandler(WORD wES, WORD wDS, WORD wDI, WORD wSI, WORD wBP, WORD wSP, WORD wBX,
  1537.     WORD wDX, WORD wCX, WORD wOldAX, WORD wOldBP, WORD wRetIP, WORD wRetCS, WORD wRealAX,
  1538.     WORD wNumber, WORD wHandle, WORD wIP, WORD wCS, WORD wFlags)
  1539. {
  1540.     FARPROC lpfnDlg;
  1541.     int nResult;
  1542.     static WORD wReentry;
  1543.  
  1544.     /* See if we're already here.  If so, tell routine to chain on */
  1545.     if (wReentry)
  1546.         return 2;
  1547.     wReentry = 1;
  1548.  
  1549.     /* If this was a CtlAltSysRq interrupt, just restart the instr. */
  1550.     if (wNumber == INT_CTLALTSYSRQ)
  1551.     {
  1552.         wsprintf(szText, "THTest:  CtlAltSysRq at %04X:%04X\r\n", wCS, wIP);
  1553.         OutputDebugString(szText);
  1554.         wReentry = 0;
  1555.         return 1;
  1556.     }
  1557.  
  1558.     /* Set the static variables */
  1559.     wsCS = wCS;
  1560.     wsIP = wIP;
  1561.     wsFault = wNumber;
  1562.     wsFaultTask = GetCurrentTask();
  1563.  
  1564.     /* Use the dialog box to determine what to do with the fault */
  1565.     lpfnDlg = MakeProcInstance((FARPROC)FaultDialogProc, hInst);
  1566.     nResult = DialogBox(hInst, MAKEINTRESOURCE(IDD_FAULT), hwndMain, lpfnDlg);
  1567.     FreeProcInstance(lpfnDlg);
  1568.  
  1569.     /* We're getting out now, so undo reentry flag */
  1570.     wReentry = 0;
  1571.  
  1572.     return (WORD)nResult;
  1573. }
  1574.  
  1575.  
  1576. /*  FaultDialogProc
  1577.  *      Handles the Fault dialog box
  1578.  *      It returns 0 to nuke the app, 1 to restart the instruction,
  1579.  *      2 to chain on
  1580.  */
  1581.  
  1582. BOOL __export CALLBACK FaultDialogProc(HWND hDlg, WORD wMessage, WORD wParam, DWORD dwParam)
  1583. {
  1584.     switch (wMessage)
  1585.     {
  1586.     case WM_INITDIALOG:
  1587.         wsprintf(szText, "%d", wsFault);
  1588.         SetDlgItemText(hDlg, IDC_FAULTNUM, szText);
  1589.         wsprintf(szText, "%04X:%04X", wsCS, wsIP);
  1590.         SetDlgItemText(hDlg, IDC_CSIP, szText);
  1591.         wsprintf(szText, "%04X", wsFaultTask);
  1592.         SetDlgItemText(hDlg, IDC_HFAULT, szText);
  1593.         wsprintf(szText, "%04X", wsProgramTask);
  1594.         SetDlgItemText(hDlg, IDC_HPROGRAM, szText);
  1595.         return TRUE;
  1596.  
  1597.     case WM_COMMAND:
  1598.         switch (wParam)
  1599.         {
  1600.         case IDC_KILL:
  1601.             EndDialog(hDlg, 0);
  1602.             return TRUE;
  1603.  
  1604.         case IDC_RESTART:
  1605.             EndDialog(hDlg, 1);
  1606.             return TRUE;
  1607.  
  1608.         case IDC_CHAIN:
  1609.             EndDialog(hDlg, 2);
  1610.             return TRUE;
  1611.  
  1612.         default:
  1613.             return FALSE;
  1614.         }
  1615.  
  1616.     default:
  1617.         return FALSE;
  1618.     }
  1619. }