text: /***************************** Module Header ******************************\
  * Module Name: conexts.c
  *
  * Copyright (c) 1985 - 1999, Microsoft Corporation
  *
  * This module contains random debugging related functions.
  *
  \***************************************************************************/
  
  
  #include "precomp.h"
  #pragma hdrstop
  #define NOEXTAPI
  #include <wdbgexts.h>
  
  /***************************************************************************\
  * Global variables
  \***************************************************************************/
  PSTR pszAccessViolation = "CONEXTS: Access violation on \"%s\", switch to server context\n";
  PSTR pszMoveException   = "CONEXTS: exception in move()\n";
  PSTR pszReadFailure     = "CONEXTS: moveBlock(%x, %x, %x) failed!\n";
  
  /***************************************************************************\
  * Macros
  \***************************************************************************/
  #define move(dst, src)  moveBlock(dst, src, sizeof(dst))
  
  #define moveBlock(dst, src, size)                                                                     \
  try {                                                                                                 \
      if (lpExtensionApis->nSize >= sizeof(WINDBG_EXTENSION_APIS)) {                                    \
          if (!(*lpExtensionApis->lpReadProcessMemoryRoutine)((DWORD_PTR)(src), &(dst), (size), NULL)) {    \
              (*lpExtensionApis->lpOutputRoutine)(pszReadFailure, &dst, src, size);                     \
              return FALSE;                                                                             \
           }                                                                                            \
      } else {                                                                                          \
          if (!NT_SUCCESS(NtReadVirtualMemory(hCurrentProcess, (LPVOID)(src), &(dst), (size), NULL))) { \
              (*lpExtensionApis->lpOutputRoutine)(pszReadFailure, &dst, src, size);                     \
              return FALSE;                                                                             \
          }                                                                                             \
      }                                                                                                 \
  } except (EXCEPTION_EXECUTE_HANDLER) {                                                                \
      (*lpExtensionApis->lpOutputRoutine)(pszMoveException);                                            \
      return FALSE;                                                                                     \
  }
  
  #define moveExpressionValue(dst, src)                                 \
  try {                                                                 \
      DWORD dwGlobal = (DWORD)lpExtensionApis->lpGetExpressionRoutine(src);    \
      if (lpExtensionApis->nSize < sizeof(WINDBG_EXTENSION_APIS)) {     \
          move(dwGlobal, dwGlobal);                                     \
      }                                                                 \
      (DWORD)dst = dwGlobal;                                            \
  } except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?          \
              EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {  \
      (*lpExtensionApis->lpOutputRoutine)(pszAccessViolation, src);     \
      return FALSE;                                                     \
  }
  
  #define moveExpressionValuePtr(dst, src)                              \
  try {                                                                 \
      DWORD_PTR dwGlobal = lpExtensionApis->lpGetExpressionRoutine(src);\
      if (lpExtensionApis->nSize < sizeof(WINDBG_EXTENSION_APIS)) {     \
          move(dwGlobal, dwGlobal);                                     \
      }                                                                 \
      (DWORD_PTR)dst = dwGlobal;                                        \
  } except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?          \
              EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {  \
      (*lpExtensionApis->lpOutputRoutine)(pszAccessViolation, src);     \
      return FALSE;                                                     \
  }
  
  #define moveExpressionAddress(dst, src)                               \
  try {                                                                 \
      if (lpExtensionApis->nSize >= sizeof(WINDBG_EXTENSION_APIS)) {    \
          (DWORD_PTR)dst = lpExtensionApis->lpGetExpressionRoutine("&"src); \
      } else {                                                          \
          (DWORD_PTR)dst = lpExtensionApis->lpGetExpressionRoutine(src);    \
      }                                                                 \
  } except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?          \
              EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {  \
      (*lpExtensionApis->lpOutputRoutine)(pszAccessViolation, src);     \
      return FALSE;                                                     \
  }
  
  BOOL DebugConvertToAnsi(
      HANDLE hCurrentProcess,
      PWINDBG_EXTENSION_APIS lpExtensionApis,
      LPWSTR psrc,
      ULONG cbSrc,
      LPSTR pdst,
      ULONG cbDst)
  {
      WCHAR awch[80];
      ULONG cchText;
  
      cbSrc = min(cbSrc, sizeof(awch) - sizeof(WCHAR));
      moveBlock(awch, psrc, cbSrc);
      awch[cbSrc/sizeof(WCHAR)] = 0;
  
      cchText = wcslen(awch);
      if (cchText == 0) {
          strcpy(pdst, "<null>");
      } else {
          cbSrc = min(cbSrc + sizeof(WCHAR), (cchText + 1) * sizeof(WCHAR));
          RtlUnicodeToMultiByteN(pdst, cbDst, NULL,
                  awch, cbSrc);
          pdst[cbDst-1] = 0;
      }
      return TRUE;
  }
  
  BOOL gbShowFlagNames = FALSE;
  
  #define NO_FLAG (LPSTR)0xFFFFFFFF  // use this for non-meaningful entries.
  
  #define GF_CONSOLE  1
  LPSTR apszConsoleFlags[] = {
     "CONSOLE_IS_ICONIC"              , // 0x000001
     "CONSOLE_OUTPUT_SUSPENDED"       , // 0x000002
     "CONSOLE_HAS_FOCUS"              , // 0x000004
     "CONSOLE_IGNORE_NEXT_MOUSE_INPUT", // 0x000008
     "CONSOLE_SELECTING"              , // 0x000010
     "CONSOLE_SCROLLING"              , // 0x000020
     "CONSOLE_DISABLE_CLOSE"          , // 0x000040
     "CONSOLE_NOTIFY_LAST_CLOSE"      , // 0x000080
     "CONSOLE_NO_WINDOW"              , // 0x000100
     "CONSOLE_VDM_REGISTERED"         , // 0x000200
     "CONSOLE_UPDATING_SCROLL_BARS"   , // 0x000400
     "CONSOLE_QUICK_EDIT_MODE"        , // 0x000800
     "CONSOLE_TERMINATING"            , // 0x001000
     "CONSOLE_CONNECTED_TO_EMULATOR"  , // 0x002000
     "CONSOLE_FULLSCREEN_NOPAINT"     , // 0x004000
     "CONSOLE_SHUTTING_DOWN"          , // 0x008000
     "CONSOLE_AUTO_POSITION"          , // 0x010000
     "CONSOLE_IGNORE_NEXT_KEYUP"      , // 0x020000
     "CONSOLE_WOW_REGISTERED"         , // 0x040000
     "CONSOLE_USE_PRIVATE_FLAGS"      , // 0x080000
     "CONSOLE_HISTORY_NODUP"          , // 0x100000
     "CONSOLE_SCROLLBAR_TRACKING"     , // 0x200000
     "CONSOLE_IN_DESTRUCTION"         , // 0x400000
     "CONSOLE_SETTING_WINDOW_SIZE"    , // 0x800000
     "CONSOLE_DEFAULT_BUFFER_SIZE"    , // 0x0100000
      NULL                              // no more
  };
  
  #define GF_CONSOLESEL  2
  LPSTR apszConsoleSelectionFlags[] = {
     "CONSOLE_SELECTION_NOT_EMPTY"    , // 1
     "CONSOLE_MOUSE_SELECTION"        , // 2
     "CONSOLE_MOUSE_DOWN"             , // 4
     "CONSOLE_SELECTION_INVERTED"     , // 8
     NULL                               // no more
  };
  
  #define GF_FULLSCREEN  3
  LPSTR apszFullScreenFlags[] = {
     "CONSOLE_FULLSCREEN",             // 0
     "CONSOLE_FULLSCREEN_HARDWARE",    // 1
     NULL
  };
  
  #define GF_CMDHIST     4
  LPSTR apszCommandHistoryFlags[] = {
     "CLE_ALLOCATED",                  // 0x01
     "CLE_RESET",                      // 0x02
     NULL
  };
  
  
  /*
   * Converts a 32bit set of flags into an appropriate string.
   * pszBuf should be large enough to hold this string, no checks are done.
   * pszBuf can be NULL, allowing use of a local static buffer but note that
   * this is not reentrant.
   * Output string has the form: " = FLAG1 | FLAG2 ..."
   */
  LPSTR GetFlags(
  WORD wType,
  DWORD dwFlags,
  LPSTR pszBuf)
  {
      static char szT[400];
      DWORD i;
      BOOL fFirst = TRUE;
      BOOL fNoMoreNames = FALSE;
      LPSTR *apszFlags;
  
      if (pszBuf == NULL) {
          pszBuf = szT;
      }
      *pszBuf = '\0';
  
      if (!gbShowFlagNames) {
          return(pszBuf);
      }
  
      switch (wType) {
      case GF_CONSOLE:
          apszFlags = apszConsoleFlags;
          break;
  
      case GF_CONSOLESEL:
          apszFlags = apszConsoleSelectionFlags;
          break;
  
      case GF_FULLSCREEN:
          apszFlags = apszFullScreenFlags;
          break;
  
      case GF_CMDHIST:
          apszFlags = apszCommandHistoryFlags;
          break;
  
      default:
          strcpy(pszBuf, " = Invalid flag type.");
          return(pszBuf);
      }
  
      for (i = 0; dwFlags; dwFlags >>= 1, i++) {
  
          if (!fNoMoreNames && (apszFlags[i] == NULL)) {
              fNoMoreNames = TRUE;
          }
          if (dwFlags & 1) {
              if (!fFirst) {
                  strcat(pszBuf, " | ");
              } else {
                  strcat(pszBuf, " = ");
                  fFirst = FALSE;
              }
              if (fNoMoreNames || (apszFlags[i] == NO_FLAG)) {
                  char ach[16];
                  sprintf(ach, "0x%lx", 1 << i);
                  strcat(pszBuf, ach);
              } else {
                  strcat(pszBuf, apszFlags[i]);
              }
          }
      }
      return pszBuf;
  }
  
  
  /***************************************************************************\
  * help - list help for debugger extensions in CONEXTS.
  *
  *
  * 04-Feb-1994 IanJa     Created.
  \***************************************************************************/
  
  BOOL help(
      HANDLE hCurrentProcess,
      HANDLE hCurrentThread,
      DWORD dwCurrentPc,
      PWINDBG_EXTENSION_APIS lpExtensionApis,
      LPSTR lpArgumentString)
  {
      PWINDBG_OUTPUT_ROUTINE Print;
      PWINDBG_GET_EXPRESSION EvalExpression;
      PWINDBG_GET_SYMBOL GetSymbol;
  
      UNREFERENCED_PARAMETER(hCurrentProcess);
      UNREFERENCED_PARAMETER(hCurrentThread);
      UNREFERENCED_PARAMETER(dwCurrentPc);
  
      Print = lpExtensionApis->lpOutputRoutine;
      EvalExpression = lpExtensionApis->lpGetExpressionRoutine;
      GetSymbol = lpExtensionApis->lpGetSymbolRoutine;
  
      while (*lpArgumentString == ' ')
          lpArgumentString++;
  
      if (*lpArgumentString == '\0') {
          Print("conexts help:\n\n");
          Print("!help [cmd]            - this list, or details about cmd\n");
          Print("!dc [fvh] [pconsole]   - Dump CONSOLE_INFORMATION struct\n");
          Print("!dch <p>               - Dump Command History\n");
          Print("!dcpt [address]        - Dump CPTABLEINFO (default: GlyphCP)\n");
          Print("!dmem [v] [pconsole]   - Dump memory usage\n");
          Print("!df                    - Dump font cache\n");
          Print("!di <p>                - Dump input buffer info\n");
          Print("!dir <p>               - Dump input record ???\n");
          Print("!ds <pscreen>          - Dump SCREEN_INFORMATION struct\n");
          Print("!dt [f] [v[n]] <pcon>  - Dump screen buffer info\n");
      } else {
          if (*lpArgumentString == '!')
              lpArgumentString++;
          if (strcmp(lpArgumentString, "df") == 0) {
              Print("!df         - dumps Faces and then the cache\n");
  
          } else if (strcmp(lpArgumentString, "dc") == 0) {
              Print("!dc [fhv]          - dumps CONSOLE_INFORMATION struct for all consoles\n");
              Print("!dc [fhv] address  - dumps CONSOLE_INFORMATION struct for console at address\n");
              Print("   optional flags (must be sparated by spaces) :\n");
              Print("     f - show names of flags\n");
              Print("     h - show command histories\n");
              Print("     v - show verbose information\n");
              Print("eg: \"dc f h v\"\n");
  
          } else if (strcmp(lpArgumentString, "dt") == 0) {
              Print("!dt [fc] [v[n]] addr - dumps text buffer info for Console at addr\n");
              Print("!dt                  - dumps text buffer info for all Consoles\n");
              Print("  f    - show flags\n");
              Print("  c    - checks text buffer integrity\n");
              Print("  v[n] - show first n lines (default 10)\n");
  
          } else if (strcmp(lpArgumentString, "di") == 0) {
              Print("!di address - dumps text buffer info (INPUT_INFORMATION)\n");
              Print("!di         - dumps text buffer info for all Consoles\n");
  
          } else if (strcmp(lpArgumentString, "ds") == 0) {
              Print("!ds address - dumps SCREEN_INFORMATION struct at address\n");
  
          } else if (strcmp(lpArgumentString, "dmem") == 0) {
              Print("!dmem [v]       - dumps memory usage for all consoles\n");
              Print("!dmem [v] addr  - dumps memory usage for all console at addr\n");
              Print("     v - show verbose information\n");
  
          }
      }
  
      return 0;
  }
  
  BOOL dch(HANDLE, HANDLE, DWORD, PWINDBG_EXTENSION_APIS, LPSTR);
  
  /***************************************************************************\
  * dc - Dump Console - dump CONSOLE_INFORMATION struct
  *
  * dc address    - dumps simple info for console at address
  *                 (takes handle too)
  \***************************************************************************/
  
  BOOL dc(
      HANDLE hCurrentProcess,
      HANDLE hCurrentThread,
      DWORD dwCurrentPc,
      PWINDBG_EXTENSION_APIS lpExtensionApis,
      LPSTR lpArgString)
  {
      PWINDBG_OUTPUT_ROUTINE Print;
      PWINDBG_GET_EXPRESSION EvalExpression;
      PWINDBG_GET_SYMBOL GetSymbol;
  
      char ach[120];
      char chVerbose, chShowFlags, chHistory;
      BOOL fPrintLine;
      ULONG i;
      ULONG NumberOfConsoleHandles;
      PCONSOLE_INFORMATION *ConsoleHandles;
      CONSOLE_INFORMATION Console;
      PCONSOLE_INFORMATION pConsole = NULL;
  
      Print = lpExtensionApis->lpOutputRoutine;
      EvalExpression = lpExtensionApis->lpGetExpressionRoutine;
      GetSymbol = lpExtensionApis->lpGetSymbolRoutine;
  
      gbShowFlagNames = FALSE;
      chVerbose   = ' ';
      chShowFlags = ' ';
      chHistory = ' ';
  
      do {
          /*
           * Skip white space
           */
          while (*lpArgString && *lpArgString == ' ')
              lpArgString++;
  
          /*
           * f : show flags
           */
          switch (*lpArgString) {
          case 'f': // show flags
              gbShowFlagNames = TRUE;
              chShowFlags = 'f';
              break;
  
          case 'v':
              chVerbose = 'v';
              break;
  
          case 'h':
              chHistory = 'h';
              break;
  
          case '\0':
              /*
               * If no console is specified, loop through all of them
               */
              moveExpressionValue(NumberOfConsoleHandles,
                                  "winsrv!NumberOfConsoleHandles");
              moveExpressionValuePtr(ConsoleHandles,
                                  "winsrv!ConsoleHandles");
              fPrintLine = FALSE;
              for (i = 0; i < NumberOfConsoleHandles; i++) {
                  move(pConsole, ConsoleHandles);
                  if (pConsole != NULL) {
                      if (fPrintLine)
                          Print("==========================================\n");
                      sprintf(ach, "%c %c %c %p", chVerbose, chShowFlags, chHistory, pConsole);
                      dc(hCurrentProcess, hCurrentThread, dwCurrentPc, lpExtensionApis, ach);
                      fPrintLine = TRUE;
                  }
                  ConsoleHandles++;
              }
              return TRUE;
  
          default:
              pConsole = (PCONSOLE_INFORMATION)EvalExpression(lpArgString);
              break;
          }
          lpArgString++;
  
      } while (pConsole == NULL);
  
      move(Console, pConsole);
  
      DebugConvertToAnsi(hCurrentProcess,
                         lpExtensionApis,
                         Console.Title,
                         Console.TitleLength,
                         ach,
                         sizeof(ach));
      Print("PCONSOLE @ 0x%lX   \"%s\"\n", pConsole, ach);
  
      if (chHistory == 'h') {
          PLIST_ENTRY ListHead, ListNext;
          LIST_ENTRY ListEntry;
          PCOMMAND_HISTORY History;
  
          ListHead = &(pConsole->CommandHistoryList);
          ListNext = Console.CommandHistoryList.Flink;
          while (ListNext != ListHead) {
              History = CONTAINING_RECORD( ListNext, COMMAND_HISTORY, ListLink );
              sprintf(ach, "%p", History);
              dch(hCurrentProcess, hCurrentThread, dwCurrentPc,
                      lpExtensionApis, ach);
              move(ListEntry, ListNext);
              ListNext = ListEntry.Flink;
              Print("----\n");
          }
          return TRUE;
      }
  
      Print("\t pConsoleLock           0x%08lX\n"
            "\t RefCount               0x%04lX\n"
            "\t WaitCount              0x%04lX\n"
            "\t pInputBuffer           0x%08lX\n"
            "\t pCurrentScreenBuffer   0x%08lX\n"
            "\t pScreenBuffers         0x%08lX\n"
            "\t hWnd                   0x%08lX\n"
            "\t hDC                    0x%08lX\n"
            "\t LastAttributes         0x%04lX\n",
            &pConsole->ConsoleLock,
            Console.RefCount,
            Console.WaitCount,
            &pConsole->InputBuffer,
            Console.CurrentScreenBuffer,
            Console.ScreenBuffers,
            Console.hWnd,
            Console.hDC,
            Console.LastAttributes);
  
      Print("\t Flags                  0x%08lX%s\n",
            Console.Flags, GetFlags(GF_CONSOLE, Console.Flags, NULL));
      Print("\t FullScreenFlags        0x%04lX%s\n",
            Console.FullScreenFlags,
            GetFlags(GF_FULLSCREEN, Console.FullScreenFlags, NULL));
      Print("\t ConsoleHandle          0x%08lX\n"
            "\t CtrlFlags              0x%08lX\n",
            Console.ConsoleHandle,
            Console.CtrlFlags
            );
  
      if (chVerbose == 'v') {
          Print("\t hMenu                  0x%08lX\n"
                "\t hHeirMenu              0x%08lX\n"
                "\t hSysPalette            0x%08lX\n"
                "\t WindowRect.L T R B     0x%08lX 0x%08lX 0x%08lX 0x%08lX\n"
                "\t ResizeFlags            0x%08lX\n"
                "\t OutputQueue.F B        0x%08lX 0x%08lX\n"
                "\t InitEvents[]           0x%08lX 0x%08lX\n"
                "\t ClientThreadHandle     0x%08lX\n"
                "\t ProcessHandleList.F B  0x%08lX 0x%08lX\n"
                "\t CommandHistoryList.F B 0x%08lX 0x%08lX\n"
                "\t ExeAliasList.F B       0x%08lX 0x%08lX\n",
                Console.hMenu,
                Console.hHeirMenu,
                Console.hSysPalette,
                Console.WindowRect.left,
                Console.WindowRect.top,
                Console.WindowRect.right,
                Console.WindowRect.bottom,
                Console.ResizeFlags,
                Console.OutputQueue.Flink,
                Console.OutputQueue.Blink,
                Console.InitEvents[0],
                Console.InitEvents[1],
                Console.ClientThreadHandle,
                Console.ProcessHandleList.Flink,
                Console.ProcessHandleList.Blink,
                Console.CommandHistoryList.Flink,
                Console.CommandHistoryList.Blink,
                Console.ExeAliasList.Flink,
                Console.ExeAliasList.Blink
                );
          DebugConvertToAnsi(hCurrentProcess,
                             lpExtensionApis,
                             Console.OriginalTitle,
                             Console.OriginalTitleLength,
                             ach,
                             sizeof(ach)
                             );
          Print("\t NumCommandHistories    0x%04lX\n"
                "\t MaxCommandHistories    0x%04lX\n"
                "\t CommandHistorySize     0x%04lX\n"
                "\t OriginalTitleLength    0x%04lX\n"
                "\t TitleLength            0x%04lX\n"
                "\t OriginalTitle          %s\n"
                "\t dwHotKey               0x%08lX\n"
                "\t hIcon                  0x%08lX\n"
                "\t iIcondId               0x%08lX\n"
                "\t ReserveKeys            0x%02lX\n"
                "\t WaitQueue              0x%08lX\n",
                Console.NumCommandHistories,
                Console.MaxCommandHistories,
                Console.CommandHistorySize,
                Console.OriginalTitleLength,
                Console.TitleLength,
                ach,
                Console.dwHotKey,
                Console.hIcon,
                Console.iIconId,
                Console.ReserveKeys,
                Console.WaitQueue
                );
          Print("\t SelectionFlags         0x%08lX%s\n"
                "\t SelectionRect.L T R B  0x%04lX 0x%04lX 0x%04lX 0x%04lX\n"
                "\t SelectionAnchor.X Y    0x%04lX 0x%04lX\n"
                "\t TextCursorPosition.X Y 0x%04lX 0x%04lX\n"
                "\t TextCursorSize         0x%08lX\n"
                "\t TextCursorVisible      0x%02lX\n"
                "\t InsertMode             0x%02lX\n"
                "\t wShowWindow            0x%04lX\n"
                "\t dwWindowOriginX        0x%08lX\n"
                "\t dwWindowOriginY        0x%08lX\n"
                "\t PopupCount             0x%04lX\n",
                Console.SelectionFlags,
                GetFlags(GF_CONSOLESEL, Console.SelectionFlags, NULL),
                Console.SelectionRect.Left,
                Console.SelectionRect.Top,
                Console.SelectionRect.Right,
                Console.SelectionRect.Bottom,
                Console.SelectionAnchor.X,
                Console.SelectionAnchor.Y,
                Console.TextCursorPosition.X,
                Console.TextCursorPosition.Y,
                Console.TextCursorSize,
                Console.TextCursorVisible,
                Console.InsertMode,
                Console.wShowWindow,
                Console.dwWindowOriginX,
                Console.dwWindowOriginY,
                Console.PopupCount
                );
          Print("\t VDMStartHardwareEvent  0x%08lX\n"
                "\t VDMEndHardwareEvent    0x%08lX\n"
                "\t VDMProcessHandle       0x%08lX\n"
                "\t VDMProcessId           0x%08lX\n"
                "\t VDMBufferSectionHandle 0x%08lX\n"
                "\t VDMBuffer              0x%08lX\n"
                "\t VDMBufferClient        0x%08lX\n"
                "\t VDMBufferSize.X Y      0x%04lX 0x%04lX\n"
                "\t StateSectionHandle     0x%08lX\n"
                "\t StateBuffer            0x%08lX\n"
                "\t StateBufferClient      0x%08lX\n"
                "\t StateLength            0x%08lX\n",
                Console.VDMStartHardwareEvent,
                Console.VDMEndHardwareEvent,
                Console.VDMProcessHandle,
                Console.VDMProcessId,
                Console.VDMBufferSectionHandle,
                Console.VDMBuffer,
                Console.VDMBufferClient,
                Console.VDMBufferSize.X,
                Console.VDMBufferSize.Y,
                Console.StateSectionHandle,
                Console.StateBuffer,
                Console.StateBufferClient,
                Console.StateLength
                );
          Print("\t CP                     0x%08lX\n"
                "\t OutputCP               0x%08lX\n"
                "\t hWndProgMan            0x%08lX\n"
                "\t bIconInit              0x%08lX\n"
                "\t LimitingProcessId      0x%08lX\n"
                "\t TerminationEvent       0x%08lX\n"
                "\t VerticalClientToWin    0x%04lX\n"
                "\t HorizontalClientToWin  0x%04lX\n",
                Console.CP,
                Console.OutputCP,
                Console.hWndProgMan,
                Console.bIconInit,
                Console.LimitingProcessId,
                Console.TerminationEvent,
                Console.VerticalClientToWindow,
                Console.HorizontalClientToWindow
                );
  #if defined(FE_SB)
          Print("\t EudcInformation        0x%08lX\n"
                "\t FontCacheInformation   0x%08lX\n",
                Console.EudcInformation,
                Console.FontCacheInformation
                );
  #if defined(FE_IME)
          Print("\tConsoleIme:\n"
                "\t ScrollFlag             0x%08lX\n"
                "\t ScrollWaitTimeout      0x%08lX\n"
                "\t ScrollWaitCountDown    0x%08lX\n"
                "\t CompStrData            0x%08lX\n"
                "\t ConvAreaMode           0x%08lX\n"
                "\t ConvAreaSystem         0x%08lX\n"
                "\t NumberOfConvAreaCompStr 0x%08lX\n"
                "\t ConvAreaCompStr         0x%08lX\n"
                "\t ConvAreaRoot           0x%08lX\n",
                Console.ConsoleIme.ScrollFlag,
                Console.ConsoleIme.ScrollWaitTimeout,
                Console.ConsoleIme.ScrollWaitCountDown,
                Console.ConsoleIme.CompStrData,
                Console.ConsoleIme.ConvAreaMode,
                Console.ConsoleIme.ConvAreaSystem,
                Console.ConsoleIme.NumberOfConvAreaCompStr,
                Console.ConsoleIme.ConvAreaCompStr,
                Console.ConsoleIme.ConvAreaRoot
                );
  #endif
  #endif
      }
      return TRUE;
  }
  
  /***************************************************************************\
  * dt - Dump Text - dump text buffer information
  *
  * dt address    - dumps text buffer information  for console at address
  *
  \***************************************************************************/
  
  BOOL dt(
      HANDLE hCurrentProcess,
      HANDLE hCurrentThread,
      DWORD dwCurrentPc,
      PWINDBG_EXTENSION_APIS lpExtensionApis,
      LPSTR lpArgString)
  {
      PWINDBG_OUTPUT_ROUTINE Print;
      PWINDBG_GET_EXPRESSION EvalExpression;
      PWINDBG_GET_SYMBOL GetSymbol;
  
      char ach[120];
      BOOL fPrintLine;
      ULONG i, nLines;
      SHORT sh;
      ULONG NumberOfConsoleHandles;
      PCONSOLE_INFORMATION *ConsoleHandles;
      CONSOLE_INFORMATION Console;
      SCREEN_INFORMATION Screen;
      PCONSOLE_INFORMATION pConsole;
      DWORD FrameBufPtr;
      char chVerbose = ' ';
      char chShowFlags = ' ';
      char chCheck = ' ';
      PROW pRow;
  
      Print = lpExtensionApis->lpOutputRoutine;
      EvalExpression = lpExtensionApis->lpGetExpressionRoutine;
      GetSymbol = lpExtensionApis->lpGetSymbolRoutine;
  
  
      /*
       * Get arguments
       */
      pConsole = NULL;
      do {
          /*
           * Skip white space
           */
          while (*lpArgString && *lpArgString == ' ')
              lpArgString++;
  
          switch (*lpArgString) {
          case 'f':
              gbShowFlagNames = TRUE;
              chShowFlags = 'f';
              break;
  
          case 'c':
              chCheck = 'c';
              break;
  
          case 'v':
              chVerbose = 'v';
              nLines = 0;
              lpArgString++;
              while ((*lpArgString >= '0') && (*lpArgString <= '9')) {
                  nLines *= 10;
                  nLines += *lpArgString - '0';
                  lpArgString++;
              }
              lpArgString--;
              if (nLines == 0) {
                  nLines = 10;
              }
              break;
  
          case '\0':
              /*
               * If no console is specified, dt all of them
               */
              moveExpressionValue(NumberOfConsoleHandles,
                                  "winsrv!NumberOfConsoleHandles");
              moveExpressionValuePtr(ConsoleHandles,
                                  "winsrv!ConsoleHandles");
              fPrintLine = FALSE;
              for (i = 0; i < NumberOfConsoleHandles; i++) {
                  move(pConsole, ConsoleHandles);
                  if (pConsole != NULL) {
                      if (fPrintLine)
                          Print("==========================================\n");
                      sprintf(ach, "%c %c %p", chVerbose, chShowFlags, pConsole);
                      if (!dt(hCurrentProcess, hCurrentThread,
                                       dwCurrentPc, lpExtensionApis, ach)) {
                          return FALSE;
                      }
                      fPrintLine = TRUE;
                  }
                  ConsoleHandles++;
              }
              return TRUE;
  
          default:
              pConsole = (PCONSOLE_INFORMATION)EvalExpression(lpArgString);
              break;
          }
          lpArgString++;
      } while (pConsole == NULL);
  
      move(Console, pConsole);
  
      Print("PCONSOLE @ 0x%lX\n", pConsole);
      DebugConvertToAnsi(hCurrentProcess,
                         lpExtensionApis,
                         Console.Title,
                         Console.TitleLength,
                         ach,
                         sizeof(ach));
      Print("\t Title                %s\n"
            "\t pCurrentScreenBuffer 0x%08lX\n"
            "\t pScreenBuffers       0x%08lX\n"
            "\t VDMBuffer            0x%08lx\n"
            "\t CP %d,  OutputCP %d\n",
            ach,
            Console.CurrentScreenBuffer,
            Console.ScreenBuffers,
            Console.VDMBuffer,
            Console.CP,
            Console.OutputCP
            );
  
      moveExpressionValue(FrameBufPtr, "winsrv!FrameBufPtr");
      move(Screen, Console.CurrentScreenBuffer);
      if (Screen.Flags & CONSOLE_TEXTMODE_BUFFER) {
          Print("\t TextInfo.Rows         0x%08X\n"
                "\t TextInfo.TextRows     0x%08X\n"
                "\t TextInfo.FirstRow     0x%08X\n"
                "\t FrameBufPtr           0x%08X\n",
                Screen.BufferInfo.TextInfo.Rows,
                Screen.BufferInfo.TextInfo.TextRows,
                Screen.BufferInfo.TextInfo.FirstRow,
                FrameBufPtr);
      }
  
      pRow = Screen.BufferInfo.TextInfo.Rows;
      if (chCheck) {
          Print("Checking BufferInfo...\n");
          for (sh = 0; sh < Screen.ScreenBufferSize.Y; sh++) {
              ROW Row;
              move(Row, pRow);
  
              /*
               * Check that Attrs points to the in-place AttrPair if there
               * if only one AttrPair for this Row.
               */
              if (Row.AttrRow.Length == 1) {
                  if (Row.AttrRow.Attrs != &(pRow->AttrRow.AttrPair)) {
                      Print("Bad Row[%lx]:  Attrs %lx should be %lx\n",
                          sh, Row.AttrRow.Attrs, pRow->AttrRow.AttrPair);
                  }
              }
  
              /*
               * Some other checks?
               */
  
              pRow++;
          }
          Print("...check completed\n");
      }
  
      if (chVerbose == ' ') {
          return TRUE;
      }
  
      pRow = Screen.BufferInfo.TextInfo.Rows;
      for (i = 0; i < nLines; i++) {
          ROW Row;
          move(Row, pRow);
  
          DebugConvertToAnsi(hCurrentProcess,
                             lpExtensionApis,
                             Row.CharRow.Chars,
                             -1,
                             ach,
                             sizeof(ach));
          Print("Row %2d: %4x %4x, %4x %4x, %lx:\"%.40s\"\n",
              i,
              (USHORT)Row.CharRow.Right, (USHORT)Row.CharRow.OldRight,
              (USHORT)Row.CharRow.Left, (USHORT)Row.CharRow.OldLeft,
              Row.CharRow.Chars, ach);
          Print("      %4x %4x,%04x or %lx\n",
              (USHORT)Row.AttrRow.Length,
              (USHORT)Row.AttrRow.AttrPair.Length,
              (WORD)Row.AttrRow.AttrPair.Attr,
              Row.AttrRow.Attrs);
          pRow++;
      }
      return TRUE;
  }
  
  /***************************************************************************\
  * df - Dump Font - dump Font information
  *
  * df address    - dumps simple info for console at address
  *                 (takes handle too)
  \***************************************************************************/
  
  BOOL df(
      HANDLE hCurrentProcess,
      HANDLE hCurrentThread,
      DWORD dwCurrentPc,
      PWINDBG_EXTENSION_APIS lpExtensionApis,
      LPSTR lpArgumentString)
  {
      PWINDBG_OUTPUT_ROUTINE Print;
      PWINDBG_GET_EXPRESSION EvalExpression;
      PWINDBG_GET_SYMBOL GetSymbol;
      BYTE Buff[sizeof(FACENODE) + (LF_FACESIZE * sizeof(WCHAR))];
      PFACENODE pFN;
  
      DWORD NumberOfFonts;
      DWORD FontInfoLength;
      FONT_INFO FontInfo;
      PFONT_INFO pFontInfo;
      DWORD dw;
  
      UNREFERENCED_PARAMETER(hCurrentProcess);
      UNREFERENCED_PARAMETER(hCurrentThread);
      UNREFERENCED_PARAMETER(dwCurrentPc);
  
      Print = lpExtensionApis->lpOutputRoutine;
      EvalExpression = lpExtensionApis->lpGetExpressionRoutine;
      GetSymbol = lpExtensionApis->lpGetSymbolRoutine;
  
  
      /*
       * Skip space
       */
  
      while (*lpArgumentString == ' ')
          lpArgumentString++;
  
  
      Print("Faces:\n");
      moveExpressionValuePtr(pFN, "winsrv!gpFaceNames");
      while (pFN != 0) {
          move(Buff, pFN);
          pFN = (PFACENODE)Buff;
          Print(" \"%ls\"\t%s %s %s %s %s %s\n",
                &pFN->awch[0],
                pFN->dwFlag & EF_NEW        ? "NEW"        : "   ",
                pFN->dwFlag & EF_OLD        ? "OLD"        : "   ",
                pFN->dwFlag & EF_ENUMERATED ? "ENUMERATED" : "          ",
                pFN->dwFlag & EF_OEMFONT    ? "OEMFONT"    : "       ",
                pFN->dwFlag & EF_TTFONT     ? "TTFONT"     : "      ",
                pFN->dwFlag & EF_DEFFACE    ? "DEFFACE"    : "       ");
          pFN = pFN->pNext;
      }
  
      moveExpressionValue(FontInfoLength, "winsrv!FontInfoLength");
      moveExpressionValue(NumberOfFonts, "winsrv!NumberOfFonts");
      moveExpressionValuePtr(pFontInfo, "winsrv!FontInfo");
  
      Print("0x%lx fonts cached, 0x%lx allocated:\n", NumberOfFonts, FontInfoLength);
  
      for (dw = 0; dw < NumberOfFonts; dw++, pFontInfo++) {
          WCHAR FaceName[LF_FACESIZE];
          move(FontInfo, pFontInfo);
          move(FaceName, FontInfo.FaceName);
          Print("%04x hFont    0x%08lX \"%ls\"\n"
                "     SizeWant (%d;%d)\n"
                "     Size     (%d;%d)\n"
                "     Family   %02X\n"
                "     Weight   0x%08lX\n",
                dw,
                FontInfo.hFont,
                FaceName,
                FontInfo.SizeWant.X, FontInfo.SizeWant.Y,
                FontInfo.Size.X, FontInfo.Size.Y,
                FontInfo.Family,
                FontInfo.Weight);
  #if defined(FE_SB)
          Print("     CharSet  0x%02X\n",
                FontInfo.tmCharSet);
  #endif
      }
  
      return TRUE;
  }
  
  /***************************************************************************\
  * di - Dump Input - dump input buffer
  *
  * di address    - dumps simple info for input at address
  *
  \***************************************************************************/
  
  BOOL di(
      HANDLE hCurrentProcess,
      HANDLE hCurrentThread,
      DWORD dwCurrentPc,
      PWINDBG_EXTENSION_APIS lpExtensionApis,
      LPSTR lpArgumentString)
  {
      PWINDBG_OUTPUT_ROUTINE Print;
      PWINDBG_GET_EXPRESSION EvalExpression;
      PWINDBG_GET_SYMBOL GetSymbol;
  
      INPUT_INFORMATION Input;
      PINPUT_INFORMATION pInput;
  
      PCONSOLE_INFORMATION pConsole;
      ULONG NumberOfConsoleHandles;
      PCONSOLE_INFORMATION *ConsoleHandles;
      BOOL fPrintLine;
      ULONG i;
      char ach[120];
  
      Print = lpExtensionApis->lpOutputRoutine;
      EvalExpression = lpExtensionApis->lpGetExpressionRoutine;
      GetSymbol = lpExtensionApis->lpGetSymbolRoutine;
  
  
      /*
       * Skip with space
       */
  
      while (*lpArgumentString == ' ')
          lpArgumentString++;
  
      /*
       * If no INPUT_INFORMATION is specified, dt all of them
       */
      if (*lpArgumentString == 0) {
          moveExpressionValue(NumberOfConsoleHandles,
                              "winsrv!NumberOfConsoleHandles");
          moveExpressionValuePtr(ConsoleHandles,
                              "winsrv!ConsoleHandles");
          fPrintLine = FALSE;
          for (i = 0; i < NumberOfConsoleHandles; i++) {
              move(pConsole, ConsoleHandles);
              if (pConsole != NULL) {
                  if (fPrintLine)
                      Print("---\n");
                  pInput = &pConsole->InputBuffer;
  #ifdef _WIN64
                  _i64toa((ULONG64)pInput, ach, 16);
  #else
                  _itoa((ULONG)pInput, ach, 16);
  #endif
                  if (!di(hCurrentProcess, hCurrentThread, dwCurrentPc, lpExtensionApis, ach)) {
                      return FALSE;
                  }
                  fPrintLine = TRUE;
              }
              ConsoleHandles++;
          }
          return TRUE;
      } else {
          pInput = (PINPUT_INFORMATION)EvalExpression(lpArgumentString);
      }
  
      move(Input, pInput);
  
      Print("PINPUT @ 0x%lX\n", pInput);
      Print("\t pInputBuffer         0x%08lX\n"
            "\t InputBufferSize      0x%08lX\n"
            "\t AllocatedBufferSize  0x%08lX\n"
            "\t InputMode            0x%08lX\n"
            "\t RefCount             0x%08lX\n"
            "\t First                0x%08lX\n"
            "\t In                   0x%08lX\n"
            "\t Out                  0x%08lX\n"
            "\t Last                 0x%08lX\n"
            "\t ReadWaitQueue.Flink  0x%08lX\n"
            "\t ReadWaitQueue.Blink  0x%08lX\n"
            "\t InputWaitEvent       0x%08lX\n",
            Input.InputBuffer,
            Input.InputBufferSize,
            Input.AllocatedBufferSize,
            Input.InputMode,
            Input.RefCount,
            Input.First,
            Input.In,
            Input.Out,
            Input.Last,
            Input.ReadWaitQueue.Flink,
            Input.ReadWaitQueue.Blink,
            Input.InputWaitEvent
            );
  
      return TRUE;
  }
  /***************************************************************************\
  * dir - Dump Input Record - dump input buffer
  *
  * dir address number    - dumps simple info for input at address
  *
  \***************************************************************************/
  
  BOOL dir(
      HANDLE hCurrentProcess,
      HANDLE hCurrentThread,
      DWORD dwCurrentPc,
      PWINDBG_EXTENSION_APIS lpExtensionApis,
      LPSTR lpArgumentString)
  {
      PWINDBG_OUTPUT_ROUTINE Print;
      PWINDBG_GET_EXPRESSION EvalExpression;
      PWINDBG_GET_SYMBOL GetSymbol;
  
      INPUT_RECORD InputRecord;
      PINPUT_RECORD pInputRecord;
  
      char ach[80];
      int cch;
      LPSTR lpAddress;
      DWORD NumRecords,i;
  
      UNREFERENCED_PARAMETER(hCurrentProcess);
      UNREFERENCED_PARAMETER(hCurrentThread);
      UNREFERENCED_PARAMETER(dwCurrentPc);
  
      Print = lpExtensionApis->lpOutputRoutine;
      EvalExpression = lpExtensionApis->lpGetExpressionRoutine;
      GetSymbol = lpExtensionApis->lpGetSymbolRoutine;
  
  
      /*
       * Skip with space
       */
  
      while (*lpArgumentString == ' ')
          lpArgumentString++;
  
      lpAddress = lpArgumentString;
      while (*lpArgumentString != ' ' && *lpArgumentString != 0)
          lpArgumentString++;
  
      cch = (int)(lpArgumentString - lpAddress);
      if (cch > 79)
          cch = 79;
  
      strncpy(ach, lpAddress, cch);
  
      pInputRecord = (PINPUT_RECORD)EvalExpression(lpAddress);
      NumRecords = (DWORD)EvalExpression(lpArgumentString);
  
      Print("%x PINPUTRECORDs @ 0x%lX\n", NumRecords, pInputRecord);
      for (i=0;i<NumRecords;i++) {
          move(InputRecord, pInputRecord);
  
          switch (InputRecord.EventType) {
              case KEY_EVENT:
                  Print("\t KEY_EVENT\n");
                  if (InputRecord.Event.KeyEvent.bKeyDown)
                      Print("\t  KeyDown\n");
                  else
                      Print("\t  KeyUp\n");
                  Print("\t  wRepeatCount %d\n",
                        InputRecord.Event.KeyEvent.wRepeatCount);
                  Print("\t  wVirtualKeyCode %x\n",
                        InputRecord.Event.KeyEvent.wVirtualKeyCode);
                  Print("\t  wVirtualScanCode %x\n",
                        InputRecord.Event.KeyEvent.wVirtualScanCode);
                  Print("\t  aChar is %c",
                        InputRecord.Event.KeyEvent.uChar.AsciiChar);
                  Print("\n");
                  Print("\t  uChar is %x\n",
                        InputRecord.Event.KeyEvent.uChar.UnicodeChar);
                  Print("\t  dwControlKeyState %x\n",
                        InputRecord.Event.KeyEvent.dwControlKeyState);
                  break;
              case MOUSE_EVENT:
                  Print("\t MOUSE_EVENT\n"
                        "\t   dwMousePosition %x %x\n"
                        "\t   dwButtonState %x\n"
                        "\t   dwControlKeyState %x\n"
                        "\t   dwEventFlags %x\n",
                        InputRecord.Event.MouseEvent.dwMousePosition.X,
                        InputRecord.Event.MouseEvent.dwMousePosition.Y,
                        InputRecord.Event.MouseEvent.dwButtonState,
                        InputRecord.Event.MouseEvent.dwControlKeyState,
                        InputRecord.Event.MouseEvent.dwEventFlags
                       );
  
                  break;
              case WINDOW_BUFFER_SIZE_EVENT:
                  Print("\t WINDOW_BUFFER_SIZE_EVENT\n"
                        "\t   dwSize %x %x\n",
                        InputRecord.Event.WindowBufferSizeEvent.dwSize.X,
                        InputRecord.Event.WindowBufferSizeEvent.dwSize.Y
                       );
                  break;
              case MENU_EVENT:
                  Print("\t MENU_EVENT\n"
                        "\t   dwCommandId %x\n",
                        InputRecord.Event.MenuEvent.dwCommandId
                       );
                  break;
              case FOCUS_EVENT:
                  Print("\t FOCUS_EVENT\n");
                  if (InputRecord.Event.FocusEvent.bSetFocus)
                      Print("\t bSetFocus is TRUE\n");
                  else
                      Print("\t bSetFocus is FALSE\n");
                  break;
              default:
                  Print("\t Unknown event type %x\n",InputRecord.EventType);
                  break;
          }
          pInputRecord++;
      }
      return TRUE;
  }
  
  /***************************************************************************\
  * ds - Dump Screen - dump SCREEN_INFORMATION struct
  *
  * ds address    - dumps simple info for input at address
  *
  \***************************************************************************/
  
  BOOL ds(
      HANDLE hCurrentProcess,
      HANDLE hCurrentThread,
      DWORD dwCurrentPc,
      PWINDBG_EXTENSION_APIS lpExtensionApis,
      LPSTR lpArgumentString)
  {
      PWINDBG_OUTPUT_ROUTINE Print;
      PWINDBG_GET_EXPRESSION EvalExpression;
      PWINDBG_GET_SYMBOL GetSymbol;
  
      SCREEN_INFORMATION Screen;
      PSCREEN_INFORMATION pScreen;
  
      UNREFERENCED_PARAMETER(hCurrentProcess);
      UNREFERENCED_PARAMETER(hCurrentThread);
      UNREFERENCED_PARAMETER(dwCurrentPc);
  
      Print = lpExtensionApis->lpOutputRoutine;
      EvalExpression = lpExtensionApis->lpGetExpressionRoutine;
      GetSymbol = lpExtensionApis->lpGetSymbolRoutine;
  
  
      /*
       * Skip with space
       */
  
      while (*lpArgumentString == ' ')
          lpArgumentString++;
  
  
      pScreen = (PSCREEN_INFORMATION)EvalExpression(lpArgumentString);
      move(Screen, pScreen);
  
      Print("PSCREEN @ 0x%lX\n", pScreen);
      Print("\t pConsole             0x%08lX\n"
            "\t Flags                0x%08lX %s | %s\n"
            "\t OutputMode           0x%08lX\n"
            "\t RefCount             0x%08lX\n"
            "\t ScreenBufferSize.X Y 0x%08X 0x%08X\n"
            "\t Window.L T R B       0x%08X 0x%08X 0x%08X 0x%08X\n"
            "\t ResizingWindow       0x%08X\n",
            Screen.Console,
            Screen.Flags,
            Screen.Flags & CONSOLE_TEXTMODE_BUFFER ? "TEXTMODE" : "GRAPHICS",
            Screen.Flags & CONSOLE_OEMFONT_DISPLAY ? "OEMFONT" : "TT FONT",
            Screen.OutputMode,
            Screen.RefCount,
            (DWORD)Screen.ScreenBufferSize.X,
            (DWORD)Screen.ScreenBufferSize.Y,
            (DWORD)Screen.Window.Left,
            (DWORD)Screen.Window.Top,
            (DWORD)Screen.Window.Right,
            (DWORD)Screen.Window.Bottom,
            Screen.ResizingWindow
            );
      Print("\t Attributes           0x%08X\n"
            "\t PopupAttributes      0x%08X\n"
            "\t WindowMaximizedX     0x%08X\n"
            "\t WindowMaximizedY     0x%08X\n"
            "\t WindowMaximized      0x%08X\n"
            "\t CommandIdLow High    0x%08X 0x%08X\n"
            "\t CursorHandle         0x%08X\n"
            "\t hPalette             0x%08X\n"
            "\t dwUsage              0x%08X\n"
            "\t CursorDisplayCount   0x%08X\n"
            "\t WheelDelta           0x%08X\n",
            Screen.Attributes,
            Screen.PopupAttributes,
            Screen.WindowMaximizedX,
            Screen.WindowMaximizedY,
            Screen.WindowMaximized,
            Screen.CommandIdLow,
            Screen.CommandIdHigh,
            Screen.CursorHandle,
            Screen.hPalette,
            Screen.dwUsage,
            Screen.CursorDisplayCount,
            Screen.WheelDelta
            );
      if (Screen.Flags & CONSOLE_TEXTMODE_BUFFER) {
          Print("\t TextInfo.Rows         0x%08X\n"
                "\t TextInfo.TextRows     0x%08X\n"
                "\t TextInfo.FirstRow     0x%08X\n",
                Screen.BufferInfo.TextInfo.Rows,
                Screen.BufferInfo.TextInfo.TextRows,
                Screen.BufferInfo.TextInfo.FirstRow);
  
          Print("\t TextInfo.CurrentTextBufferFont.FontSize       0x%04X,0x%04X\n"
                "\t TextInfo.CurrentTextBufferFont.FontNumber     0x%08X\n",
                Screen.BufferInfo.TextInfo.CurrentTextBufferFont.FontSize.X,
                Screen.BufferInfo.TextInfo.CurrentTextBufferFont.FontSize.Y,
                Screen.BufferInfo.TextInfo.CurrentTextBufferFont.FontNumber);
  
          Print("\t TextInfo.CurrentTextBufferFont.Family, Weight 0x%08X, 0x%08X\n"
                "\t TextInfo.CurrentTextBufferFont.FaceName       %ls\n"
                "\t TextInfo.CurrentTextBufferFont.FontCodePage   %d\n",
                Screen.BufferInfo.TextInfo.CurrentTextBufferFont.Family,
                Screen.BufferInfo.TextInfo.CurrentTextBufferFont.Weight,
                Screen.BufferInfo.TextInfo.CurrentTextBufferFont.FaceName,
                Screen.BufferInfo.TextInfo.CurrentTextBufferFont.FontCodePage);
  
          if (Screen.BufferInfo.TextInfo.ListOfTextBufferFont != NULL) {
              PTEXT_BUFFER_FONT_INFO pLinkFont;
              TEXT_BUFFER_FONT_INFO  LinkFont;
              ULONG Count = 0;
  
              pLinkFont = Screen.BufferInfo.TextInfo.ListOfTextBufferFont;
  
              while (pLinkFont != 0) {
                  move(LinkFont, pLinkFont);
  
                  Print("\t Link Font #%d\n", Count++);
                  Print("\t  TextInfo.LinkOfTextBufferFont.FontSize       0x%04X,0x%04X\n"
                        "\t  TextInfo.LinkOfTextBufferFont.FontNumber     0x%08X\n",
                        LinkFont.FontSize.X,
                        LinkFont.FontSize.Y,
                        LinkFont.FontNumber);
  
                  Print("\t  TextInfo.LinkOfTextBufferFont.Family, Weight 0x%08X, 0x%08X\n"
                        "\t  TextInfo.LinkOfTextBufferFont.FaceName       %ls\n"
                        "\t  TextInfo.LinkOfTextBufferFont.FontCodePage   %d\n",
                        LinkFont.Family,
                        LinkFont.Weight,
                        LinkFont.FaceName,
                        LinkFont.FontCodePage);
  
                  pLinkFont = LinkFont.NextTextBufferFont;
              }
              Print("\n");
          }
  
          Print("\t TextInfo.ModeIndex         0x%08X\n"
  #ifdef i386
                "\t TextInfo.WindowedWindowSize.X Y 0x%08X 0x%08X\n"
                "\t TextInfo.WindowedScreenSize.X Y 0x%08X 0x%08X\n"
                "\t TextInfo.MousePosition.X Y 0x%08X 0x%08X\n"
  #endif
                "\t TextInfo.Flags             0x%08X\n",
  
                Screen.BufferInfo.TextInfo.ModeIndex,
  #ifdef i386
                Screen.BufferInfo.TextInfo.WindowedWindowSize.X,
                Screen.BufferInfo.TextInfo.WindowedWindowSize.Y,
                Screen.BufferInfo.TextInfo.WindowedScreenSize.X,
                Screen.BufferInfo.TextInfo.WindowedScreenSize.Y,
                Screen.BufferInfo.TextInfo.MousePosition.X,
                Screen.BufferInfo.TextInfo.MousePosition.Y,
  #endif
                Screen.BufferInfo.TextInfo.Flags);
  
          Print("\t TextInfo.CursorVisible        0x%08X\n"
                "\t TextInfo.CursorOn             0x%08X\n"
                "\t TextInfo.DelayCursor          0x%08X\n"
                "\t TextInfo.CursorPosition.X Y   0x%08X 0x%08X\n"
                "\t TextInfo.CursorSize           0x%08X\n"
                "\t TextInfo.CursorYSize          0x%08X\n"
                "\t TextInfo.UpdatingScreen       0x%08X\n",
                Screen.BufferInfo.TextInfo.CursorVisible,
                Screen.BufferInfo.TextInfo.CursorOn,
                Screen.BufferInfo.TextInfo.DelayCursor,
                Screen.BufferInfo.TextInfo.CursorPosition.X,
                Screen.BufferInfo.TextInfo.CursorPosition.Y,
                Screen.BufferInfo.TextInfo.CursorSize,
                Screen.BufferInfo.TextInfo.CursorYSize,
                Screen.BufferInfo.TextInfo.UpdatingScreen);
  
      } else {
          Print("\t GraphicsInfo.BitMapInfoLength 0x%08X\n"
                "\t GraphicsInfo.lpBitMapInfo     0x%08X\n"
                "\t GraphicsInfo.BitMap           0x%08X\n"
                "\t GraphicsInfo.ClientBitMap     0x%08X\n"
                "\t GraphicsInfo.ClientProcess    0x%08X\n"
                "\t GraphicsInfo.hMutex           0x%08X\n"
                "\t GraphicsInfo.hSection         0x%08X\n"
                "\t GraphicsInfo.dwUsage          0x%08X\n",
                Screen.BufferInfo.GraphicsInfo.BitMapInfoLength,
                Screen.BufferInfo.GraphicsInfo.lpBitMapInfo,
                Screen.BufferInfo.GraphicsInfo.BitMap,
                Screen.BufferInfo.GraphicsInfo.ClientBitMap,
                Screen.BufferInfo.GraphicsInfo.ClientProcess,
                Screen.BufferInfo.GraphicsInfo.hMutex,
                Screen.BufferInfo.GraphicsInfo.hSection,
                Screen.BufferInfo.GraphicsInfo.dwUsage
          );
      }
  
      return TRUE;
  }
  
  /***************************************************************************\
  * dcpt - Dump CPTABLEINFO
  *
  * dcpt address    - dumps CPTABLEINFO at address
  * dcpt            - dumps CPTABLEINFO at GlyphCP
  *
  \***************************************************************************/
  
  BOOL dcpt(
      HANDLE hCurrentProcess,
      HANDLE hCurrentThread,
      DWORD dwCurrentPc,
      PWINDBG_EXTENSION_APIS lpExtensionApis,
      LPSTR lpArgumentString)
  {
      PWINDBG_OUTPUT_ROUTINE Print;
      PWINDBG_GET_EXPRESSION EvalExpression;
      PWINDBG_GET_SYMBOL GetSymbol;
  
      PCPTABLEINFO pcpt;
      CPTABLEINFO cpt;
  
      UNREFERENCED_PARAMETER(hCurrentProcess);
      UNREFERENCED_PARAMETER(hCurrentThread);
      UNREFERENCED_PARAMETER(dwCurrentPc);
  
      Print = lpExtensionApis->lpOutputRoutine;
      EvalExpression = lpExtensionApis->lpGetExpressionRoutine;
      GetSymbol = lpExtensionApis->lpGetSymbolRoutine;
  
  
      /*
       * Skip with space
       */
  
      while (*lpArgumentString == ' ')
          lpArgumentString++;
  
      /*
       * If no CPTABLEINFO is specified, use the GlyphCP
       */
      if (*lpArgumentString == 0) {
          lpArgumentString = "winsrv!GlyphCP";
      }
      pcpt = (PCPTABLEINFO)EvalExpression(lpArgumentString);
      move(cpt, pcpt);
  
      Print("CPTABLEINFO @ 0x%lX\n", pcpt);
  
      Print("  CodePage = 0x%x (%d)\n"
            "  MaximumCharacterSize = %x\n"
            "  DefaultChar = %x\n",
            cpt.CodePage, cpt.CodePage,
            cpt.MaximumCharacterSize,
            cpt.DefaultChar);
  
      Print("  UniDefaultChar = 0x%04x\n"
            "  TransDefaultChar = %x\n"
            "  TransUniDefaultChar = 0x%04x\n"
            "  DBCSCodePage = 0x%x (%d)\n",
            cpt.UniDefaultChar,
            cpt.TransDefaultChar,
            cpt.TransUniDefaultChar,
            cpt.DBCSCodePage, cpt.DBCSCodePage);
  
      Print("  LeadByte[MAXIMUM_LEADBYTES] = %04x,%04x,%04x,...\n"
            "  MultiByteTable = %x\n"
            "  WideCharTable = %lx\n"
            "  DBCSRanges = %lx\n"
            "  DBCSOffsets = %lx\n",
            cpt.LeadByte[0], cpt.LeadByte[1], cpt.LeadByte[2],
            cpt.MultiByteTable,
            cpt.WideCharTable,
            cpt.DBCSRanges,
            cpt.DBCSOffsets);
  
      return TRUE;
  }
  
  /***************************************************************************\
  * dch  - Dump Command History
  *
  * dch address    - dumps COMMAND_HISTORY at address
  * dch            - dumps some random COMMAND_HISTORY
  *
  \***************************************************************************/
  
  BOOL dch(
      HANDLE hCurrentProcess,
      HANDLE hCurrentThread,
      DWORD dwCurrentPc,
      PWINDBG_EXTENSION_APIS lpExtensionApis,
      LPSTR lpArgumentString)
  {
      PWINDBG_OUTPUT_ROUTINE Print;
      PWINDBG_GET_EXPRESSION EvalExpression;
      PWINDBG_GET_SYMBOL GetSymbol;
  
      PCOMMAND_HISTORY pCmdHist;
      COMMAND_HISTORY CmdHist;
      PCOMMAND pCmd;
      union {
          COMMAND Cmd;
          WCHAR awch[80];
      } DbgCmd;
  
      int i;
      char ach[120];
  
      UNREFERENCED_PARAMETER(hCurrentThread);
      UNREFERENCED_PARAMETER(dwCurrentPc);
  
      Print = lpExtensionApis->lpOutputRoutine;
      EvalExpression = lpExtensionApis->lpGetExpressionRoutine;
      GetSymbol = lpExtensionApis->lpGetSymbolRoutine;
  
      /*
       * Skip spaces
       */
      while (*lpArgumentString == ' ')
          lpArgumentString++;
  
      /*
       * If no COMMAND_HISTORY is specified, use something ????
       */
      if (*lpArgumentString == 0) {
          Print("must specify address of COMMAND_HISTORY struct\n");
          Print("(a breakpoint on winsrv!AddCommand() may help)\n");
          return FALSE;
      }
  
      pCmdHist = (PCOMMAND_HISTORY)EvalExpression(lpArgumentString);
      move(CmdHist, pCmdHist);
  
      Print("COMMAND_HISTORY @ 0x%lX\n", pCmdHist);
  
      Print("  Flags            = 0x%08lX%s\n",
            CmdHist.Flags,  GetFlags(GF_CMDHIST, CmdHist.Flags, NULL));
      Print("  ListLink.F B     = 0x%08lX 0x%08lX\n",
            CmdHist.ListLink.Flink, CmdHist.ListLink.Blink);
  
      DebugConvertToAnsi(hCurrentProcess,
                         lpExtensionApis,
                         CmdHist.AppName,
                         -1,
                         ach,
                         sizeof(ach));
      Print("  AppName          = %s\n", ach);
  
      Print("  NumberOfCommands = 0x%lx\n"
            "  LastAdded        = 0x%lx\n"
            "  LastDisplayed    = 0x%lx\n"
            "  FirstCommand     = 0x%lx\n"
            "  MaximumNumberOfCommands = 0x%lx\n",
            CmdHist.NumberOfCommands,
            CmdHist.LastAdded,
            CmdHist.LastDisplayed,
            CmdHist.FirstCommand,
            CmdHist.MaximumNumberOfCommands);
  
      Print("  ProcessHandle    = 0x%08lX\n",
            CmdHist.ProcessHandle);
  
      Print("  PopupList.F B    = 0x%08lX 0x%08lX\n",
            CmdHist.PopupList.Flink, CmdHist.PopupList.Blink);
  
      for (i = 0; i < CmdHist.NumberOfCommands; i++) {
          move(pCmd, &(pCmdHist->Commands[i]));
  
          // first get the count of bytes in the string...
          moveBlock(DbgCmd, pCmd, sizeof(DbgCmd.Cmd.CommandLength));
  
          // ...then get the string (and the count of bytes again)
          moveBlock(DbgCmd, pCmd,
                  DbgCmd.Cmd.CommandLength + sizeof(DbgCmd.Cmd.CommandLength));
  
          // DebugConvertToAnsi(hCurrentProcess,lpExtensionApis,
          //         DbgCmd.Cmd.Command, ach);
          DbgCmd.Cmd.CommandLength /= sizeof(WCHAR);
          DbgCmd.Cmd.Command[DbgCmd.Cmd.CommandLength] = L'\0';
          Print("   %03d: %d chars = \"%S\"\n", i,
                  DbgCmd.Cmd.CommandLength,
                  DbgCmd.Cmd.Command);
          if (i == CmdHist.LastAdded) {
              Print("        (Last Added)\n");
          } else if (i == CmdHist.LastDisplayed) {
              Print("        (Last Displayed)\n");
          } else if (i == CmdHist.FirstCommand) {
              Print("        (First Command)\n");
          }
      }
  
      return TRUE;
  }
  
  /***************************************************************************\
  * dmem - Dump Memory Usage
  \***************************************************************************/
  
  #define HEAP_GRANULARITY    8
  #define HEAP_SIZE(Size)     (((Size) + (HEAP_GRANULARITY - 1) + HEAP_GRANULARITY) & ~(HEAP_GRANULARITY - 1))
  
  ULONG dmem(
      HANDLE hCurrentProcess,
      HANDLE hCurrentThread,
      DWORD dwCurrentPc,
      PWINDBG_EXTENSION_APIS lpExtensionApis,
      LPSTR lpArgString)
  {
      PWINDBG_OUTPUT_ROUTINE Print;
      PWINDBG_GET_EXPRESSION EvalExpression;
      PWINDBG_GET_SYMBOL GetSymbol;
  
      char ach[120];
      char chVerbose;
      ULONG i;
      ULONG NumberOfConsoleHandles;
      PCONSOLE_INFORMATION *ConsoleHandles;
      CONSOLE_INFORMATION Console;
      PCONSOLE_INFORMATION pConsole = NULL;
      SCREEN_INFORMATION Screen;
      PSCREEN_INFORMATION pScreen = NULL;
      ULONG cbTotal = 0;
      ULONG cbConsole = 0;
      ULONG cbInput = 0;
      ULONG cbOutput = 0;
      ULONG cbFE = 0;
  
      Print = lpExtensionApis->lpOutputRoutine;
      EvalExpression = lpExtensionApis->lpGetExpressionRoutine;
      GetSymbol = lpExtensionApis->lpGetSymbolRoutine;
  
      chVerbose   = ' ';
  
      do {
          /*
           * Skip white space
           */
          while (*lpArgString && *lpArgString == ' ')
              lpArgString++;
  
          switch (*lpArgString) {
          case 'v':
              chVerbose = 'v';
              break;
  
          case '\0':
              /*
               * If no console is specified, loop through all of them
               */
              moveExpressionValue(NumberOfConsoleHandles,
                                  "winsrv!NumberOfConsoleHandles");
              moveExpressionValuePtr(ConsoleHandles,
                                  "winsrv!ConsoleHandles");
              for (i = 0; i < NumberOfConsoleHandles; i++) {
                  move(pConsole, ConsoleHandles);
                  if (pConsole != NULL) {
                      sprintf(ach, "%c %p", chVerbose, pConsole);
                      cbTotal += dmem(hCurrentProcess, hCurrentThread, dwCurrentPc, lpExtensionApis, ach);
                      Print("==========================================\n");
                  }
                  ConsoleHandles++;
              }
              Print("Total Size for all consoles = %d bytes\n", cbTotal);
              return cbTotal;
  
          default:
              pConsole = (PCONSOLE_INFORMATION)EvalExpression(lpArgString);
              break;
          }
          lpArgString++;
  
      } while (pConsole == NULL);
  
      move(Console, pConsole);
  
      DebugConvertToAnsi(hCurrentProcess,
                         lpExtensionApis,
                         Console.Title,
                         Console.TitleLength,
                         ach,
                         sizeof(ach));
      Print("PCONSOLE @ 0x%lX   \"%s\"\n", pConsole, ach);
  
      cbConsole = HEAP_SIZE(sizeof(Console)) +
                  HEAP_SIZE(Console.TitleLength) +
                  HEAP_SIZE(Console.OriginalTitleLength);
  
      cbInput = HEAP_SIZE(Console.InputBuffer.AllocatedBufferSize);
  
      pScreen = Console.ScreenBuffers;
      while (pScreen != NULL) {
  
          move(Screen, pScreen);
          cbOutput += HEAP_SIZE(sizeof(Screen));
  
          if (Screen.Flags & CONSOLE_TEXTMODE_BUFFER) {
              cbOutput += HEAP_SIZE(Screen.ScreenBufferSize.Y * sizeof(ROW)) +
                          HEAP_SIZE(Screen.ScreenBufferSize.X * Screen.ScreenBufferSize.Y * sizeof(WCHAR));
              if (Screen.BufferInfo.TextInfo.DbcsScreenBuffer.TransBufferCharacter) {
                  cbFE += HEAP_SIZE(Screen.ScreenBufferSize.X * Screen.ScreenBufferSize.Y * sizeof(WCHAR));
              }
              if (Screen.BufferInfo.TextInfo.DbcsScreenBuffer.TransBufferAttribute) {
                  cbFE += HEAP_SIZE(Screen.ScreenBufferSize.X * Screen.ScreenBufferSize.Y * sizeof(BYTE));
              }
              if (Screen.BufferInfo.TextInfo.DbcsScreenBuffer.TransWriteConsole) {
                  cbFE += HEAP_SIZE(Screen.ScreenBufferSize.X * Screen.ScreenBufferSize.Y * sizeof(WCHAR));
              }
              if (Screen.BufferInfo.TextInfo.DbcsScreenBuffer.KAttrRows) {
                  cbFE += HEAP_SIZE(Screen.ScreenBufferSize.X * Screen.ScreenBufferSize.Y * sizeof(BYTE));
              }
          }
  
          pScreen = Screen.Next;
      }
  
      cbTotal = cbConsole + cbInput + cbOutput + cbFE;
  
      if (chVerbose == 'v') {
          Print("    Console Size = %7d\n", cbConsole);
          Print("    Input Size   = %7d\n", cbInput);
          Print("    Output Size  = %7d\n", cbOutput);
          Print("    FE Size      = %7d\n", cbFE);
      }
  
      Print("Total Size       = %7d\n", cbTotal);
  
      return cbTotal;
  }
  
  