home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / spy / app / wprintf.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  34KB  |  1,198 lines

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