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