home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 10 / 10.iso / l / l430 / 1.ddi / CHAP8.ZIP / GDIWALK.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-11  |  19.3 KB  |  791 lines

  1. /*
  2.     GDIWALK.C -- GDI Local heap object browser
  3.  
  4.     Copyright (c) Dave Maxey 1992
  5.     
  6.     From Chapter 8 of "Undocumented Windows" (Addison-Wesley 1992)
  7.     by Andrew Schulman, Dave Maxey and Matt Pietrek
  8.  
  9.     Build using: WINIOBC GDIWALK (for Borland C++ v3.00)
  10.                  WINIOMS GDIWALK (for Microsoft C/SDK)
  11. */
  12.  
  13. #include <windows.h>
  14. #include <ctype.h>
  15. #include <stdarg.h>
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include <dos.h>
  19. #include "toolhelp.h"
  20. #include "winio.h"
  21. #include "gdiobj.h"
  22.  
  23. #ifndef __BORLANDC__ 
  24. #define MK_FP(a,b)  ((void far *)(((unsigned long)(a) << 16) | (b))) 
  25. #else 
  26. #define asm _asm 
  27. #endif 
  28.  
  29. typedef struct _LINESTOHEAP
  30.     {
  31.     WORD wHeap;
  32.     int    nFirstLine, nLastLine;
  33.     } LINESTOHEAP;
  34.  
  35. void WalkOneGDIHeap(WORD seg);
  36. void GDIHeapWalk(void);
  37. BOOL ContainsLocalHeap(WORD seg);
  38. void MainWndLine(HWND hwnd, LPSTR line, int lineNum);
  39. void OtherWndLine(HWND hwnd, LPSTR line, int lineNum);
  40. void DumpBlock(WORD wSel, WORD wOfs, WORD wBytes);
  41. void DumpPen(WORD wSel, WORD wOfs, WORD wBytes);
  42. void DumpBrush(WORD wSel, WORD wOfs, WORD wBytes);
  43. void DumpFont(WORD wSel, WORD wOfs, WORD wBytes);
  44. void DumpPalette(WORD wSel, WORD wOfs, WORD wBytes);
  45. void DumpBitmap(WORD wSel, WORD wOfs, WORD wBytes);
  46. void DumpRegion(WORD wSel, WORD wOfs, WORD wBytes);
  47. void DumpDC(WORD wSel, WORD wOfs, WORD wBytes);
  48. void DumpDisabledDC(WORD wSel, WORD wOfs, WORD wBytes);
  49. void DumpMetaDC(WORD wSel, WORD wOfs, WORD wBytes);
  50. void DumpMetaFile(WORD wSel, WORD wOfs, WORD wBytes);
  51. BOOL FarLocalSize(WORD wSel, WORD wH, WORD *pOfs, WORD *pSize);
  52. WORD MyGDIBlockType(WORD wSeg, WORD wOfs, WORD wType);
  53.  
  54. #define ID_REFRESH        1
  55. #define MAXHEAPS        16
  56.  
  57. LINESTOHEAP ltoh[MAXHEAPS] = {0};
  58.  
  59. char szTitle[] = "GDI Heap Walker";
  60. char UnknownString[] = "<UNKNOWN>";
  61. int nLineNum = 0;
  62. int nHeaps;
  63. BOOL bDebug, b31;
  64.  
  65. char *GDIBlockType[] =
  66. {
  67. "NORMAL",               // 0
  68. "Pen",                  // 1
  69. "Brush",                // 2
  70. "Font",                 // 3
  71. "Palette",              // 4
  72. "Bitmap",               // 5
  73. "Region",               // 6
  74. "DC",                   // 7
  75. "Disabled DC",          // 8
  76. "Meta DC",              // 9
  77. "Metafile",             // 10
  78. "Metafile DC"           // 11
  79. };
  80.  
  81. #define BLOCKTYPES (sizeof(GDIBlockType) / sizeof(char *))
  82.  
  83.  
  84. typedef void (* fnDUMP)(WORD wSel, WORD wOfs, WORD wBytes);
  85.  
  86. fnDUMP fnDump[] =
  87.     { DumpBlock, DumpPen, DumpBrush, DumpFont, DumpPalette, DumpBitmap,
  88.         DumpRegion, DumpDC, DumpDisabledDC, DumpMetaDC, DumpMetaFile,
  89.         DumpDC, DumpBlock };
  90.  
  91. #define    WINDOWSIZE(y, x) \
  92.     ((DWORD) ((DWORD) ((unsigned)(y)) << 16) | ((unsigned)(x)))
  93.  
  94. POINT pntSize[] = {
  95.     { 76, -1 },
  96.     { 44, 9 },
  97.     { 46, 13 },
  98.     { 45, 21 },
  99.     { 50, 10 },
  100.     { 48, 9 },
  101.     { 76, -1 },
  102.     { 47, 25 },
  103.     { 47, 10 },
  104.     { 50, 25 },
  105.     { 50, 10 },
  106.     { 47, 25 },
  107.     { 76, -1 }
  108.     };
  109.     
  110. typedef struct {
  111.     char *szField;
  112.     int iType;
  113.     } HFIELD;
  114.  
  115. HFIELD hfld[] = {
  116.     { "hMetaFile", 10 }, { "hrgnClip", 6 }, { "hLPen", 1 },
  117.     { "hLBrush", 2 }, { "hLFont", 3 }, { "hBitmap", 5 },
  118.     { "dchPal", 4 }, { "hrgnVisSave", 6 }, { "hdc", 7 } };
  119.  
  120. #define MAXHFIELDS        (sizeof(hfld) / sizeof(HFIELD))
  121.     
  122. WORD verr(WORD sel)
  123.     {
  124.     _asm mov ax, 1
  125.     _asm verr word ptr sel
  126.     _asm je short ok
  127.     _asm dec ax
  128.     ok:;
  129.     }
  130.  
  131. WORD lsl(WORD wSel)
  132.     {
  133.     _asm sub ax, ax
  134.     _asm lsl ax, wSel
  135.     }
  136.  
  137.  
  138. void DumpHeader(LPGDIOBJHDR goh)
  139.     {
  140.     if (b31)
  141.         {
  142.         printf(
  143.             "GDIOBJHDR:\n"
  144.             "\thNext\t\t: %04X\n"
  145.             "\twMagic\t\t: %04X (\"%c%c\")\n"
  146.             "\tdwCount\t\t: %ld\n"
  147.             "\twMetaList\t: %04X\n",
  148.             goh->hNext, goh->wMagic,
  149.             goh->wMagic & 0xff, goh->wMagic >> 8,
  150.             goh->dwCount, goh->wMetaList);
  151.         if (bDebug)
  152.             printf(
  153.                 "\twSelCount\t: %d\n"
  154.                 "\thOwner\t\t: %04X\n",
  155.                 ((LPGDIOBJDBG) goh)->wSelCount,
  156.                 ((LPGDIOBJDBG) goh)->hOwner);
  157.         }
  158.     else
  159.         {
  160.         printf(
  161.             "GDIOBJHDR:\n"
  162.             "\twFlags\t\t: %04X\n"
  163.             "\twObjType\t: %d\n"
  164.             "\tdwCount\t\t: %ld\n"
  165.             "\twMetaList\t: %04X\n",
  166.             goh->hNext, goh->wMagic & 0xff,
  167.             goh->dwCount, goh->wMetaList);
  168.         }
  169.         
  170.     }
  171.  
  172. void DumpPen(WORD wSel, WORD wOfs, WORD wBytes)
  173.     {
  174.     LPPENOBJ fp = (LPPENOBJ) MK_FP(wSel, wOfs);
  175.     
  176.     DumpHeader((LPGDIOBJHDR) &(fp->header));
  177.     if (bDebug && b31) (DWORD) fp += 4;
  178.     printf(
  179.         "LOGPEN:\n"
  180.         "\tlopnStyle\t: %04X\n"
  181.         "\tlopnWidth\t: (%d, %d)\n"
  182.         "\tlopnColor\t: %08lX\n",
  183.         fp->logpen.lopnStyle,
  184.         fp->logpen.lopnWidth.x,
  185.         fp->logpen.lopnWidth.y,
  186.         fp->logpen.lopnColor);
  187.     }
  188.  
  189. void DumpBrush(WORD wSel, WORD wOfs, WORD wBytes)
  190.     {
  191.     LPBRUSHOBJ fp = (LPBRUSHOBJ) MK_FP(wSel, wOfs);
  192.     
  193.     DumpHeader((LPGDIOBJHDR) &(fp->header));
  194.     if (bDebug && b31) (DWORD) fp += 4;
  195.     printf(
  196.         "LOGBRUSH:\n"
  197.         "\tlbStyle\t\t: %04X\n"
  198.         "\tlbColor\t\t: %08lX\n"
  199.         "\tlbHatch\t\t: %04X\n",
  200.         fp->logbrush.lbStyle,
  201.         fp->logbrush.lbColor,
  202.         fp->logbrush.lbHatch);
  203.     printf("crHatchBk\t\t: %08lX\n", fp->crHatchBk);
  204.     }
  205.  
  206. void DumpFont(WORD wSel, WORD wOfs, WORD wBytes)
  207.     {
  208.     LPFONTOBJ fp = (LPFONTOBJ) MK_FP(wSel, wOfs);
  209.     
  210.     DumpHeader((LPGDIOBJHDR) &(fp->header));
  211.     if (bDebug && b31) (DWORD) fp += 4;
  212.     printf(
  213.         "LOGFONT:\n"
  214.         "\tlfHeight\t: %d\n"
  215.         "\tlfWidth\t\t: %d\n"
  216.         "\tlfEscapement\t: %d\n"
  217.         "\tlfOrientation\t: %d\n"
  218.         "\tlfWeight\t: %d\n"
  219.         "\tlfItalic\t: %d\n"
  220.         "\tlfUnderline\t: %d\n"
  221.         "\tlfStrikeOut\t: %d\n"
  222.         "\tlfCharSet\t: %d\n"
  223.         "\tlfOutPrecision\t: %d\n"
  224.         "\tlfClipPrecision\t: %d\n"
  225.         "\tlfQuality\t: %d\n"
  226.         "\tlfPitchAndFamily: %04X\n"
  227.         "\tlfFaceName\t: %Fs\n",
  228.         fp->logfont.lfHeight,
  229.         fp->logfont.lfWidth,
  230.         fp->logfont.lfEscapement,
  231.         fp->logfont.lfOrientation,
  232.         fp->logfont.lfWeight,
  233.         fp->logfont.lfItalic,
  234.         fp->logfont.lfUnderline,
  235.         fp->logfont.lfStrikeOut,
  236.         fp->logfont.lfCharSet,
  237.         fp->logfont.lfOutPrecision,
  238.         fp->logfont.lfClipPrecision,
  239.         fp->logfont.lfQuality,
  240.         fp->logfont.lfPitchAndFamily,
  241.         (LPSTR) &(fp->logfont.lfFaceName));
  242.     }
  243.  
  244. void DumpPalette(WORD wSel, WORD wOfs, WORD wBytes)
  245.     {
  246.     WORD i;
  247.     LPPALETTEOBJ fp = (LPPALETTEOBJ) MK_FP(wSel, wOfs);
  248.     
  249.     DumpHeader((LPGDIOBJHDR) &(fp->header));
  250.     if (bDebug && b31) (DWORD) fp += 4;
  251.     printf(
  252.         "LOGPALETTE:\n"
  253.         "\tpalVersion\t: %4X\n"
  254.         "\tpalNumEntries\t: %d\n",
  255.         fp->logpalette.palVersion,
  256.         fp->logpalette.palNumEntries);
  257.     for (i = 0; i < fp->logpalette.palNumEntries; i++)
  258.         printf("\tpalPalEntry[%d]\t: %08lX\n",
  259.             i, *((DWORD FAR *) &(fp->logpalette.palPalEntry[i])));
  260.     }
  261.  
  262. void DumpBitmap(WORD wSel, WORD wOfs, WORD wBytes)
  263.     {
  264.     LPBITMAPOBJ fp = (LPBITMAPOBJ) MK_FP(wSel, wOfs);
  265.     
  266.     printf("Lines marked '->' may be double clicked\nfor expansion\n\n");
  267.     DumpHeader((LPGDIOBJHDR) &(fp->header));
  268.     if (bDebug) (DWORD) fp += 4;
  269.     printf(
  270.         "LOGBITMAP:\n"
  271.         "\thmemBitmap\t: %04X\n"
  272.         "\tbSelected\t: %04X\n"
  273.         "\th0E\t\t: %04X\n",
  274.         fp->hmemBitmap,
  275.         fp->bSelected,
  276.         fp->h0E);
  277.     }
  278.  
  279. void DumpRegion(WORD wSel, WORD wOfs, WORD wBytes)
  280.     {
  281.     DumpBlock(wSel, wOfs, wBytes);
  282.     }
  283.  
  284. void DumpDC(WORD wSel, WORD wOfs, WORD wBytes)
  285.     {
  286.     LPDC fp = (LPDC) MK_FP(wSel, wOfs);
  287.     
  288.     printf("Lines marked '->' may be double clicked\nfor expansion\n\n");
  289.     DumpHeader((LPGDIOBJHDR) &(fp->header));
  290.     if (bDebug && b31) (DWORD) fp += 4;
  291.     printf(
  292.         "DC:\n"
  293.         "\tbyFlags\t\t: %02X\n"
  294.         "\tbyFlags2\t: %02X\n"
  295.         "->\thMetaFile\t: %04X\n"
  296.         "->\thrgnClip\t: %04X\n"
  297.         "\thPDevice\t: %04X\n"
  298.         "->\thLPen\t\t: %04X\n"
  299.         "->\thLBrush\t\t: %04X\n"
  300.         "->\thLFont\t\t: %04X\n"
  301.         "->\thBitmap\t\t: %04X\n"
  302.         "->\tdchPal\t\t: %04X\n"
  303.         "\thLDevice\t: %04X\n"
  304.         "\thRaoClip\t: %04X\n"
  305.         "\thPDeviceBlock\t: %04X\n"
  306.         "\thPPen\t\t: %04X\n"
  307.         "\thPBrush\t\t: %04X\n"
  308.         "\thPFontTrans\t: %04X\n"
  309.         "\thPFont\t\t: %04X\n"
  310.         "\tlpPDevice\t: %Fp\n"
  311.         "\tpLDevice\t: %04X\n"
  312.         "\tpRaoClip\t: %04X\n",
  313.         fp->byFlags, fp->byFlags2, fp->hMetaFile, fp->hrgnClip,
  314.         fp->hPDevice, fp->hLPen, fp->hLBrush, fp->hLFont,
  315.         fp->hBitmap, fp->dchPal, fp->hLDevice, fp->hRaoClip,
  316.         fp->hPDeviceBlock, fp->hPPen, fp->hPBrush, fp->hPFontTrans,
  317.         fp->hPFont, fp->lpPDevice, fp->pLDevice,
  318.         fp->pRaoClip);
  319.         
  320.     printf(
  321.         "\tpPDeviceBlock\t: %04X\n"
  322.         "\tpPPen\t\t: %04X\n"
  323.         "\tpPBrush\t\t: %04X\n"
  324.         "\tpPFontTrans\t: %04X\n"
  325.         "\tlpPFont\t\t: %Fp\n"
  326.         "\tnPFTIndex\t: %04X\n"
  327.         "\tfnTransform\t: %Fp\n"
  328.         "\twROP2\t\t: %04X\n"
  329.         "\twBkMode\t\t: %04X\n"
  330.         "\tdwBkColor\t: %08lX\n"
  331.         "\tdwTextColor\t: %08lX\n"
  332.         "\tnTBreakExtra\t: %d\n"
  333.         "\tnBreakExtra\t: %d\n"
  334.         "\twBreakErr\t: %04X\n"
  335.         "\tnBreakRem\t: %d\n"
  336.         "\tnBreakCount\t: %d\n"
  337.         "\tnCharExtra\t: %d\n"
  338.         "\tcrLbkColor\t: %08lX\n"
  339.         "\tcrLTextColor\t: %08lX\n"
  340.         "\tLCursPosX\t: %d\n"
  341.         "\tLCursPosY\t: %d\n",
  342.         fp->pPDeviceBlock, fp->pPPen, fp->pPBrush, fp->pPFontTrans,
  343.         fp->lpPFont, fp->nPFTIndex, fp->Transform, fp->wROP2,
  344.         fp->wBkMode, fp->dwBkColor, fp->dwTextColor, fp->nTBreakExtra,
  345.         fp->nBreakExtra, fp->wBreakErr, fp->nBreakRem, fp->nBreakCount,
  346.         fp->nCharExtra, fp->crLbkColor, fp->crLTextColor, fp->LCursPosX,
  347.         fp->LCursPosY);
  348.         
  349.     printf(
  350.         "\tWndOrgX\t\t: %d\n"
  351.         "\tWndOrgX\t\t: %d\n"
  352.         "\tWndExtX\t\t: %d\n"
  353.         "\tWndExtY\t\t: %d\n"
  354.         "\tVportOrgX\t: %d\n"
  355.         "\tVportOrgY\t: %d\n"
  356.         "\tVportExtX\t: %d\n"
  357.         "\tVportExtY\t: %d\n"
  358.         "\tUserVptOrgX\t: %d\n"
  359.         "\tUserVptOrgY\t: %d\n"
  360.         "\twMapMode\t: %04X\n"
  361.         "\twXFormFlags\t: %04X\n"
  362.         "\twRelAbs\t\t: %04X\n"
  363.         "\twPolyFillMode\t: %04X\n"
  364.         "\twStretchBltMode\t: %04X\n"
  365.         "\tbyPlanes\t: %d\n"
  366.         "\tbyBitsPix\t: %d\n"
  367.         "\twPenWidth\t: %d\n"
  368.         "\twPenHeight\t: %d\n"
  369.         "\twTextAlign\t: %04X\n"
  370.         "\tdwMapperFlags\t: %08lX\n",
  371.         fp->WndOrgX, fp->WndOrgX, fp->WndExtX, fp->WndExtY,
  372.         fp->VportOrgX, fp->VportOrgY, fp->VportExtX, fp->VportExtY,
  373.         fp->UserVptOrgX, fp->UserVptOrgY, fp->wMapMode, fp->wXFormFlags,
  374.         fp->wRelAbs, fp->wPolyFillMode, fp->wStretchBltMode, fp->byPlanes,
  375.         fp->byBitsPix, fp->wPenWidth, fp->wPenHeight, fp->wTextAlign,
  376.         fp->dwMapperFlags);
  377.         
  378.     printf(
  379.         "\twBrushOrgX\t: %d\n"
  380.         "\twBrushOrgY\t: %d\n"
  381.         "\twFontAspectX\t: %d\n"
  382.         "\twFontAspectY\t: %d\n"
  383.         "\thFontWeights\t: %d\n"
  384.         "\twDCSaveLevel\t: %d\n"
  385.         "\twcDCLocks\t: %d\n"
  386.         "->\thVisRgn\t\t: %04X\n"
  387.         "\twDCOrgX\t\t: %d\n"
  388.         "\twDCOrgY\t\t: %d\n"
  389.         "\tlpfnPrint\t: %Fp\n"
  390.         "\twDCLogAtom\t: %04X\n"
  391.         "\twDCPhysAtom\t: %04X\n"
  392.         "\twDCFileAtom\t: %04X\n"
  393.         "\twPostScaleX\t: %d\n"
  394.         "\twPostScaleY\t: %d\n",
  395.         fp->wBrushOrgX, fp->wBrushOrgY,
  396.         fp->wFontAspectX, fp->wFontAspectY,
  397.         fp->hFontWeights, fp->wDCSaveLevel,
  398.         fp->wcDCLocks, fp->hVisRgn,
  399.         fp->wDCOrgX, fp->wDCOrgY, fp->lpfnPrint, fp->wDCLogAtom,
  400.         fp->wDCPhysAtom, fp->wDCFileAtom,
  401.         fp->wPostScaleX, fp->wPostScaleY);
  402.     if (b31)
  403.         {
  404.         printf(
  405.             "\trectBounds\t: (%d, %d, %d, %d)\n"
  406.             "\trectLVB\t\t: (%d, %d, %d, %d)\n"
  407.             "\tlpfnNotify\t: %Fp\n"
  408.             "\tlpHookData\t: %Fp\n"
  409.             "\twDCGlobFlags\t: %04X\n",
  410.             fp->dc_tail.tail_3_1.rectBounds.left,
  411.             fp->dc_tail.tail_3_1.rectBounds.top,
  412.             fp->dc_tail.tail_3_1.rectBounds.right,
  413.             fp->dc_tail.tail_3_1.rectBounds.bottom,
  414.             fp->dc_tail.tail_3_1.rectLVB.left,
  415.             fp->dc_tail.tail_3_1.rectLVB.top,
  416.             fp->dc_tail.tail_3_1.rectLVB.right,
  417.             fp->dc_tail.tail_3_1.rectLVB.bottom,
  418.             fp->dc_tail.tail_3_1.lpfnNotify,
  419.             fp->dc_tail.tail_3_1.lpHookData,
  420.             fp->dc_tail.tail_3_1.wDCGlobFlags);
  421.         if (bDebug)
  422.             printf(
  423.                 "\thDCNext\t\t: %04X\n",
  424.                 fp->dc_tail.tail_3_1.hDCNext);
  425.         }
  426.     else
  427.         {
  428.         printf(
  429.             "\twB4\t\t: %04X\n"
  430.             "\trectB6\t\t: (%d, %d, %d, %d)\n"
  431.             "\twDCGlobFlags\t: %04X\n"
  432.             "\twC0\t\t: %04X\n",
  433.             fp->dc_tail.tail_3_0.wB4,
  434.             fp->dc_tail.tail_3_0.rectB6.left,
  435.             fp->dc_tail.tail_3_0.rectB6.top,
  436.             fp->dc_tail.tail_3_0.rectB6.right,
  437.             fp->dc_tail.tail_3_0.rectB6.bottom,
  438.             fp->dc_tail.tail_3_0.wDCGlobFlags,
  439.             fp->dc_tail.tail_3_0.wC0);
  440.         }
  441.     }
  442.  
  443. void DumpDisabledDC(WORD wSel, WORD wOfs, WORD wBytes)
  444.     {
  445.     DumpBlock(wSel, wOfs, wBytes);
  446.     }
  447.  
  448. void DumpMetaDC(WORD wSel, WORD wOfs, WORD wBytes)
  449.     {
  450.     DumpBlock(wSel, wOfs, wBytes);
  451.     }
  452.  
  453.  
  454.  
  455. void DumpMetaFile(WORD wSel, WORD wOfs, WORD wBytes)
  456.     {
  457.     DumpBlock(wSel, wOfs, wBytes);
  458.     }
  459.  
  460.  
  461. #define WIDTH 16
  462.  
  463. void DumpBlock(WORD wSel, WORD wOfs, WORD wBytes)
  464.     {
  465.     LPSTR fp, p;
  466.     WORD i, j, c;
  467.     
  468.     fp = MK_FP(wSel, wOfs);
  469.     
  470.     for (i=0; i<wBytes; i += WIDTH)
  471.         {
  472.         c = ((wBytes-i) > WIDTH) ? WIDTH : wBytes-i;
  473.         printf("%04X | ", i);
  474.         for (j=c, p=fp+i; j--; p++)
  475.             printf("%02X ", (unsigned char) *p);
  476.         for (j=WIDTH-c; j--; )  // pad out on last line
  477.             printf("   ");
  478.         putchar('|'); putchar(' ');
  479.         for (j=c, p=fp+i; j--; p++)
  480.             putchar( isprint(*p) ? *p : '.' );
  481.         putchar('\n');
  482.         }
  483.     }
  484.  
  485.  
  486. void DispatchDump(char *typ, WORD wH, WORD wSel, WORD wOfs, WORD wBytes)
  487.     {
  488.     WORD wLimit;
  489.     char buf[80];
  490.     HWND hwndNew, hwndSav;
  491.     int i;
  492.     DWORD dwSave;
  493.  
  494.     wSel &= ~3;
  495.     wSel |= 1;
  496.     
  497.     if (! verr(wSel))
  498.         {
  499.         winio_warn(FALSE, "GDI Walker", "%04x no longer valid\n", wSel);
  500.         return;
  501.         }
  502.     if ((wLimit = lsl(wSel)) < wOfs)
  503.         {
  504.         winio_warn(FALSE, "GDI Walker",
  505.             "Start offs %04X is outside selector %04X limit of %04X\n",
  506.             wOfs, wSel, wLimit);
  507.         return;
  508.         }
  509.     if ((wLimit + 1) < (wBytes + wOfs))
  510.         {
  511.         winio_warn(FALSE, "GDI Walker",
  512.             "Selector %04X limit is %04X, length of dump adjusted\n",
  513.             wSel, wLimit);
  514.         wBytes = wLimit - wOfs + 1;
  515.         }
  516.     
  517.     for (i = 0; i < BLOCKTYPES; i++)
  518.         if (strcmp(typ, GDIBlockType[i]) == 0) break;
  519.  
  520.     sprintf(buf, "%s handle %04X @ %04X:%04X for %d bytes",
  521.         typ, wH, wSel, wOfs, wBytes);
  522.     
  523.     if ((hwndNew = FindWindow(NULL, buf)) != NULL)
  524.         {
  525.         ShowWindow(hwndNew, SW_RESTORE);
  526.         BringWindowToTop(hwndNew);
  527.         return;
  528.         }
  529.  
  530.     // Use the table entry for window size. If the entry has a
  531.     // y size of -1, it means it is a dump, and we use the amount
  532.     // of data to display to determine the y size.
  533.     dwSave = winio_defwindowsize(
  534.         WINDOWSIZE( ((pntSize[i].y == -1)
  535.             ? min(20, (wBytes + 15) / 16) : pntSize[i].y),
  536.             pntSize[i].x));
  537.     
  538.     if (! (hwndNew = winio_window(buf, min(wBytes * 20, 1024), WW_HASMENU)))
  539.         {
  540.         winio_warn(FALSE, "Dump", "Insufficient resources!");
  541.         return;
  542.         }
  543.     
  544.     winio_defwindowsize(dwSave);
  545.     
  546.     hwndSav = winio_setcurrent(hwndNew);
  547.     
  548.     winio_setpaint(hwndNew, FALSE);
  549.     
  550.     // there is an extra entry in the fnDump table to allow for when
  551.     // the type was not in the GDIBlockType table
  552.     (* (fnDump[i]))(wSel, wOfs, wBytes);
  553.     
  554.     winio_setlinefn(hwndNew, OtherWndLine);
  555.     winio_setpaint(hwndNew, TRUE);
  556.     winio_home(hwndNew);
  557.     winio_setcurrent(hwndSav);
  558.  
  559. //    GDIHeapWalk();
  560.     }
  561.  
  562.     
  563. void MainWndLine(HWND hwnd, LPSTR line, int lineNum)
  564.     {
  565.     WORD wSel, wH, wOfs, wBytes;
  566.     char typ[20];
  567.     char buf[80];
  568.     int i;
  569.     
  570.     for (i = 0; i < nHeaps; i++)
  571.         if (lineNum < ltoh[i].nFirstLine)
  572.             return;
  573.         else
  574.         if (lineNum < ltoh[i].nLastLine)
  575.             break;
  576.     
  577.     wSel = ltoh[i].wHeap;
  578.     
  579.     lstrcpy(buf, line);
  580.     
  581.     if (sscanf(buf, "%04X    %04X  %04X  %s", &wH, &wOfs, &wBytes, &typ) < 1)
  582.         return;
  583.     
  584.     DispatchDump(typ, wH, wSel, wOfs, wBytes);
  585.     }
  586.  
  587.  
  588.  
  589. void OtherWndLine(HWND hwnd, LPSTR line, int lineNum)
  590.     {
  591.     WORD wSel, wH, wOfs, wBytes;
  592.     char typ[20];
  593.     char buf[80];
  594.     int i;
  595.     
  596.     if ((*line++ != '-') || (*line++ != '>')) return;
  597.     
  598.     GetWindowText(hwnd, (LPSTR) &buf, sizeof(buf));
  599.     sscanf(buf, "%s handle %04X @ %04X:%04X for %d bytes",
  600.         &typ, &wH, &wSel, &wOfs, &wBytes);
  601.  
  602.     lstrcpy(buf, line);
  603.     
  604.     if (sscanf(buf, "      %s : %04X", &typ, &wH) < 1)
  605.         return;
  606.     
  607.     if (! wH)
  608.         {
  609.         winio_warn(FALSE, szTitle, "NULL handle!");
  610.         return;
  611.         }
  612.  
  613.     for (i = 0; i < MAXHFIELDS; i++)
  614.         if (strcmp(hfld[i].szField, typ) == 0)
  615.             break;
  616.     if (i == MAXHFIELDS) return;
  617.     
  618.     if (! FarLocalSize(wSel, wH, &wOfs, &wBytes))
  619.         {
  620.         winio_warn(FALSE, szTitle, "Handle %04X in GDI heap %04X\n"
  621.             "is no longer valid.", wH, wSel);
  622.         GDIHeapWalk();
  623.         }
  624.     else
  625.         DispatchDump(GDIBlockType[hfld[i].iType], wH, wSel, wOfs, wBytes);
  626.     }
  627.  
  628.  
  629.  
  630. char *GetGDIBlockType(WORD type)
  631.     {
  632.     // only default GDI local heap gets ToolHelp GDI subtypes;
  633.     // use signatures to show for the rest?
  634.         
  635.     if ( type <= (BLOCKTYPES - 1) /* LT_GDI_MAX */ )
  636.         return GDIBlockType[type];
  637.  
  638.     if ( type == 0xFF )
  639.         return "FREE";
  640.  
  641.     return UnknownString;
  642.     }
  643.     
  644. void WalkOneGDIHeap(WORD seg)
  645.     {
  646.     LOCALENTRY le;
  647.     BOOL ok;
  648.     
  649.     if (! seg) return;
  650.  
  651.     seg &= 0xfffc;
  652.     seg |= 1;
  653.     
  654.     printf(
  655.         "GDI heap in segment %04xh:\n"
  656.         "(Double-click to view a block)\n"
  657.         "HANDLE  ADDR  SIZE  TYPE\n",
  658.         seg);
  659.     nLineNum += 4;
  660.     
  661.     ltoh[nHeaps].wHeap = seg;
  662.     ltoh[nHeaps].nFirstLine = nLineNum;
  663.     
  664.     le.dwSize = sizeof(le);
  665.     ok = LocalFirst(&le, seg);
  666.  
  667.     while ( ok )
  668.         {
  669.         nLineNum++;
  670.         printf
  671.             (
  672.             "%04X    %04X  %04X  %s\n",
  673.             le.hHandle, le.wAddress, le.wSize,
  674.             GetGDIBlockType(MyGDIBlockType(seg, le.wAddress, le.wType))
  675.             );
  676.  
  677.         ok = LocalNext(&le);
  678.         }
  679.     ltoh[nHeaps++].nLastLine = nLineNum;
  680.     printf("\n");
  681.     nLineNum++;
  682.     }
  683.  
  684. void GDIHeapWalk(void)
  685.     {
  686.     GLOBALENTRY ge;
  687.     BOOL ok;
  688.     HANDLE hGDI = GetModuleHandle("GDI");
  689.     SYSHEAPINFO shi;
  690.  
  691.     winio_clear(__hMainWnd);
  692.  
  693.     // Turn off repaints to minimize Heisenberg effects on heap
  694.         
  695.     winio_setbusy();
  696.     winio_setpaint(__hMainWnd, FALSE);
  697.  
  698.     nHeaps = 0;
  699.     nLineNum = 0;
  700.     SystemHeapInfo(&shi);
  701.     WalkOneGDIHeap(shi.hGDISegment);
  702.     printf("\n");
  703.     ge.dwSize = sizeof(ge);
  704.     ok = GlobalFirst(&ge, GLOBAL_ALL);
  705.     
  706.     while ( ok )
  707.         {
  708.         if (ge.hOwner == hGDI)
  709.             {
  710.             if (ContainsLocalHeap(ge.hBlock) &&
  711.                     (ge.hBlock != shi.hGDISegment))
  712.                 {
  713.                 WalkOneGDIHeap(ge.hBlock);
  714.                 printf("\n");
  715.                 }
  716.             }
  717.         ok = GlobalNext(&ge, GLOBAL_ALL);
  718.         }
  719.  
  720.     // Turn repaints back on, and position at the top of the info
  721.     winio_setpaint(__hMainWnd, TRUE);
  722.     winio_resetbusy();
  723.     winio_home(__hMainWnd);
  724.     }
  725.  
  726.  
  727. int main(int argc, char *argv[] )
  728.     {
  729.     b31 = HIBYTE(GetVersion());
  730.     bDebug = GetSystemMetrics(SM_DEBUG);
  731.  
  732.     winio_about("GDIWALK"
  733.         "\nGDI Local heap object browser"
  734.         "\n\nFrom Chapter 8 of"
  735.         "\n\"Undocumented Windows\" (Addison-Wesley, 1992)"
  736.         "\nby Andrew Schulman, David Maxey and Matt Pietrek"
  737.         );
  738.     
  739.     winio_settitle(__hMainWnd, szTitle);
  740.     winio_setbufsize(__hMainWnd, (WORD) 65530, FALSE);
  741.     GDIHeapWalk();
  742.     winio_setmenufunc(__hMainWnd, ID_REFRESH, (MENU_FUNC) GDIHeapWalk);
  743.     InsertMenu(winio_hmenumain(__hMainWnd), 1,
  744.         MF_ENABLED | MF_STRING | MF_BYPOSITION,
  745.         ID_REFRESH, "&Refresh!");
  746.     DrawMenuBar(__hMainWnd);
  747.     winio_setlinefn(__hMainWnd, MainWndLine);
  748.     
  749.     return 0;
  750.     }
  751.  
  752. // We can rely on ToolHelp to tell us whether a block contains a
  753. // valid local heap; all the homebrew validity checks are not needed here
  754. BOOL ContainsLocalHeap(WORD seg)
  755.     {
  756.     LOCALENTRY le;
  757.     le.dwSize = sizeof(le);
  758.     return LocalFirst(&le, seg);
  759.     }
  760.  
  761.  
  762. BOOL FarLocalSize(WORD wSel, WORD wH, WORD *pOfs, WORD *pSize)
  763.     {
  764.     LOCALENTRY le;
  765.     BOOL ok;
  766.     
  767.     le.dwSize = sizeof(le);
  768.     ok = LocalFirst(&le, wSel);
  769.  
  770.     while (ok && (le.hHandle != wH))
  771.         ok = LocalNext(&le);
  772.     if (ok)
  773.         {
  774.         *pOfs = le.wAddress;
  775.         *pSize = le.wSize;
  776.         }
  777.     return ok;
  778.     }
  779.  
  780. WORD MyGDIBlockType(WORD wSeg, WORD wOfs, WORD wType)
  781.     {
  782.     LPGDIOBJHDR lp = (LPGDIOBJHDR) MK_FP(wSeg, wOfs);
  783.     
  784.     if (wType) return wType;
  785.     
  786.     if (((lp->wMagic & 0x4f1f) == 0x4f1f) && ((lp->wMagic & 0x1f) == 11))
  787.         return 11;
  788.     
  789.     return 0;
  790.     }
  791.