WPRINTF.C
Upload User: bangxh
Upload Date: 2007-01-31
Package Size: 42235k
Code Size: 34k
Category:

Windows Develop

Development Platform:

Visual C++

  1. /******************************************************************************
  2. *       This is a part of the Microsoft Source Code Samples. 
  3. *       Copyright (C) 1993-1997 Microsoft Corporation.
  4. *       All rights reserved. 
  5. *       This source code is only intended as a supplement to 
  6. *       Microsoft Development Tools and/or WinHelp documentation.
  7. *       See these sources for detailed information regarding the 
  8. *       Microsoft samples programs.
  9. ******************************************************************************/
  10. /*****************************************************************************
  11. *
  12. * Module: wprintf.c
  13. *
  14. *   Contains the routines for using printf windows
  15. *
  16. * Functions:
  17. *
  18. *   MyCreatePrintfWin()
  19. *   SetPrintFont()
  20. *   SetPrintfTabs()
  21. *   ClearPrintfWindow()
  22. *   CopyToClipboard()
  23. *   IsPrintfEmpty()
  24. *   PrintfWndProc()
  25. *   DebugPaint()
  26. *   InsertString()
  27. *   DebugHScroll()
  28. *   DebugVScroll()
  29. *   SetWindowClass()
  30. *   LinesInDebugWindow()
  31. *   CharsInDebugWindow()
  32. *   wprintfSetScrollRange()
  33. *   NewLine()
  34. *
  35. * Comments:
  36. *
  37. *****************************************************************************/
  38. #include "spy.h"
  39. /*****************************************************************************
  40. *                                                                             
  41. *  g e n e r a l   c o n s t a n t s                                          
  42. *                                                                             
  43. *****************************************************************************/
  44. #define MAXBUFLEN 200         /* Maximum string length for wprintf */
  45. #define FIRST(pTxt) ((pTxt)->iFirst)
  46. #define TOP(pTxt)   (((pTxt)->iFirst + (pTxt)->iTop) % (pTxt)->iMaxLines)
  47. #define LAST(pTxt)  (((pTxt)->iFirst + (pTxt)->iCount-1) % (pTxt)->iMaxLines)
  48. #define INC(pTxt,x) ((x) = ++(x) % (pTxt)->iMaxLines)
  49. #define DEC(pTxt,x) ((x) = --(x) % (pTxt)->iMaxLines)
  50. #define OFFSETX (pTxt->Tdx/2)
  51. #define OFFSETY 1
  52. #define VARSIZE 1
  53. #define BOUND(x,mn,mx) ((x) < (mn) ? (mn) : ((x) > (mx) ? (mx) : (x)))
  54. #define FTwixtI3(l,x,h) ((x)>=(l) && (x<=h))
  55. #define EnterCrit(p)
  56. #define LeaveCrit(p)
  57. /*****************************************************************************
  58. *                                                                              
  59. *   g l o b a l   v a r i a b l e s                                            
  60. *                                                                              
  61. *****************************************************************************/
  62. typedef struct {
  63.     INT     iLen;
  64.     CHAR    * *hText;
  65. }   LINE;
  66. struct TEXT_STRUCT {
  67.     CRITICAL_SECTION csSync;      // CritSect to sync the threads
  68.     INT     iFirst;               /* First line in queue */
  69.     INT     iCount;               /* Number of lines in queue */
  70.     INT     iTop;                 /* Line at top of window */
  71.     INT     iLeft;                /* X offset of the window */
  72.     INT     MaxLen;               /* Max String Length */
  73.     INT     iMaxLines;            /* max number of LINEs */
  74.     HFONT   hFont;                /* Font to draw with */
  75.     DWORD   Tdx, Tdy;             /* Font Size */
  76.     LINE    arLines[VARSIZE];     /* array of iMaxLines LINEs */
  77. };
  78. typedef struct TEXT_STRUCT *PTXT; /* pointer to a text struct */
  79. typedef PTXT               *HTXT; /* Handle to a text struct */
  80. PRIVATE INT iSem = 0;
  81. INT tabs[20];
  82. INT nTabs = 0;
  83. /*****************************************************************************
  84. *                                                                              
  85. *   f u n c t i o n   d e f i n i t i o n s                                    
  86. *                                                                              
  87. *****************************************************************************/
  88. LONG APIENTRY PrintfWndProc(HWND, UINT, WPARAM, LONG);
  89. PRIVATE VOID DebugPaint(HWND hwnd, LPPAINTSTRUCT pps);
  90. PRIVATE INT  InsertString (PTXT, CHAR *);
  91. PRIVATE VOID DebugHScroll(HWND, PTXT, INT);
  92. PRIVATE VOID DebugVScroll(HWND, PTXT, INT);
  93. PRIVATE BOOL SetWindowClass (HANDLE, LPSTR);
  94. PRIVATE INT  LinesInDebugWindow (HWND);
  95. PRIVATE INT  CharsInDebugWindow (HWND);
  96. PRIVATE VOID wprintfSetScrollRange (HWND, BOOL);
  97. PRIVATE VOID NewLine (PTXT pTxt);
  98. PRIVATE INT mwprintf( HWND hwnd, LPSTR format, ... );
  99. /*****************************************************************************
  100. * MyCreatePrintfWin
  101. *
  102. * Creates a window to printf to.
  103. *
  104. * Arguments:
  105. *    HWND hwnd - handle to the parent window
  106. *
  107. * Returns:
  108. *    VOID
  109. *****************************************************************************/
  110. VOID
  111. MyCreatePrintfWin(
  112.     HWND hwnd
  113.     )
  114. {
  115.     RECT rc;
  116.     if (ghwndPrintf)
  117.         DestroyWindow(ghwndPrintf);
  118.     GetClientRect(hwnd, &rc);
  119.     ghwndPrintf = CreatePrintfWin(hwnd, ghInst, "", WS_CHILD | WS_VSCROLL |
  120.         WS_HSCROLL, -gcxBorder, -gcyBorder, rc.right + (2 *gcxBorder),
  121.         rc.bottom + (2 * gcyBorder), gnLines);
  122. }
  123. /*****************************************************************************
  124. * DebugPaint(hwnd, pps)                                                       
  125. *                                                                             
  126. * The paint function.                                                    
  127. *                                                                        
  128. * Arguments:                                                             
  129. *    HWND hwnd - Window to paint to.                                    
  130. *    LPPAINTSTRUCT - pps              
  131. *                                                                              
  132. *   Returns:                                                                   
  133. *       nothing                                                                
  134. *                                                                              
  135. *****************************************************************************/
  136. PRIVATE VOID
  137. DebugPaint(
  138.     HWND hwnd,
  139.     LPPAINTSTRUCT pps
  140.     )
  141. {
  142.     PTXT pTxt;
  143.     HTXT hTxt;
  144.     INT iQueue;
  145.     INT xco;
  146.     INT yco;
  147.     INT iLast;
  148.     HBRUSH hb;
  149.     COLORREF c;
  150.     hTxt = (HTXT)GetWindowLong(hwnd, 0);
  151.     pTxt = *hTxt;
  152.     SetTextColor(pps->hdc, GetSysColor(COLOR_WINDOWTEXT));
  153.     c = GetSysColor(COLOR_WINDOW);
  154.     SetBkColor(pps->hdc, c);
  155.     hb = CreateSolidBrush(c);
  156.     if (pTxt->hFont)
  157.         SelectObject(pps->hdc, pTxt->hFont);
  158.     iLast  = LAST(pTxt);
  159.     iQueue = TOP(pTxt);
  160.     xco = OFFSETX - pTxt->iLeft * pTxt->Tdx;
  161.     yco = OFFSETY;
  162.     for (;;)
  163.     {
  164.         if (yco <= pps->rcPaint.bottom &&
  165.                 (yco + (LONG)(pTxt->Tdy)) >= pps->rcPaint.top)
  166.         {
  167.             if (pTxt->arLines[iQueue].hText == NULL
  168.                 || (LPSTR)*(pTxt->arLines[iQueue].hText) == NULL)
  169.             {
  170.                 RECT rcT;
  171.                 rcT.top = yco;
  172.                 rcT.bottom = yco+pTxt->Tdy;
  173.                 rcT.left = pps->rcPaint.left;
  174.                 rcT.right = pps->rcPaint.right;
  175.                 FillRect(pps->hdc, &rcT, hb);
  176.             }
  177.             else
  178.             {
  179.                 TabbedTextOut(pps->hdc, xco, yco,
  180.                     (LPSTR)*(pTxt->arLines[iQueue].hText),
  181.                     pTxt->arLines[iQueue].iLen, nTabs, tabs, xco);
  182.             }
  183.         }
  184.         if (iQueue == iLast)
  185.             break;
  186.         yco += pTxt->Tdy;
  187.         INC(pTxt, iQueue);
  188.     }
  189.     DeleteObject((HANDLE)hb);
  190. }
  191. /*****************************************************************************
  192. * SetWindowClass (hInstance)                                                
  193. *     
  194. * Registers the window class of the printf window
  195. *                                                                         
  196. * Arguments:                                                                 
  197. *   HANDLE hInstance - instance handle of current instance                    
  198. *   LPSTR lpch - pointer to class name
  199. *                                                                              
  200. * Returns:                                                                   
  201. *   TRUE if successful, FALSE if not                                       
  202. *****************************************************************************/
  203. PRIVATE BOOL
  204. SetWindowClass(
  205.     HANDLE hInstance,
  206.     LPSTR lpch
  207.     )
  208. {
  209.     WNDCLASS wc;
  210.     wc.style          = CS_HREDRAW | CS_VREDRAW;
  211.     wc.lpfnWndProc    = PrintfWndProc;
  212.     wc.cbClsExtra     = 0;
  213.     wc.cbWndExtra     = sizeof(HANDLE);
  214.     wc.hInstance      = hInstance;
  215.     wc.hIcon          = NULL;
  216.     wc.hCursor        = LoadCursor(NULL, IDC_ARROW);
  217.     wc.hbrBackground  = (HBRUSH)(COLOR_WINDOW + 1);
  218.     wc.lpszMenuName   = NULL;
  219.     wc.lpszClassName  = lpch;
  220.     return RegisterClass(&wc);
  221. }
  222. /*****************************************************************************
  223. * CreatePrintfWin (hParent, lpchName, dwStyle, x, y, dx, dy, iMaxLines)       
  224. *                                                                             
  225. * Creates a window for the depositing of debuging messages.                
  226. *                                                                              
  227. * Arguments:                                                                 
  228. *   HWND hParent - Window handle of the parent window.                          
  229. *   HANDLE hInstance - Module instance handle.                                     
  230. *   lPSTR lpchName - String to appear in the caption bar of the debuging window   
  231. *   DWORD dwStyle - Window style                                                 
  232. *   INT x,y - Location of window                                           
  233. *   INT dx,dy - Size of the window                                           
  234. *   INT iMaxLines - The maximum number of text lines to display in the window    
  235. *                                                                              
  236. * Returns:                                                                   
  237. *   A window handle of the debuging window, or NULL if a error occured.      
  238. *****************************************************************************/
  239. PUBLIC HWND APIENTRY
  240. CreatePrintfWin (
  241. HWND   hParent,
  242. HANDLE hInstance,
  243. LPSTR  lpchName,
  244. DWORD  dwStyle,
  245. INT   x,
  246. INT   y,
  247. INT   dx,
  248. INT   dy,
  249. INT    iMaxLines
  250. )
  251. {
  252.     static BOOL bClass = FALSE;   /* Is the class registered */
  253.     HWND   hwnd;
  254.     HTXT   hTxt;      /* handle to a debuging window struct */
  255.     PTXT   pTxt;
  256.     static CHAR achClass[40];
  257.     /*
  258.         *  Make a Class name that is unique across instances
  259.         */
  260.     if (!bClass++) {
  261.         wsprintf(achClass, "WPRINTF_%4.4X", hInstance);
  262.         SetWindowClass(hInstance, achClass);
  263.     }
  264.     /* Allocate the window long before create the window, such that the
  265.            window proc can find the window long during the create. */
  266.     hTxt = (HTXT)LocalAlloc(LHND, sizeof(struct TEXT_STRUCT) + (iMaxLines
  267.         - VARSIZE) * sizeof(LINE));
  268.     if (!hTxt) {
  269.         return FALSE;
  270.     }
  271.     pTxt = *hTxt;
  272.     //InitializeCriticalSection(&pTxt->csSync);
  273.     pTxt->iFirst            = 0;    /* Set the queue up to have 1 NULL line */
  274.     pTxt->iCount            = 1;
  275.     pTxt->iTop              = 0;
  276.     pTxt->iLeft             = 0;
  277.     pTxt->MaxLen            = 0;
  278.     pTxt->iMaxLines         = iMaxLines;
  279.     pTxt->arLines[0].hText  = NULL;
  280.     pTxt->arLines[0].iLen   = 0;
  281.     hwnd = CreateWindow((LPSTR)achClass, (LPSTR)lpchName, dwStyle, x, y,
  282.         dx, dy, (HWND)hParent,     /* parent window */
  283.     (HMENU)NULL,       /* use class menu */
  284.     (HANDLE)hInstance, /* handle to window instance */
  285.     (LPSTR)hTxt        /* used by WM_CREATE to set the window long */
  286.     );
  287.     if (!hwnd) {
  288.         return FALSE;
  289.     }
  290.     wprintfSetScrollRange(hwnd, FALSE);
  291.     /* Make window visible */
  292.     ShowWindow(hwnd, SHOW_OPENWINDOW);
  293.     return hwnd;
  294. }
  295. /*****************************************************************************
  296. * SetPrintfFont (hwnd,hFont)                                                
  297. *               
  298. * Sets the font for the printf window.
  299. *                                                               
  300. * Arguments:                                                                 
  301. *   HWND hwnd - Window handle of the printf window.                          
  302. *   HFONT hFont - Font handle                                                  
  303. *                                                                              
  304. * Returns:                                                                   
  305. *                                                                              
  306. *****************************************************************************/
  307. VOID
  308. SetPrintfFont(
  309.     HWND hwnd,
  310.     HFONT hfont
  311.     )
  312. {
  313.     PTXT pTxt;
  314.     HDC hDC;
  315.     TEXTMETRIC tm;
  316.     HFONT hfontOld;
  317.     pTxt = *(HTXT)GetWindowLong(hwnd, 0);
  318.     pTxt->hFont = hfont;
  319.     /* Find out the size of a Char in the font */
  320.     hDC = GetDC(hwnd);
  321.     hfontOld = SelectObject(hDC, hfont);
  322.     DeleteObject(hfontOld);
  323.     GetTextMetrics(hDC, &tm);
  324.     pTxt->Tdy = tm.tmHeight;
  325.     pTxt->Tdx = tm.tmAveCharWidth;
  326.     ReleaseDC(hwnd, hDC);
  327.     CalculatePrintfTabs(hfont);
  328.     InvalidateRect(hwnd, NULL, TRUE);
  329.     UpdateWindow(hwnd);
  330. }
  331. /*****************************************************************************
  332. * SetPrintfTabs                                                             
  333. *
  334. * Sets the Tabstops in the printf window.
  335. *        
  336. * Arguments:
  337. *    INT n - number of tabs to set.
  338. *    LPINT pTabs - arrays of tabstops
  339. *
  340. * Returns:                                                                   
  341. *    VOID                                                                              
  342. *****************************************************************************/
  343. VOID
  344. SetPrintfTabs(
  345.     INT n,
  346.     LPINT pTabs
  347.     )
  348. {
  349.     INT i;
  350.     nTabs = n;
  351.     for (i = 0; i < nTabs; i++)
  352.         tabs[i] = *pTabs++;
  353. }
  354. /*****************************************************************************
  355. * ClearPrintfWindow
  356. *                                                                              
  357. * Clears all text from the window                                             
  358. *                                                                             
  359. * Arguments:                                                                 
  360. *    HWND hwnd - window handle for the Degubing window                  
  361. *
  362. * Returns:
  363. *    VOID                                                                              
  364. *****************************************************************************/
  365. VOID
  366. ClearPrintfWindow(
  367.     HWND hwnd
  368.     )
  369. {
  370.     INT   i, iQueue;
  371.     PTXT  pTxt;
  372.     HTXT  hTxt;
  373.     if (hwnd != NULL && IsWindow(hwnd)) {
  374.         hTxt  = (HTXT)GetWindowLong(hwnd, 0);
  375.         pTxt = *hTxt;
  376.         EnterCrit(pTxt);
  377.         iQueue = TOP(pTxt);
  378.         for (i = 0; i < (pTxt)->iCount; i++, INC(pTxt, iQueue))
  379.             if ((pTxt)->arLines[iQueue].hText != NULL) {
  380.                 LocalFree ((HANDLE)pTxt->arLines[iQueue].hText);
  381.                 pTxt->arLines[iQueue].hText = NULL;
  382.             }
  383.         pTxt->iFirst            = 0;  /* Set the queue up to have 1 NULL line */
  384.         pTxt->iCount            = 1;
  385.         pTxt->iTop              = 0;
  386.         pTxt->iLeft             = 0;
  387.         pTxt->MaxLen            = 0;
  388.         pTxt->arLines[0].hText  = NULL;
  389.         pTxt->arLines[0].iLen   = 0;
  390.         wprintfSetScrollRange(hwnd, FALSE);
  391.         InvalidateRect(hwnd, NULL, TRUE);
  392.         LeaveCrit(pTxt);
  393.     }
  394. }
  395. /*****************************************************************************
  396. * PrintfWndProc( hwnd, uiMessage, wParam, lParam )                          
  397. *
  398. * The window proc for the debugging window.  This processes all          
  399. * of the window's messages.                                              
  400. *                                                                              
  401. * Arguments:                                                                 
  402. *   HWND hwnd - window handle for the parent window                    
  403. *   UINT uiMessage -message number                                         
  404. *   WPARAM wParam - message-dependent                                      
  405. *   LPARAM lParam - message-dependent                                      
  406. *                                                                              
  407. * Returns:                                                                   
  408. *   0 if processed, nonzero if ignored                                     
  409. *****************************************************************************/
  410. PUBLIC LONG APIENTRY
  411. PrintfWndProc(
  412. HWND   hwnd,
  413. UINT   uiMessage,
  414. WPARAM wParam,
  415. LONG   lParam
  416. )
  417. {
  418.     PAINTSTRUCT rPS;
  419.     HTXT        hTxt;
  420.     PTXT        pTxt;
  421.     hTxt  = (HTXT)GetWindowLong(hwnd, 0);
  422.     if ( hTxt ) {
  423.         pTxt = *hTxt;
  424.     }
  425.     switch (uiMessage) {
  426.     case WM_CREATE:
  427.         {
  428.             /* set the WindowLong before any other message tries to
  429.                          * reference it during the create of a window
  430.                          */
  431.             LPCREATESTRUCT csWindowLong = (LPCREATESTRUCT) lParam;
  432.             hTxt = (HTXT)csWindowLong->lpCreateParams;
  433.             SetWindowLong(hwnd, 0, (LONG)hTxt);
  434.             SetPrintfFont(hwnd, ghfontPrintf);
  435.             wprintfSetScrollRange(hwnd, FALSE);
  436.         }
  437.         break;
  438.     case WM_DESTROY:
  439.         {
  440.             INT i, iQueue;
  441.             EnterCrit(pTxt);
  442.             iQueue = TOP(pTxt);
  443.             for (i = 0; i < (pTxt)->iCount; i++, INC(pTxt, iQueue))
  444.                 if ((pTxt)->arLines[iQueue].hText != NULL) {
  445.                     LocalFree ((HANDLE)(pTxt)->arLines[iQueue].hText);
  446.                     pTxt->arLines[iQueue].hText = NULL;
  447.                 }
  448.             LeaveCrit(pTxt);
  449.             // DeleteCriticalSection(&pTxt->csSync);
  450.             LocalFree((HANDLE)hTxt);
  451.             break;
  452.         }
  453.     case WM_SIZE:
  454.         EnterCrit(pTxt);
  455.         if (!iSem) {
  456.             wprintfSetScrollRange(hwnd, TRUE);
  457.         }
  458.         DebugVScroll(hwnd, pTxt, 0);
  459.         LeaveCrit(pTxt);
  460.         break;
  461.     case WM_VSCROLL:
  462.         EnterCrit(pTxt);
  463.         switch (LOWORD(wParam)) {
  464.         case SB_LINEDOWN:
  465.             DebugVScroll(hwnd, pTxt, 1);
  466.             break;
  467.         case SB_LINEUP:
  468.             DebugVScroll(hwnd, pTxt, -1);
  469.             break;
  470.         case SB_PAGEUP:
  471.             DebugVScroll(hwnd, pTxt, -LinesInDebugWindow(hwnd));
  472.             break;
  473.         case SB_PAGEDOWN:
  474.             DebugVScroll(hwnd, pTxt, LinesInDebugWindow(hwnd));
  475.             break;
  476.         case SB_THUMBTRACK:
  477.         case SB_THUMBPOSITION:
  478.             DebugVScroll(hwnd, pTxt, HIWORD(wParam) - pTxt->iTop);
  479.             break;
  480.         case SB_ENDSCROLL:
  481.             break;
  482.         }
  483.         LeaveCrit(pTxt);
  484.         break;
  485.     case WM_HSCROLL:
  486.         EnterCrit(pTxt);
  487.         switch (LOWORD(wParam)) {
  488.         case SB_LINEDOWN:
  489.             DebugHScroll (hwnd, pTxt, 1);
  490.             break;
  491.         case SB_LINEUP:
  492.             DebugHScroll (hwnd, pTxt, -1);
  493.             break;
  494.         case SB_PAGEUP:
  495.             DebugHScroll (hwnd, pTxt, -CharsInDebugWindow(hwnd));
  496.             break;
  497.         case SB_PAGEDOWN:
  498.             DebugHScroll (hwnd, pTxt, CharsInDebugWindow(hwnd));
  499.             break;
  500.         case SB_THUMBTRACK:
  501.         case SB_THUMBPOSITION:
  502.             DebugHScroll(hwnd, pTxt, HIWORD(wParam) - pTxt->iLeft);
  503.             break;
  504.         case SB_ENDSCROLL:
  505.             break;
  506.         }
  507.         LeaveCrit(pTxt);
  508.         break;
  509.     case WM_PAINT:
  510.         EnterCrit(pTxt);
  511.         BeginPaint(hwnd, (LPPAINTSTRUCT) & rPS);
  512.         DebugPaint(hwnd, &rPS);
  513.         EndPaint(hwnd, (LPPAINTSTRUCT) & rPS);
  514.         LeaveCrit(pTxt);
  515.         break;
  516.     case WM_KEYDOWN:
  517.         EnterCrit(pTxt);
  518.         switch (wParam) {
  519.         case VK_UP:
  520.             DebugVScroll(hwnd, pTxt, -1);
  521.             break;
  522.         case VK_DOWN:
  523.             DebugVScroll(hwnd, pTxt, 1);
  524.             break;
  525.         case VK_PRIOR:
  526.             DebugVScroll(hwnd, pTxt, -LinesInDebugWindow(hwnd));
  527.             break;
  528.         case VK_NEXT:
  529.             DebugVScroll(hwnd, pTxt, LinesInDebugWindow(hwnd));
  530.             break;
  531.         case VK_LEFT:
  532.             DebugHScroll(hwnd, pTxt, -1);
  533.             break;
  534.         case VK_RIGHT:
  535.             DebugHScroll(hwnd, pTxt, 1);
  536.             break;
  537.         }
  538.         LeaveCrit(pTxt);
  539.         break;
  540.     case WM_KEYUP:
  541.         break;
  542.     case WM_VWPRINTF:
  543.         return mwprintf( hwnd, (LPSTR)"%s", (LPSTR)wParam );
  544.     default:
  545.         return DefWindowProc(hwnd, uiMessage, wParam, lParam);
  546.     }
  547.     return 0L;
  548. }
  549. /*****************************************************************************
  550. * DebugScroll
  551. *   
  552. * Scrolls the debug window vertically
  553. *
  554. * Arguments:
  555. *    HWND hwnd - handle to the debug window
  556. *    PTXT pTxt - pointer to the text to scroll
  557. *    INT n - number of lines to scroll
  558. *
  559. * Returns:
  560. *    VOID
  561. *****************************************************************************/
  562. PRIVATE VOID
  563. DebugVScroll(
  564. HWND hwnd,
  565. PTXT pTxt,
  566. INT  n
  567. )
  568. {
  569.     RECT rect;
  570.     INT  iMinPos, iMaxPos;
  571.     GetScrollRange(hwnd, SB_VERT, (LPINT) &iMinPos, (LPINT) &iMaxPos);
  572.     GetClientRect(hwnd, (LPRECT) &rect);
  573.     rect.left += OFFSETX;
  574.     rect.top  += OFFSETY;
  575.     n = BOUND(pTxt->iTop + n, iMinPos, iMaxPos) - pTxt->iTop;
  576.     if (n == 0)
  577.         return;
  578.     pTxt->iTop += n;
  579.     ScrollWindow(hwnd, 0, -n * pTxt->Tdy, (LPRECT) &rect, (LPRECT) &rect);
  580.     SetScrollPos(hwnd, SB_VERT, pTxt->iTop, TRUE);
  581. }
  582. /*****************************************************************************
  583. * DebugHScroll
  584. *
  585. * Performs the horizontal scroll calculations
  586. *
  587. * Arguments:
  588. *    HWND hwnd - handle to the debug window
  589. *    PTXT pTxt - pointer to the text to scroll
  590. *    INT n - number of characters to scroll
  591. *
  592. * Returns:
  593. *    VOID
  594. *****************************************************************************/
  595. PRIVATE VOID
  596. DebugHScroll(
  597. HWND hwnd,
  598. PTXT pTxt,
  599. INT  n
  600. )
  601. {
  602.     RECT rect;
  603.     INT  iMinPos, iMaxPos;
  604.     GetScrollRange (hwnd, SB_HORZ, (LPINT) &iMinPos, (LPINT) &iMaxPos);
  605.     GetClientRect (hwnd, (LPRECT) & rect);
  606.     rect.left += OFFSETX;
  607.     rect.top  += OFFSETY;
  608.     n = BOUND(pTxt->iLeft + n, iMinPos, iMaxPos) - pTxt->iLeft;
  609.     if (n == 0)
  610.         return;
  611.     pTxt->iLeft += n;
  612.     ScrollWindow(hwnd, -n * pTxt->Tdx, 0, (LPRECT) & rect, (LPRECT) & rect);
  613.     SetScrollPos(hwnd, SB_HORZ, pTxt->iLeft, TRUE);
  614. }
  615. /*****************************************************************************
  616. * LinesInDebugWindow
  617. *
  618. * Calculates the number of lines in the debug window
  619. *
  620. * Arguments:
  621. *    HWND hwnd - handle to the debug window
  622. *
  623. * Returns:
  624. *    INT - number of lines in the debug window
  625. *****************************************************************************/
  626. PRIVATE INT
  627. LinesInDebugWindow (
  628. HWND hwnd
  629. )
  630. {
  631.     RECT CRect;
  632.     PTXT pTxt;
  633.     pTxt = *(HTXT)GetWindowLong(hwnd, 0);
  634.     GetClientRect(hwnd, &CRect);
  635.     if ( pTxt->Tdy == 0 ) {
  636.         return 0;
  637.     }
  638.     return pTxt ? (CRect.bottom - CRect.top - OFFSETY) / pTxt->Tdy : 0;
  639. }
  640. /*****************************************************************************
  641. * CharsInDebugWindow
  642. *
  643. * Calculates the number of characters horizontally in the debug window
  644. *
  645. * Arguments:
  646. *    HWND hwnd - handle to the debug window
  647. *
  648. * Returns:
  649. *    INT - number of horizontal characters in the debug window
  650. *****************************************************************************/
  651. PRIVATE INT
  652. CharsInDebugWindow (
  653. HWND hwnd
  654. )
  655. {
  656.     RECT CRect;
  657.     PTXT pTxt;
  658.     pTxt = *(HTXT)GetWindowLong (hwnd, 0);
  659.     GetClientRect(hwnd, (LPRECT) & CRect);
  660.     if ( pTxt->Tdx == 0 ) {
  661.         return 0;
  662.     }
  663.     return pTxt ? (CRect.right - CRect.left - OFFSETX) / pTxt->Tdx : 0;
  664. }
  665. PRIVATE INT
  666. mwprintf(
  667.     HWND hwnd,
  668.     LPSTR format,
  669.     ...
  670.     )
  671. {
  672.     va_list marker;
  673.     INT i;
  674.     va_start(marker, format);
  675.     i = vwprintf(hwnd, format, marker);
  676.     va_end(marker);
  677.     return i;
  678. }
  679. /*****************************************************************************
  680. * vwprintf
  681. *
  682. * variable printf - works like the C runtime printf
  683. *
  684. * Arguments:
  685. *    HWND hwnd - handle to the debug window
  686. *    LPSTR format - pointer to the format string
  687. *    va_list marker - pointer to marker
  688. *
  689. * Returns:
  690. *    INT - number of arguments printed
  691. *****************************************************************************/
  692. PUBLIC INT FAR cdecl
  693. vwprintf(
  694. HWND  hwnd,
  695. LPSTR format,
  696. va_list marker
  697. )
  698. {
  699.     static HWND hwndLast = NULL;
  700.     static CHAR  pchBuf[MAXBUFLEN];
  701.     RECT  rect, rcClient;
  702.     INT   iRet;
  703.     INT   cLinesDisplayed;       // lines of output to show
  704.     INT   cLinesFitInWindow;    // lines that can fit in the current window
  705.     INT   cLinesNew;  // how much left to scroll
  706.     PTXT  pTxt;
  707.     HTXT  hTxt;
  708.     BOOL  fNoScrollB;
  709.     if (hwnd == NULL)
  710.         hwnd = hwndLast;
  711.     if (hwnd == NULL || !IsWindow(hwnd))
  712.         return 0;  /* exit if bad window handle */
  713.     hwndLast = hwnd;
  714.     //
  715.     // First format the line and wait until we can play with the Txt structure
  716.     //
  717.     iRet = wvsprintf((LPSTR)pchBuf, format, marker);
  718.     hTxt = (HTXT)GetWindowLong(hwnd, 0);
  719.     pTxt = (PTXT)LocalLock((HANDLE)hTxt);
  720.     if(pTxt == NULL)
  721.         return 0;  // exit if bad memory block
  722.     EnterCrit(pTxt);
  723.     //
  724.     // Number of lines that we can display stuff in
  725.     //
  726.     cLinesFitInWindow   = LinesInDebugWindow(hwnd);
  727.     if (cLinesFitInWindow > pTxt->iMaxLines) {
  728.         fNoScrollB = TRUE;
  729.         cLinesFitInWindow = pTxt->iMaxLines;
  730.     } else {
  731.         fNoScrollB = FALSE;
  732.     }
  733.     //
  734.     // Number of lines actually displayed in the current window
  735.     //
  736.     cLinesDisplayed   = min(pTxt->iCount, cLinesFitInWindow);
  737.     //
  738.     // Return value is number of new lines to display
  739.     //
  740.     cLinesNew = InsertString(pTxt, pchBuf);
  741.     //
  742.     // Now make sure the new text is painted only if visable
  743.     //
  744.     GetClientRect(hwnd, (LPRECT) & rect);
  745.     rcClient = rect;
  746.     //
  747.     // Calculate how much of the window to invalidate
  748.     //
  749.     rect.top += (cLinesDisplayed - 1) * pTxt->Tdy;
  750.     InvalidateRect(hwnd, (LPRECT)&rect, TRUE);
  751.     //
  752.     // If we have more lines than we can display, scroll the window
  753.     // such that the last line printed is now at the bottom
  754.     //
  755.     if (cLinesDisplayed + cLinesNew > cLinesFitInWindow) {
  756.         cLinesNew = cLinesDisplayed + cLinesNew - cLinesFitInWindow;
  757.         if (fNoScrollB) {
  758.             rcClient.bottom = cLinesDisplayed * pTxt->Tdy;
  759.             ScrollWindow(hwnd, 0, -cLinesNew * pTxt->Tdy, (LPRECT) &rcClient, (LPRECT) &rcClient);
  760.         } else {
  761.             wprintfSetScrollRange(hwnd, FALSE);
  762.             DebugVScroll(hwnd, pTxt, cLinesNew);
  763.         }
  764.         LeaveCrit(pTxt);
  765.     } else {
  766.         LeaveCrit(pTxt);
  767.     }
  768.     LocalUnlock((HANDLE)hTxt);
  769.     return(iRet);       /* return the count of arguments printed */
  770. }
  771. /*****************************************************************************
  772. * wprintfSetScrollRange
  773. *
  774. * Sets the scroll range of the debug window
  775. *
  776. * Arguments:
  777. *    HWND hwnd - handle to the debug window
  778. *    BOOL fRedraw - whether or not to redraw the window
  779. *
  780. * Returns:
  781. *    VOID
  782. *****************************************************************************/
  783. PRIVATE VOID
  784. wprintfSetScrollRange (
  785. HWND hwnd,
  786. BOOL bRedraw
  787. )
  788. {
  789.     PTXT pTxt;
  790.     INT  iRange;
  791.     INT  iLeftCritSect = 0;
  792.     iSem++;
  793.     pTxt = *(HTXT)GetWindowLong(hwnd, 0);
  794.     /* Update the scroll bars */
  795.     iRange = pTxt->iCount - 1 - LinesInDebugWindow(hwnd);
  796.     if (iRange < 0) {
  797.         iRange = 0;
  798.         DebugVScroll(hwnd, pTxt, -pTxt->iTop);
  799.     }
  800.     while (GetCurrentThreadId() == (DWORD)pTxt->csSync.OwningThread){
  801. LeaveCrit(pTxt);
  802. iLeftCritSect++;
  803.     }
  804.     SetScrollRange(hwnd, SB_VERT, 0, iRange, FALSE);
  805.     SetScrollPos(hwnd, SB_VERT, pTxt->iTop, bRedraw);
  806.     if(iLeftCritSect) {
  807. EnterCrit(pTxt);
  808.     }
  809.     iRange = pTxt->MaxLen - CharsInDebugWindow(hwnd) + 1;
  810.     if (iRange < 0) {
  811.         iRange = 0;
  812.         DebugHScroll(hwnd, pTxt, -pTxt->iLeft);
  813.     }
  814.     if(iLeftCritSect)
  815. LeaveCrit(pTxt);
  816.     SetScrollRange(hwnd, SB_HORZ, 0, iRange, FALSE);
  817.     SetScrollPos(hwnd, SB_HORZ, pTxt->iLeft, bRedraw);
  818.     while (iLeftCritSect--) {
  819. EnterCrit(pTxt);
  820.     }
  821.     iSem--;
  822. }
  823. /*****************************************************************************
  824. * NewLine
  825. *
  826. * Calculates when a new line is needed in the debug window
  827. *
  828. * Arguments:
  829. *    PTXT pTxt - pointer to the text
  830. *
  831. * Returns:
  832. *    VOID
  833. *****************************************************************************/
  834. PRIVATE VOID
  835. NewLine (
  836. PTXT pTxt
  837. )
  838. {
  839.     INT iLast = LAST(pTxt);
  840.     if (pTxt->iCount == pTxt->iMaxLines) {
  841.         LocalFree ((HANDLE)pTxt->arLines[pTxt->iFirst].hText);
  842.         pTxt->arLines[pTxt->iFirst].hText = NULL;
  843.         INC (pTxt, pTxt->iFirst);
  844.         if (pTxt->iTop > 0) {
  845.             pTxt->iTop--;
  846.         }
  847.     } else {
  848.         pTxt->iCount++;
  849.     }
  850.     iLast = LAST(pTxt);
  851.     pTxt->arLines[iLast].hText = NULL;
  852.     pTxt->arLines[iLast].iLen  = 0;
  853. }
  854. /*****************************************************************************
  855. * InsertString
  856. *
  857. * Inserts a string into the debug window
  858. *
  859. * Arguments:
  860. *    PTXT pTxt - pointer to the text
  861. *    CHAR *str - pointer to insertion string
  862. *
  863. * Returns:
  864. *    INT - Line number at which string was inserted
  865. *****************************************************************************/
  866. PRIVATE INT
  867. InsertString (
  868. PTXT  pTxt,
  869. CHAR  *str
  870. )
  871. {
  872.     CHAR   pchBuf[MAXBUFLEN];        /* intermediate buffer */
  873.     INT    iBuf;
  874.     INT    iLast = LAST(pTxt);
  875.     INT    cLine = 0;
  876.     for (iBuf = 0; iBuf < pTxt->arLines[iLast].iLen; iBuf++)
  877.         pchBuf[iBuf] = (*pTxt->arLines[iLast].hText)[iBuf];
  878.     while (*str != '') {
  879.         while ((*str != 'n') && (*str != ''))
  880.             pchBuf[iBuf++] = *str++;
  881.         if (pTxt->arLines[iLast].hText != NULL)
  882.             LocalFree((HANDLE)pTxt->arLines[iLast].hText);
  883.         /* Test for the case of a zero length line, Only brian would do this */
  884.         if (iBuf == 0)
  885.             pTxt->arLines[iLast].hText == NULL;
  886.         else {
  887.             if ((pTxt->arLines[iLast].hText = (CHAR **)LocalAlloc(LHND, iBuf))
  888.                 == NULL) {
  889.                 return 0;
  890.             }
  891.         }
  892.         pTxt->arLines[iLast].iLen = iBuf;
  893.         while (--iBuf >= 0 )
  894.             (*pTxt->arLines[iLast].hText)[iBuf] = pchBuf[iBuf];
  895.         if (*str == 'n') {   /* Now do the next string after the n */
  896.             str++;
  897.             cLine++;
  898.             iBuf = 0;
  899.             NewLine(pTxt);
  900.             INC(pTxt, iLast);
  901.         }
  902.     }
  903.     return cLine;
  904. }
  905. /*****************************************************************************
  906. * CopyToClipboard
  907. *
  908. * Copies all lines to the clipboard in text format.
  909. *
  910. * Arguments:
  911. *   none
  912. *
  913. * Returns:
  914. *   TRUE if successful, FALSE if not.
  915. *
  916. *****************************************************************************/
  917. BOOL
  918. CopyToClipboard(
  919.     VOID
  920.     )
  921. {
  922.     PTXT pTxt;
  923.     INT iQueue;
  924.     INT cch;
  925.     INT i;
  926.     BOOL fSuccess = FALSE;
  927.     LPSTR pBuf = NULL;
  928.     LPSTR pb;
  929.     pTxt = *(HTXT)GetWindowLong(ghwndPrintf, 0);
  930.     EnterCrit(pTxt);
  931.     iQueue = FIRST(pTxt);
  932.     cch = 0;
  933.     for (i = 0; i < pTxt->iCount; i++, INC(pTxt, iQueue))
  934.     {
  935.         if (pTxt->arLines[iQueue].hText != NULL)
  936.         {
  937.             //
  938.             // Count the characters in the line, plus room for the
  939.             // carriage return and newline.
  940.             //
  941.             cch += pTxt->arLines[iQueue].iLen;
  942.             cch += 2;
  943.         }
  944.     }
  945.     //
  946.     // Add one for the terminating null.
  947.     //
  948.     cch++;
  949.     if (!(pBuf = (LPSTR)GlobalAlloc(GMEM_DDESHARE, cch * sizeof(TCHAR))))
  950.     {
  951.         LeaveCrit(pTxt);
  952.         return FALSE;
  953.     }
  954.     pb = pBuf;
  955.     iQueue = FIRST(pTxt);
  956.     for (i = 0; i < pTxt->iCount; i++, INC(pTxt, iQueue))
  957.     {
  958.         if (pTxt->arLines[iQueue].hText != NULL)
  959.         {
  960.             lstrcpy(pb, *pTxt->arLines[iQueue].hText);
  961.             pb += pTxt->arLines[iQueue].iLen;
  962.             *pb++ = 'r';
  963.             *pb++ = 'n';
  964.         }
  965.     }
  966.     LeaveCrit(pTxt);
  967.     if (OpenClipboard(ghwndSpyApp))
  968.     {
  969.         EmptyClipboard();
  970.         fSuccess = SetClipboardData(CF_TEXT, pBuf) ? TRUE : FALSE;
  971.         CloseClipboard();
  972.     }
  973.     return fSuccess;
  974. }
  975. /*****************************************************************************
  976. * IsPrintfEmpty
  977. *
  978. * Used to determine if the printf window is empty or not.
  979. *
  980. * Arguments:
  981. *   none
  982. *
  983. * Returns:
  984. *   TRUE if the printf window is empty, FALSE if there is at least
  985. *   one line in the window.
  986. *
  987. *****************************************************************************/
  988. BOOL
  989. IsPrintfEmpty(
  990.     VOID
  991.     )
  992. {
  993.     PTXT pTxt;
  994.     pTxt = *(HTXT)GetWindowLong(ghwndPrintf, 0);
  995.     //
  996.     // It is empty if the line count is zero (doesn't currently happen)
  997.     // or if there is only one line and it is NULL.
  998.     //
  999.     return (pTxt->iCount == 0 ||
  1000.         (pTxt->iCount == 1 && pTxt->arLines[FIRST(pTxt)].hText == NULL))
  1001.         ? TRUE : FALSE;
  1002. }