home *** CD-ROM | disk | FTP | other *** search
- /*
- USERWALK.C -- Walks the USER heap segments, and allows browsing
- of recognized structures.
-
- Copyright (c) Dave Maxey 1992
-
- From Chapter 6 of "Undocumented Windows" (Addison-Wesley 1992)
- by Andrew Schulman, Dave Maxey and Matt Pietrek
-
- Build using: WINIOBC USERWALK (for Borland C++ v3.00)
- WINIOMS USERWALK (for Microsoft C/SDK)
- */
-
- #include <windows.h>
- #include <ctype.h>
- #include <stdarg.h>
- #include <stdio.h>
- #include <string.h>
- #include <dos.h>
- #include "toolhelp.h"
- #include "winio.h"
- #include "userobj.h"
-
- #ifndef __BORLANDC__
- #define MK_FP(a,b) ((void far *)(((unsigned long)(a) << 16) | (b)))
- //#else
- //#define asm _asm
- #endif
-
- typedef struct _LINESTOHEAP
- {
- WORD wHeap;
- int nFirstLine, nLastLine;
- } LINESTOHEAP;
-
- void WalkOneUserHeap(WORD seg);
- void UserHeapWalk(void);
- BOOL ContainsLocalHeap(WORD seg);
- void MainWndLine(HWND hwnd, LPSTR line, int lineNum);
- void OtherWndLine(HWND hwnd, LPSTR line, int lineNum);
-
- /* The following are structure 'viewer' functions. Since only a
- subset of the structures referred to are known, many of these call
- DumpBlock, which is the hex dump default */
- void DumpBlock(WORD wSel, WORD wOfs, WORD wBytes);
- void DumpClass(WORD wSel, WORD wOfs, WORD wBytes);
- void DumpWindow(WORD wSel, WORD wOfs, WORD wBytes);
- void DumpString(WORD wSel, WORD wOfs, WORD wBytes);
- void DumpMenu(WORD wSel, WORD wOfs, WORD wBytes);
- void DumpClip(WORD wSel, WORD wOfs, WORD wBytes);
- void DumpCombo(WORD wSel, WORD wOfs, WORD wBytes);
- void DumpPalette(WORD wSel, WORD wOfs, WORD wBytes);
- void DumpEditCtl(WORD wSel, WORD wOfs, WORD wBytes);
- void DumpBWL(WORD wSel, WORD wOfs, WORD wBytes);
- void DumpOwnerDraw(WORD wSel, WORD wOfs, WORD wBytes);
- void DumpSPB(WORD wSel, WORD wOfs, WORD wBytes);
- void DumpChkPnt(WORD wSel, WORD wOfs, WORD wBytes);
- void DumpDCE(WORD wSel, WORD wOfs, WORD wBytes);
- void DumpMWP(WORD wSel, WORD wOfs, WORD wBytes);
- void DumpProp(WORD wSel, WORD wOfs, WORD wBytes);
- void DumpListbox(WORD wSel, WORD wOfs, WORD wBytes);
- void DumpMisc(WORD wSel, WORD wOfs, WORD wBytes);
- void DumpAtom(WORD wSel, WORD wOfs, WORD wBytes);
- void DumpLockInpSt(WORD wSel, WORD wOfs, WORD wBytes);
- void DumpHooklist(WORD wSel, WORD wOfs, WORD wBytes);
- void DumpUSUDAlloc(WORD wSel, WORD wOfs, WORD wBytes);
- void DumpHotKeyList(WORD wSel, WORD wOfs, WORD wBytes);
- void DumpPopupMenu(WORD wSel, WORD wOfs, WORD wBytes);
-
- BOOL FarLocalSize(WORD wSel, WORD wH, WORD *pOfs, WORD *pSize);
- BOOL MyIsMenu(WORD wSel, WORD wOfs);
- void GetAnyAtomName(WORD wSeg, ATOM nAtom, LPSTR lpBuffer, int nSize);
- void buildlist(void);
- BOOL IsMenuHeap(WORD wSel);
- void DoRefresh(HWND hwnd, WORD wID);
-
-
- #define ID_REFRESH 1
- #define ID_HEAPS 2
- #define ID_WINDOWS 3
- #define ID_ANALYSIS 5
- #define MAXHEAPS 8
-
- WORD wCurrView;
- HMENU hMenuView;
- char szTitle[] = "USER Heap Walker";
- char UnknownString[] = "<UNKNOWN>";
- int nLineNum = 0;
- int nHeaps;
- BOOL bDebug, b31;
- WORD wDefHeap, wMenuHeap, wAtomHeap;
- char *strIndent = " ";
- SYSHEAPINFO shi;
- HWND hwndAnal = NULL;
-
- // These are the TOOLHELP defined object types
- char *UserBlockType[] =
- {
- "NORMAL", // 0
- "Class", // 1
- "Window", // 2
- "STRING", // 3
- "Menu", // 4
- "CLIP", // 5
- "Combo box", // 6
- "PALETTE", // 7
- "Edit control", // 8
- "BWL", // 9
- "OWNERDRAW", // 10
- "SPB", // 11
- "CHECKPOINT", // 12
- "DCE", // 13
- "MWP", // 14
- "Property", // 15
- "Listbox", // 16
- "MISC", // 17
- "atom", // 18
- "LOCKINPUTSTATE", // 19
- "HOOKLIST", // 20
- "USERSEEUSERDOALLOC", // 21
- "HOTKEYLIST", // 22
- "POPUPMENU" // 23
- };
-
- #define BLOCKTYPES (sizeof(UserBlockType) / sizeof(char *))
-
- POINT pntSize[] = {
- { 76, -1 },
- { 55, 16 },
- { 50, 28 },
- { 76, -1 },
- { 55, 15 },
- { 76, -1 },
- { 76, -1 },
- { 76, -1 },
- { 76, -1 },
- { 76, -1 },
- { 76, -1 },
- { 76, -1 },
- { 76, -1 },
- { 76, -1 },
- { 76, -1 },
- { 60, 20 },
- { 76, -1 },
- { 76, -1 },
- { 76, -1 },
- { 76, -1 },
- { 76, -1 },
- { 76, -1 },
- { 76, -1 },
- { 76, -1 },
- { 76, -1 }
- };
-
- typedef long HEAPAMOUNTS[BLOCKTYPES];
-
- LINESTOHEAP ltoh[MAXHEAPS] = {0};
- HEAPAMOUNTS heapamnts[MAXHEAPS] = {0};
- DWORD heaptots[MAXHEAPS] = {0};
-
-
- typedef void (* fnDUMP)(WORD wSel, WORD wOfs, WORD wBytes);
-
- fnDUMP fnDump[] =
- { DumpBlock, DumpClass, DumpWindow, DumpString, DumpMenu, DumpClip,
- DumpCombo, DumpPalette, DumpEditCtl, DumpBWL, DumpOwnerDraw,
- DumpSPB, DumpChkPnt, DumpDCE, DumpMWP, DumpProp, DumpListbox,
- DumpMisc, DumpAtom, DumpLockInpSt, DumpHooklist, DumpUSUDAlloc,
- DumpHotKeyList, DumpPopupMenu, DumpBlock };
-
- #define WINDOWSIZE(y, x) \
- ((DWORD) ((DWORD) ((unsigned)(y)) << 16) | ((unsigned)(x)))
-
- typedef struct {
- char *szField;
- int iType;
- } HFIELD;
-
- HFIELD hfld[] = {
- { "hwndNext", 2 }, { "hwndChild", 2 }, { "hClass", 1 },
- { "hwndLastActive", 2 }, { "hmenuSystem", 4 }, { "hwndOwner", 2 },
- { "wID_Menu", 4 }, { "hwndParent", 2 }, { "hmenuNext", 4},
- { "hIDorPopup", 4 }, { "hProp", 15 }, { "hDCE", 13 } };
-
- #define MAXHFIELDS (sizeof(hfld) / sizeof(HFIELD))
-
- WORD verr(WORD sel)
- {
- _asm mov ax, 1
- _asm verr word ptr sel
- _asm je short ok
- _asm dec ax
- ok:;
- }
-
- WORD lsl(WORD wSel)
- {
- _asm sub ax, ax
- _asm lsl ax, wSel
- }
-
-
- #define WIDTH 16
-
- void DumpBlock(WORD wSel, WORD wOfs, WORD wBytes)
- {
- LPSTR fp, p;
- WORD i, j, c;
-
- fp = MK_FP(wSel, wOfs);
-
- for (i=0; i<wBytes; i += WIDTH)
- {
- c = ((wBytes-i) > WIDTH) ? WIDTH : wBytes-i;
- printf("%04X | ", i);
- for (j=c, p=fp+i; j--; p++)
- printf("%02X ", (unsigned char) *p);
- for (j=WIDTH-c; j--; ) // pad out on last line
- printf(" ");
- putchar('|'); putchar(' ');
- for (j=c, p=fp+i; j--; p++)
- putchar( isprint(*p) ? *p : '.' );
- putchar('\n');
- }
- }
-
-
- void DumpClass(WORD wSel, WORD wOfs, WORD wBytes)
- {
- CLASS far *pCls;
- char szClsName[64];
- pCls = (CLASS FAR *) MK_FP(wSel, wOfs);
-
- GetAnyAtomName(shi.hUserSegment, pCls->atomCls, (LPSTR) &szClsName, 64);
-
- printf("Lines marked '->' may be double clicked\nfor expansion\n\n");
- printf( "CLASS:\n"
- "\thcNext\t\t: %04X\n"
- "\twSig\t\t: %04X (\"%c%c\")\n"
- "\tatomCls\t\t: %04X (\"%s\")\n"
- "->\thDCE\t: %04X\n"
- "\tcClsWnds\t: %04X\n"
- "\tstyle\t\t: %04X\n"
- "\tlpfnWndProc\t: %Fp\n"
- "\tcbClsExtra\t: %04X\n"
- "\tcbWndExtra\t: %04X\n"
- "\thInstance\t: %04X\n"
- "\thIcon\t\t: %04X\n"
- "\thCursor\t\t: %04X\n"
- "\thbrBackground\t: %04X\n"
- "\tlpszMenuName\t: %Fp\n"
- "\tlpszClassName\t: %Fp\n",
- pCls->hcNext, pCls->wSig, pCls->wSig & 0xff, pCls->wSig >> 8,
- pCls->atomCls, szClsName, pCls->hDCE,
- pCls->cClsWnds, pCls->wc.style,
- pCls->wc.lpfnWndProc, pCls->wc.cbClsExtra,
- pCls->wc.cbWndExtra, pCls->wc.hInstance,
- pCls->wc.hIcon, pCls->wc.hCursor,
- pCls->wc.hbrBackground, pCls->wc.lpszMenuName,
- pCls->wc.lpszClassName
- );
- }
-
-
- void DumpWindow(WORD wSel, WORD wOfs, WORD wBytes)
- {
- WND_3_0 far *pwnd_3_0;
- WND_3_1 far *pwnd_3_1;
- CLASS far *pcls;
- WORD clsofs;
- char strClass[20];
- char strTitle[80];
-
- printf("Lines marked '->' may be double clicked\nfor expansion\n\n");
- pwnd_3_0 = (void far *) pwnd_3_1 = (void far *) MK_FP(wSel, wOfs);
- clsofs = (WORD) (b31 ? pwnd_3_1->hClass : pwnd_3_0->hClass);
- (void far *) pcls = MK_FP(wSel, clsofs);
- GetAnyAtomName(wDefHeap, pcls->atomCls,
- (LPSTR) &strClass, sizeof(strClass));
- GetWindowText(wOfs, (LPSTR) &strTitle, sizeof(strTitle));
- printf("Window Title: %s\nWindow Class: %s\n\n", strTitle, strClass);
- if (! b31)
- printf( "WND:\n"
- "->\thwndNext\t: %04X\n"
- "->\thwndChild\t: %04X\n"
- "->\thClass\t\t: %04X\n"
- "->\thProp\t\t: %04X\n"
- "->\thwndLastActive\t: %04X\n"
- "\thScroll\t\t: %04X\n"
- "\thmemTaskQ\t: %04X\n"
- "\thrgnUpdate\t: %04X\n"
- "->\thDCE\t\t: %04X\n"
- "->\thmenuSystem\t: %04X\n"
- "->\thwndOwner\t: %04X\n"
- "\trectWindow\t: (%d, %d, %d, %d)\n"
- "\trectClient\t: (%d, %d, %d, %d)\n"
- "\thPalette\t: %04X\n"
- "\twFlags\t\t: %04X\n"
- "\trgfExStyle\t: %08lX\n"
- "\trgfStyle\t: %08lX\n"
- "->\twID_Menu\t: %04X\n"
- "\thText\t\t: %04X\n"
- "->\thwndParent\t: %04X\n"
- "\thInstance\t: %04X\n"
- "\tlpfnWndProc : %Fp\n",
- pwnd_3_0->hwndNext, pwnd_3_0->hwndChild,
- pwnd_3_0->hClass, pwnd_3_0->hProp,
- pwnd_3_0->hwndLastActive, pwnd_3_0->hScroll,
- pwnd_3_0->hmemTaskQ,
- pwnd_3_0->hrgnUpdate, pwnd_3_0->hDCE,
- pwnd_3_0->hmenuSystem, pwnd_3_0->hwndOwner,
- pwnd_3_0->rectWindow.left, pwnd_3_0->rectWindow.top,
- pwnd_3_0->rectWindow.right, pwnd_3_0->rectWindow.bottom,
- pwnd_3_0->rectClient.left, pwnd_3_0->rectClient.top,
- pwnd_3_0->rectClient.right, pwnd_3_0->rectClient.bottom,
- pwnd_3_0->hPalette, pwnd_3_0->wFlags,
- pwnd_3_0->rgfExStyle, pwnd_3_0->rgfStyle,
- pwnd_3_0->wID_Menu, pwnd_3_0->hText, pwnd_3_0->hwndParent,
- pwnd_3_0->hInstance, pwnd_3_0->lpfnWndProc
- );
- else
- printf( "WND:\n"
- "->\thwndNext\t: %04X\n"
- "->\thwndChild\t: %04X\n"
- "->\thwndParent\t: %04X\n"
- "->\thwndOwner\t: %04X\n"
- "\trectWindow\t: (%d, %d, %d, %d)\n"
- "\trectClient\t: (%d, %d, %d, %d)\n"
- "\thTaskQ\t\t: %04X\n"
- "\thrgnUpdate\t: %04X\n"
- "->\thClass\t\t: %04X\n"
- "\thInstance\t: %04X\n"
- "\tlpfnWndProc\t: %Fp\n"
- "\tdwFlags\t\t: %08lX\n"
- "\trgfStyle\t: %08lX\n"
- "\trgfExStyle\t: %08lX\n"
- "->\twID_Menu\t: %04X\n"
- "\thText\t\t: %04X\n"
- "\thScroll\t\t: %04X\n"
- "->\thProp\t\t: %04X\n"
- "->\thwndLastActive\t: %04X\n"
- "->\thmenuSystem\t: %04X\n",
- pwnd_3_1->hwndNext, pwnd_3_1->hwndChild,
- pwnd_3_1->hwndParent, pwnd_3_1->hwndOwner,
- pwnd_3_1->rectWindow.left, pwnd_3_1->rectWindow.top,
- pwnd_3_1->rectWindow.right, pwnd_3_1->rectWindow.bottom,
- pwnd_3_1->rectClient.left, pwnd_3_1->rectClient.top,
- pwnd_3_1->rectClient.right, pwnd_3_1->rectClient.bottom,
- pwnd_3_1->hmemTaskQ, pwnd_3_1->hrgnUpdate,
- pwnd_3_1->hClass,
- pwnd_3_1->hInstance, pwnd_3_1->lpfnWndProc,
- pwnd_3_1->dwFlags,
- pwnd_3_1->rgfStyle, pwnd_3_1->rgfExStyle,
- pwnd_3_1->wID_Menu, pwnd_3_1->hText,
- pwnd_3_1->hScroll, pwnd_3_1->hProp,
- pwnd_3_1->hwndLastActive, pwnd_3_1->hmenuSystem
- );
- }
-
-
- void DumpMenu(WORD wSel, WORD wOfs, WORD wBytes)
- {
- int i;
- MENU_3_0 FAR *lpMenu30;
- MENU_3_1 FAR *lpMenu31;
- LPITEM lpItem;
- char buf[30];
-
- lpMenu30 = (void far *) lpMenu31 = (void far *) MK_FP(wSel, wOfs);
- if (! MyIsMenu(wSel, wOfs))
- {
- winio_warn(FALSE, szTitle, "%04X is either no longer valid\n"
- "as an HMENU, or is an ID.", wOfs);
- return;
- }
- if (! b31)
- printf("MENU:\n"
- "\twFlags\t\t: %04X\n"
- "\tiCurrSel\t: %d\n"
- "\tiCurrPopup\t: %d\n"
- "\tcbMenu\t\t: %d\n"
- "\tcxWidth\t\t: %d\n"
- "\tcyHeight\t: %d\n"
- "\tcItems\t\t: %d\n"
- "->\thwndOwner\t: %04X\n",
- lpMenu30->wFlags,
- lpMenu30->iCurrSel,
- lpMenu30->iCurrPopup,
- lpMenu30->cbMenu,
- lpMenu30->cxWidth,
- lpMenu30->cyHeight,
- lpMenu30->cItems,
- lpMenu30->hwndOwner
- );
- else
- printf("MENU:\n"
- "->\thmenuNext\t: %04X\n"
- "\twFlags\t\t: %04X\n"
- "\twMagic\t\t: %04X (\"%c%c\")\n"
- "\thTaskQ\t\t: %04X\n"
- "\tcxWidth\t\t: %d\n"
- "\tcyHeight\t: %d\n"
- "\tcItems\t\t: %d\n"
- "->\thwndOwner\t: %04X\n"
- "\thItems\t\t: %04X\n"
- "\tw12\t\t: %04X\n",
- lpMenu31->hmenuNext,
- lpMenu31->wFlags,
- lpMenu31->wMagic, lpMenu31->wMagic & 0xff, lpMenu31->wMagic >> 8,
- lpMenu31->hTaskQ,
- lpMenu31->cxWidth,
- lpMenu31->cyHeight,
- lpMenu31->cItems,
- lpMenu31->hwndOwner,
- lpMenu31->hItems,
- lpMenu31->w12
- );
-
- lpItem = b31 ? (void far *) MK_FP(wSel, lpMenu31->hItems)
- : (void far *) MK_FP(wSel, wOfs + sizeof(MENU_3_0));
-
- // cItems is at the same offset in both versions
- // and the ITEM structure didn't change.
- for (i = 0; i < lpMenu30->cItems; i++)
- {
- GlobalGetAtomName(lpItem->hStrOrBmp, (LPSTR) &buf, sizeof(buf));
- printf("ITEM %d:\n"
- "\twFlags\t\t: %04X\n"
- "->\thIDorPopup\t: %04X\n"
- "\trectCapture\t: (%d, %d, %d, %d)\n"
- "\txTab\t\t: %d\n"
- "\thCheckedBmp\t: %04X\n"
- "\thUncheckedBmp\t: %04X\n"
- "\thStrOrBmp\t: %04X (\"%s\")\n"
- "\txULStart\t: %d\n"
- "\tcxULLen\t\t: %d\n"
- "\tcbItemLen\t: %d\n",
- i + 1,
- lpItem->wFlags,
- lpItem->hIDorPopup,
- lpItem->rectCapture.left, lpItem->rectCapture.top,
- lpItem->rectCapture.right, lpItem->rectCapture.bottom,
- lpItem->xTab,
- lpItem->hCheckedBmp,
- lpItem->hUncheckedBmp,
- lpItem->hStrOrBmp, buf,
- lpItem->xULStart,
- lpItem->cxULLen,
- lpItem->cbItemLen
- );
- lpItem++;
- }
- }
-
-
- void DumpString(WORD wSel, WORD wOfs, WORD wBytes)
- {
- DumpBlock(wSel, wOfs, wBytes);
- }
-
-
- void DumpClip(WORD wSel, WORD wOfs, WORD wBytes)
- {
- DumpBlock(wSel, wOfs, wBytes);
- }
-
-
- void DumpCombo(WORD wSel, WORD wOfs, WORD wBytes)
- {
- DumpBlock(wSel, wOfs, wBytes);
- }
-
-
- void DumpPalette(WORD wSel, WORD wOfs, WORD wBytes)
- {
- DumpBlock(wSel, wOfs, wBytes);
- }
-
-
- void DumpEditCtl(WORD wSel, WORD wOfs, WORD wBytes)
- {
- DumpBlock(wSel, wOfs, wBytes);
- }
-
-
- void DumpBWL(WORD wSel, WORD wOfs, WORD wBytes)
- {
- DumpBlock(wSel, wOfs, wBytes);
- }
-
-
- void DumpOwnerDraw(WORD wSel, WORD wOfs, WORD wBytes)
- {
- DumpBlock(wSel, wOfs, wBytes);
- }
-
-
- void DumpSPB(WORD wSel, WORD wOfs, WORD wBytes)
- {
- DumpBlock(wSel, wOfs, wBytes);
- }
-
-
- void DumpChkPnt(WORD wSel, WORD wOfs, WORD wBytes)
- {
- DumpBlock(wSel, wOfs, wBytes);
- }
-
-
- void DumpDCE(WORD wSel, WORD wOfs, WORD wBytes)
- {
- CLASS far *pCls;
- char szClsName[64];
- pCls = (CLASS FAR *) MK_FP(wSel, wOfs);
-
- GetAnyAtomName(shi.hUserSegment, pCls->atomCls, (LPSTR) &szClsName, 64);
-
- printf("Lines marked '->' may be double clicked\nfor expansion\n\n");
- printf( "CLASS:\n"
- "\thcNext\t\t: %04X\n"
- "\twSig\t\t: %04X (\"%c%c\")\n"
- "\tatomCls\t\t: %04X (\"%s\")\n"
- "->\thDCE\t\t: %04X\n"
- "\tcClsWnds\t: %04X\n"
- "\tstyle\t\t: %04X\n"
- "\tlpfnWndProc\t: %Fp\n"
- "\tcbClsExtra\t: %04X\n"
- "\tcbWndExtra\t: %04X\n"
- "\thInstance\t: %04X\n"
- "\thIcon\t\t: %04X\n"
- "\thCursor\t\t: %04X\n"
- "\thbrBackground\t: %04X\n"
- "\tlpszMenuName\t: %Fp\n"
- "\tlpszClassName\t: %Fp\n",
- pCls->hcNext, pCls->wSig, pCls->wSig & 0xff, pCls->wSig >> 8,
- pCls->atomCls, szClsName, pCls->hDCE,
- pCls->cClsWnds, pCls->wc.style,
- pCls->wc.lpfnWndProc, pCls->wc.cbClsExtra,
- pCls->wc.cbWndExtra, pCls->wc.hInstance,
- pCls->wc.hIcon, pCls->wc.hCursor,
- pCls->wc.hbrBackground, pCls->wc.lpszMenuName,
- pCls->wc.lpszClassName
- );
- }
-
-
- void DumpMWP(WORD wSel, WORD wOfs, WORD wBytes)
- {
- DumpBlock(wSel, wOfs, wBytes);
- }
-
-
- void DumpProp(WORD wSel, WORD wOfs, WORD wBytes)
- {
- char strAtom[50];
- int i, iMax;
- PROPERTY FAR *pProp = (PROPERTY FAR *) MK_FP(wSel, wOfs);
-
- printf( "PROPLIST:\n"
- "\tcProps\t\t: %d\n\n",
- iMax = *((int far *) pProp));
-
- (DWORD) pProp += 2;
-
- for (i = 0; i < iMax; i++)
- {
- GetAnyAtomName(wDefHeap, pProp->atomID, (LPSTR) &strAtom,
- sizeof(strAtom));
-
- printf(
- "PROPERTY %d:\n"
- "\tatomID\t\t: %04X (\"%s\")\n"
- "\thData\t\t: %04X\n"
- "\twFlags\t\t: %04X\n",
- i + 1,
- pProp->atomID, strAtom,
- pProp->hData,
- pProp->wFlags);
- }
- }
-
-
- void DumpListbox(WORD wSel, WORD wOfs, WORD wBytes)
- {
- DumpBlock(wSel, wOfs, wBytes);
- }
-
-
- void DumpMisc(WORD wSel, WORD wOfs, WORD wBytes)
- {
- DumpBlock(wSel, wOfs, wBytes);
- }
-
-
- void DumpAtom(WORD wSel, WORD wOfs, WORD wBytes)
- {
- DumpBlock(wSel, wOfs, wBytes);
- }
-
-
- void DumpLockInpSt(WORD wSel, WORD wOfs, WORD wBytes)
- {
- DumpBlock(wSel, wOfs, wBytes);
- }
-
-
- void DumpHooklist(WORD wSel, WORD wOfs, WORD wBytes)
- {
- DumpBlock(wSel, wOfs, wBytes);
- }
-
-
- void DumpUSUDAlloc(WORD wSel, WORD wOfs, WORD wBytes)
- {
- DumpBlock(wSel, wOfs, wBytes);
- }
-
-
- void DumpHotKeyList(WORD wSel, WORD wOfs, WORD wBytes)
- {
- DumpBlock(wSel, wOfs, wBytes);
- }
-
-
- void DumpPopupMenu(WORD wSel, WORD wOfs, WORD wBytes)
- {
- DumpBlock(wSel, wOfs, wBytes);
- }
-
-
-
-
- void DispatchDump(char *typ, WORD wH, WORD wSel, WORD wOfs, WORD wBytes)
- {
- WORD wLimit;
- char buf[80];
- HWND hwndNew, hwndSav;
- int i;
- DWORD dwSave;
-
- wSel &= ~3;
- wSel |= 1;
-
- if (! verr(wSel))
- {
- winio_warn(FALSE, szTitle, "%04x no longer valid\n", wSel);
- return;
- }
- if ((wLimit = lsl(wSel)) < wOfs)
- {
- winio_warn(FALSE, szTitle,
- "Start offs %04X is outside selector %04X limit of %04X\n",
- wOfs, wSel, wLimit);
- return;
- }
- if ((wLimit + 1) < (wBytes + wOfs))
- {
- winio_warn(FALSE, szTitle,
- "Selector %04X limit is %04X, length of dump adjusted\n",
- wSel, wLimit);
- wBytes = wLimit - wOfs + 1;
- }
-
- for (i = 0; i < BLOCKTYPES; i++)
- if (strcmp(typ, UserBlockType[i]) == 0) break;
-
- sprintf(buf, "%s handle %04X @ %04X:%04X for %d bytes",
- typ, wH, wSel, wOfs, wBytes);
-
- if ((hwndNew = FindWindow(NULL, buf)) != NULL)
- {
- ShowWindow(hwndNew, SW_RESTORE);
- BringWindowToTop(hwndNew);
- return;
- }
-
- // Use the table entry for window size. If the entry has a
- // y size of -1, it means it is a dump, and we use the amount
- // of data to display to determine the y size.
- dwSave = winio_defwindowsize(
- WINDOWSIZE( ((pntSize[i].y == -1)
- ? min(20, (wBytes + 15) / 16) : pntSize[i].y),
- pntSize[i].x));
-
- if (! (hwndNew = winio_window(buf, min(wBytes * 20, 1024), WW_HASMENU)))
- {
- winio_warn(FALSE, "Dump", "Insufficient resources!");
- return;
- }
-
- winio_defwindowsize(dwSave);
-
- hwndSav = winio_setcurrent(hwndNew);
-
- winio_setpaint(hwndNew, FALSE);
-
- // there is an extra entry in the fnDump table to allow for when
- // the type was not in the UserBlockType table
- (* (fnDump[i]))(wSel, wOfs, wBytes);
-
- winio_setlinefn(hwndNew, OtherWndLine);
- winio_setpaint(hwndNew, TRUE);
- winio_home(hwndNew);
- winio_setcurrent(hwndSav);
-
- }
-
-
- void WindowViewLine(HWND hwnd, LPSTR lpLine, int iLine)
- {
- int i;
- WORD wndofs;
- char strText[80];
-
- lstrcpy((LPSTR) &strText, lpLine);
- for (i = 0; strText[i] == ' '; i++);
- if (! strText[i]) return;
- sscanf((char *) &strText[i], "%04X", &wndofs);
- if (! IsWindow(wndofs))
- {
- winio_warn(FALSE, szTitle,
- "HWND %04X is no longer valid", wndofs);
- buildlist();
- return;
- }
-
- DispatchDump(UserBlockType[2], wndofs, wDefHeap, wndofs,
- b31 ? sizeof(WND_3_1) : sizeof(WND_3_0));
- }
-
-
- void HeapViewLine(HWND hwnd, LPSTR line, int lineNum)
- {
- WORD wSel, wH, wOfs, wBytes;
- char typ[20];
- char buf[80];
- int i;
-
- for (i = 0; i < nHeaps; i++)
- if (lineNum < ltoh[i].nFirstLine)
- return;
- else
- if (lineNum < ltoh[i].nLastLine)
- break;
-
- wSel = ltoh[i].wHeap;
-
- lstrcpy(buf, line);
-
- if (sscanf(buf, "%04X %04X %04X %s", &wH, &wOfs, &wBytes, &typ) < 1)
- return;
-
- DispatchDump(typ, wH, wSel, wOfs, wBytes);
- }
-
-
-
- void OtherWndLine(HWND hwnd, LPSTR line, int lineNum)
- {
- WORD wSel, wH, wOfs, wBytes;
- char typ[20];
- char buf[80];
- int i;
-
- if ((*line++ != '-') || (*line++ != '>')) return;
-
- GetWindowText(hwnd, (LPSTR) &buf, sizeof(buf));
- sscanf(buf, "%s handle %04X @ %04X:%04X for %d bytes",
- &typ, &wH, &wSel, &wOfs, &wBytes);
-
- lstrcpy(buf, line);
-
- if (sscanf(buf, " %s : %04X", &typ, &wH) < 1)
- return;
-
- if (! wH)
- {
- winio_warn(FALSE, szTitle, "NULL handle!");
- return;
- }
-
- for (i = 0; i < MAXHFIELDS; i++)
- if (strcmp(hfld[i].szField, typ) == 0)
- break;
- if (i == MAXHFIELDS) return;
-
- if (! FarLocalSize(wSel, wH - (bDebug ? 4 : 0),
- &wOfs, &wBytes))
- {
- winio_warn(FALSE, szTitle, "Handle %04X in USER heap %04X\n"
- "is no longer valid.", wH, wSel);
- DoRefresh(__hMainWnd, ID_REFRESH);
- }
- else
- {
- if (bDebug) wOfs += 4;
- DispatchDump(UserBlockType[hfld[i].iType], wH, wSel, wOfs, wBytes);
- }
- }
-
-
-
- char *GetUserBlockType(WORD type)
- {
- // only default USER local heap gets ToolHelp USER subtypes;
- // use signatures to show for the rest?
-
- if ( type <= LT_USER_MAX )
- return UserBlockType[type];
-
- if ( type == 0xFF )
- return "FREE";
-
- return UnknownString;
- }
-
- void WalkOneUserHeap(WORD seg)
- {
- LOCALENTRY le;
- BOOL ok;
- int typ;
-
- if (! seg) return;
-
- printf(
- "USER heap in segment %04xh:\n"
- "(Double-click to view a block)\n"
- "HANDLE ADDR SIZE TYPE\n",
- seg);
- nLineNum += 4;
-
- ltoh[nHeaps].wHeap = seg;
- ltoh[nHeaps].nFirstLine = nLineNum;
-
- le.dwSize = sizeof(le);
- ok = LocalFirst(&le, seg);
-
- while ( ok )
- {
- // In debug versions, each block has a 4 byte overhead
- if (bDebug)
- {
- le.hHandle += 4;
- le.wAddress += 4;
- }
-
- nLineNum++;
- typ = le.wType ? le.wType
- : (IsWindow(le.hHandle) && (seg == wDefHeap)) ? 2
- : *((WORD FAR *) MK_FP(seg, le.wAddress + 2)) ==
- CLASS_MAGIC ? 1
- : MyIsMenu(seg, le.wAddress) ? 4
- : 0;
- printf
- (
- "%04X %04X %04X %s\n",
- le.hHandle, le.wAddress, le.wSize,
- GetUserBlockType(typ)
- );
- heaptots[nHeaps] += le.wSize;
- if (typ < BLOCKTYPES)
- ((DWORD) (heapamnts[nHeaps])[typ]) += le.wSize;
-
- ok = LocalNext(&le);
- }
- ltoh[nHeaps].nLastLine = nLineNum;
- printf("\n");
- nLineNum++;
- }
-
-
- void UserHeapWalk(void)
- {
- GLOBALENTRY ge;
- BOOL ok;
- HANDLE hUSER = GetModuleHandle("USER");
-
- winio_clear(__hMainWnd);
-
- // Turn off repaints to minimize Heisenberg effects on heap
-
- winio_setbusy();
- winio_setpaint(__hMainWnd, FALSE);
-
- memset(heapamnts, 0, sizeof(heapamnts));
- memset(heaptots, 0, sizeof(heaptots));
- nHeaps = 0;
- nLineNum = 0;
-
- WalkOneUserHeap(wDefHeap);
- printf("\n");
-
- nHeaps = 1;
- ge.dwSize = sizeof(ge);
- ok = GlobalFirst(&ge, GLOBAL_ALL);
-
- while ( ok )
- {
- if (ge.hOwner == hUSER)
- {
- ge.hBlock &= 0xfffc;
- ge.hBlock |= 1;
-
- if ((ContainsLocalHeap(ge.hBlock)) &&
- (ge.hBlock != wDefHeap))
- {
- if ((b31) && IsMenuHeap(ge.hBlock))
- wMenuHeap = ge.hBlock;
- WalkOneUserHeap(ge.hBlock);
- nHeaps++;
- printf("\n");
- }
- }
- ok = GlobalNext(&ge, GLOBAL_ALL);
- }
-
- // Turn repaints back on, and position at the top of the info
- winio_setpaint(__hMainWnd, TRUE);
- winio_resetbusy();
- winio_home(__hMainWnd);
- }
-
-
- void AnalyzeHeaps(HWND hwnd, WORD wID)
- {
- int i, j;
- long amnt, total, totfree, allheaps = 0;
- HWND hwndSave;
-
- if (IsWindow(hwndAnal))
- {
- ShowWindow(hwndAnal, SW_RESTORE);
- BringWindowToTop(hwndAnal);
- return;
- }
-
- winio_defwindowsize(WINDOWSIZE(20, 60));
- hwndAnal = winio_window("User Heap Analysis", 1024, WW_HASMENU);
-
- hwndSave = winio_setcurrent(hwndAnal);
- winio_setpaint(hwndAnal, FALSE);
- winio_setbusy();
-
- for (i = 0; i < nHeaps; i++)
- {
- printf("Heap at %04X is %ld bytes:\n", ltoh[i].wHeap,
- totfree = total = heaptots[i]);
- for (j = 0; j < BLOCKTYPES; j++)
- {
- if (! (amnt = heapamnts[i][j])) continue;
- printf("\t%-20.20sTotal: %ld bytes (%ld%c)\n",
- UserBlockType[j], amnt, (amnt * 100) / total, '%');
- totfree -= amnt;
- }
- printf("\tFREE\t\t\t : %ld bytes (%ld%c)\n",
- totfree, ((totfree * 100) / total) + 1 /* Kludge for rounding */,
- '%');
- allheaps += total;
- printf("\n");
- }
-
- printf("Total USER memory in heaps is %ld bytes", allheaps);
-
- winio_resetbusy();
- winio_setpaint(hwndAnal, TRUE);
- winio_home(hwndAnal);
- winio_setcurrent(hwndSave);
- }
-
-
-
- void printtree(WORD wndofs)
- {
- char strClass[20];
- char strText[80];
- WND_3_0 far *hwnd30;
- WND_3_1 far *hwnd31;
- CLASS far *pcls;
- WORD clsofs;
-
- for (;;)
- {
- (void far *) hwnd31 = (void far *) hwnd30 = MK_FP(wDefHeap, wndofs);
- GetWindowText((HWND) wndofs, (LPSTR) &strText, sizeof(strText));
- clsofs = (WORD) (b31 ? hwnd31->hClass : hwnd30->hClass);
- (void far *) pcls = MK_FP(wDefHeap, clsofs);
- if (pcls->wSig != 0x4b4e)
- winio_warn(FALSE, __szModule, "Bad class pointer");
- GetAnyAtomName(wDefHeap, pcls->atomCls,
- (LPSTR) &strClass, sizeof(strClass));
- printf("%s%04X %s [%s]\n", strIndent, wndofs, strText, strClass);
- if (hwnd30->hwndChild != NULL)
- {
- strIndent -= 4;
- printtree(hwnd30->hwndChild);
- strIndent += 4;
- }
-
- if ((wndofs = hwnd30->hwndNext) == NULL)
- break;
- }
- }
-
-
- void buildlist(void)
- {
- winio_clear(__hMainWnd);
- winio_setbusy();
- winio_setpaint(__hMainWnd, FALSE);
-
- strIndent += strlen(strIndent);
-
- printtree(GetDesktopWindow());
-
- winio_setpaint(__hMainWnd, TRUE);
- winio_resetbusy();
- winio_home(__hMainWnd);
- }
-
-
-
- void SwitchToHeaps(HWND hwnd, WORD wID)
- {
- char buf[50];
-
- strcpy(buf, szTitle);
- strcat(buf, ": Heap Segments");
- winio_settitle(__hMainWnd, buf);
- CheckMenuItem(hMenuView, ID_HEAPS, MF_CHECKED);
- CheckMenuItem(hMenuView, ID_WINDOWS, MF_UNCHECKED);
- winio_setlinefn(hwnd, HeapViewLine);
- wCurrView = ID_HEAPS;
-
- UserHeapWalk();
- }
-
-
- void SwitchToWindows(HWND hwnd, WORD wID)
- {
- char buf[50];
-
- strcpy(buf, szTitle);
- strcat(buf, ": Window Hierarchy");
- winio_settitle(__hMainWnd, buf);
- CheckMenuItem(hMenuView, ID_HEAPS, MF_UNCHECKED);
- CheckMenuItem(hMenuView, ID_WINDOWS, MF_CHECKED);
- winio_setlinefn(hwnd, WindowViewLine);
- wCurrView = ID_WINDOWS;
-
- buildlist();
- }
-
-
- void DoRefresh(HWND hwnd, WORD wID)
- {
- switch (wCurrView)
- {
- case ID_HEAPS :
- UserHeapWalk();
- if (IsWindow(hwndAnal))
- AnalyzeHeaps(__hMainWnd, ID_ANALYSIS);
- break;
- case ID_WINDOWS : buildlist(); break;
- }
- }
-
-
- int main(int argc, char *argv[] )
- {
- b31 = HIBYTE(GetVersion());
- bDebug = GetSystemMetrics(SM_DEBUG);
- winio_setbufsize(__hMainWnd, (WORD) 65530, FALSE);
-
- winio_about("USERWALK"
- "\nWalks the USER heap segments, and allows browsing"
- "\nof recognized structures."
- "\n\nFrom Chapter 6 of"
- "\n\"Undocumented Windows\" (Addison-Wesley, 1992)"
- "\nby Andrew Schulman, David Maxey and Matt Pietrek"
- );
-
- winio_setmenufunc(__hMainWnd, ID_REFRESH, (MENU_FUNC) DoRefresh);
- winio_setmenufunc(__hMainWnd, ID_HEAPS, (MENU_FUNC) SwitchToHeaps);
- winio_setmenufunc(__hMainWnd, ID_ANALYSIS, (MENU_FUNC) AnalyzeHeaps);
- winio_setmenufunc(__hMainWnd, ID_WINDOWS, (MENU_FUNC) SwitchToWindows);
-
- hMenuView = CreateMenu();
- AppendMenu(hMenuView, MF_ENABLED | MF_CHECKED | MF_STRING,
- ID_HEAPS, "&Heap Segments");
- AppendMenu(hMenuView, MF_ENABLED | MF_STRING,
- ID_WINDOWS, "&Window Hierarchy");
- InsertMenu(winio_hmenumain(__hMainWnd), 1,
- MF_ENABLED | MF_POPUP | MF_BYPOSITION,
- hMenuView, "&View");
- InsertMenu(winio_hmenumain(__hMainWnd), 2,
- MF_ENABLED | MF_STRING | MF_BYPOSITION,
- ID_ANALYSIS, "&Analyze Heaps");
- InsertMenu(winio_hmenumain(__hMainWnd), 3,
- MF_ENABLED | MF_STRING | MF_BYPOSITION,
- ID_REFRESH, "&Refresh!");
- DrawMenuBar(__hMainWnd);
-
- shi.dwSize = sizeof(shi);
- SystemHeapInfo(&shi);
- wDefHeap = shi.hUserSegment;
- wDefHeap &= 0xfffc;
- wDefHeap |= 1;
-
- if (! b31) wMenuHeap = wDefHeap;
-
- // This must be the first View type to initialize the heap types
- SwitchToHeaps(__hMainWnd, ID_HEAPS);
-
- wMenuHeap &= 0xfffc;
- wMenuHeap |= 1;
-
- return 0;
- }
-
- // We can rely on ToolHelp to tell us whether a block contains a
- // valid local heap; all the homebrew validity checks are not needed here
- BOOL ContainsLocalHeap(WORD seg)
- {
- LOCALENTRY le;
- le.dwSize = sizeof(le);
- return LocalFirst(&le, seg);
- }
-
-
- BOOL FarLocalSize(WORD wSel, WORD wH, WORD *pOfs, WORD *pSize)
- {
- LOCALENTRY le;
- BOOL ok;
-
- le.dwSize = sizeof(le);
- ok = LocalFirst(&le, wSel);
-
- while (ok && (le.hHandle != wH))
- ok = LocalNext(&le);
- if (ok)
- {
- *pOfs = le.wAddress;
- *pSize = le.wSize;
- }
- return ok;
- }
-
-
- BOOL MyIsMenu(WORD wSel, WORD wOfs)
- {
- MENU_3_0 FAR *lp30 = MK_FP(wSel, wOfs);
- MENU_3_1 FAR *lp31 = MK_FP(wSel, wOfs);
-
- return b31 ? lp31->wMagic == MENU_MAGIC
- : (lp30->cbMenu ==
- (((lp30->cItems + 1) * sizeof(ITEM)) + sizeof(MENU_3_0)));
- }
-
- void GetAnyAtomName(WORD wSeg, ATOM nAtom, LPSTR lpBuffer, int nSize)
- {
- _asm push ds;
- _asm mov ds, word ptr wSeg;
- GetAtomName(nAtom, lpBuffer, nSize);
- _asm pop ds;
- }
-
-
- BOOL IsMenuHeap(WORD wSel)
- {
- // This is a terrible hack, but it appears to work!
- return ((MENU_3_1 FAR *) MK_FP(wSel, 0x54))->wMagic == MENU_MAGIC;
- }
-
-