mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1129 lines
33 KiB
1129 lines
33 KiB
/*----------------------------------------------------------------------------
|
|
*| wprintf.c - Routines for using printf windows |
|
|
| |
|
|
| Usage: |
|
|
| Call CreatePrintfWindow() to set up a window for printf messages |
|
|
| Use wprintf () to put messages in to the window |
|
|
| |
|
|
| History: |
|
|
| 10/02/86 Todd Laney Created |
|
|
| 04/14/87 Added new function CreateDebugWin |
|
|
| 07/08/87 brianc added iMaxLines parm to CreateDebugWin[dow] |
|
|
| |
|
|
\*----------------------------------------------------------------------------*/
|
|
|
|
#include "spy.h"
|
|
|
|
#if 0
|
|
# pragma message( __FILE__"(18): warning !!!! : remove DPRINT code" )
|
|
# define DPRINT(p) printf p
|
|
#else
|
|
# define DPRINT /* nothing */
|
|
#endif
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
*| |
|
|
| g e n e r a l c o n s t a n t s |
|
|
| |
|
|
\*----------------------------------------------------------------------------*/
|
|
|
|
#define MAXBUFLEN 200 /* Maximum string length for wprintf */
|
|
|
|
#define FIRST(pTxt) ((pTxt)->iFirst)
|
|
#define TOP(pTxt) (((pTxt)->iFirst + (pTxt)->iTop) % (pTxt)->iMaxLines)
|
|
#define LAST(pTxt) (((pTxt)->iFirst + (pTxt)->iCount-1) % (pTxt)->iMaxLines)
|
|
#define INC(pTxt,x) ((x) = ++(x) % (pTxt)->iMaxLines)
|
|
#define DEC(pTxt,x) ((x) = --(x) % (pTxt)->iMaxLines)
|
|
#define OFFSETX (pTxt->Tdx/2)
|
|
#define OFFSETY 1
|
|
#define VARSIZE 1
|
|
|
|
#define BOUND(x,mn,mx) ((x) < (mn) ? (mn) : ((x) > (mx) ? (mx) : (x)))
|
|
|
|
#define FTwixtI3(l,x,h) ((x)>=(l) && (x<=h))
|
|
|
|
/*
|
|
* 16-Sep-1994 JonPa
|
|
*
|
|
* This critical section stuff was screwed up and caused deadlocks on
|
|
* Chicago, so I have removed it and replaced the functionallity with
|
|
* and interthread SendMessage call. (See IWvwprintf() in wm.c
|
|
*/
|
|
#if 0
|
|
# define EnterCrit(p) EnterCriticalSection(&p->csSync)
|
|
# define LeaveCrit(p) LeaveCriticalSection(&p->csSync)
|
|
#else
|
|
# define EnterCrit(p)
|
|
# define LeaveCrit(p)
|
|
#endif
|
|
|
|
/*----------------------------------------------------------------------------
|
|
*| |
|
|
| g l o b a l v a r i a b l e s |
|
|
| |
|
|
\*----------------------------------------------------------------------------*/
|
|
|
|
typedef struct {
|
|
INT iLen;
|
|
CHAR * *hText;
|
|
} LINE;
|
|
|
|
struct TEXT_STRUCT {
|
|
CRITICAL_SECTION csSync; // CritSect to sync the threads
|
|
|
|
INT iFirst; /* First line in queue */
|
|
INT iCount; /* Number of lines in queue */
|
|
INT iTop; /* Line at top of window */
|
|
INT iLeft; /* X offset of the window */
|
|
INT MaxLen; /* Max String Length */
|
|
INT iMaxLines; /* max number of LINEs */
|
|
HFONT hFont; /* Font to draw with */
|
|
DWORD Tdx, Tdy; /* Font Size */
|
|
LINE arLines[VARSIZE]; /* array of iMaxLines LINEs */
|
|
};
|
|
|
|
typedef struct TEXT_STRUCT *PTXT; /* pointer to a text struct */
|
|
typedef PTXT *HTXT; /* Handle to a text struct */
|
|
|
|
PRIVATE INT iSem = 0;
|
|
|
|
INT tabs[20];
|
|
INT nTabs = 0;
|
|
|
|
/*----------------------------------------------------------------------------
|
|
*| |
|
|
| f u n c t i o n d e f i n i t i o n s |
|
|
| |
|
|
\*----------------------------------------------------------------------------*/
|
|
|
|
LONG APIENTRY PrintfWndProc(HWND, UINT, WPARAM, LONG);
|
|
|
|
PRIVATE VOID DebugPaint(HWND hwnd, LPPAINTSTRUCT pps);
|
|
PRIVATE INT InsertString (PTXT, CHAR *);
|
|
PRIVATE VOID DebugHScroll(HWND, PTXT, INT);
|
|
PRIVATE VOID DebugVScroll(HWND, PTXT, INT);
|
|
PRIVATE BOOL SetWindowClass (HANDLE, LPSTR);
|
|
PRIVATE INT LinesInDebugWindow (HWND);
|
|
PRIVATE INT CharsInDebugWindow (HWND);
|
|
PRIVATE VOID wprintfSetScrollRange (HWND, BOOL);
|
|
PRIVATE VOID NewLine (PTXT pTxt);
|
|
PRIVATE INT mwprintf( HWND hwnd, LPSTR format, ... );
|
|
|
|
|
|
|
|
/*****************************************************************************\
|
|
* MyCreatePrintfWin
|
|
*
|
|
*
|
|
*
|
|
* Arguments:
|
|
*
|
|
*
|
|
*
|
|
* Returns:
|
|
*
|
|
*
|
|
\*****************************************************************************/
|
|
|
|
VOID
|
|
MyCreatePrintfWin(
|
|
HWND hwnd
|
|
)
|
|
{
|
|
RECT rc;
|
|
|
|
if (ghwndPrintf)
|
|
DestroyWindow(ghwndPrintf);
|
|
|
|
GetClientRect(hwnd, &rc);
|
|
|
|
ghwndPrintf = CreatePrintfWin(hwnd, ghInst, "", WS_CHILD | WS_VSCROLL |
|
|
WS_HSCROLL, -gcxBorder, -gcyBorder, rc.right + (2 *gcxBorder),
|
|
rc.bottom + (2 * gcyBorder), gnLines);
|
|
}
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------*|
|
|
| DebugPaint(hwnd, pps) |
|
|
| |
|
|
| Description: |
|
|
| The paint function. |
|
|
| |
|
|
| Arguments: |
|
|
| hwnd Window to paint to. |
|
|
| hDC handle to update region's display context |
|
|
| |
|
|
| Returns: |
|
|
| nothing |
|
|
| |
|
|
\*----------------------------------------------------------------------------*/
|
|
|
|
PRIVATE VOID
|
|
DebugPaint(
|
|
HWND hwnd,
|
|
LPPAINTSTRUCT pps
|
|
)
|
|
{
|
|
PTXT pTxt;
|
|
HTXT hTxt;
|
|
INT iQueue;
|
|
INT xco;
|
|
INT yco;
|
|
INT iLast;
|
|
HBRUSH hb;
|
|
COLORREF c;
|
|
|
|
hTxt = (HTXT)GetWindowLong(hwnd, 0);
|
|
pTxt = *hTxt;
|
|
|
|
SetTextColor(pps->hdc, GetSysColor(COLOR_WINDOWTEXT));
|
|
c = GetSysColor(COLOR_WINDOW);
|
|
SetBkColor(pps->hdc, c);
|
|
hb = CreateSolidBrush(c);
|
|
if (pTxt->hFont)
|
|
SelectObject(pps->hdc, pTxt->hFont);
|
|
|
|
iLast = LAST(pTxt);
|
|
iQueue = TOP(pTxt);
|
|
|
|
xco = OFFSETX - pTxt->iLeft * pTxt->Tdx;
|
|
yco = OFFSETY;
|
|
|
|
for (;;)
|
|
{
|
|
if (yco <= pps->rcPaint.bottom &&
|
|
(yco + (LONG)(pTxt->Tdy)) >= pps->rcPaint.top)
|
|
{
|
|
if (pTxt->arLines[iQueue].hText == NULL
|
|
|| (LPSTR)*(pTxt->arLines[iQueue].hText) == NULL)
|
|
{
|
|
RECT rcT;
|
|
|
|
rcT.top = yco;
|
|
rcT.bottom = yco+pTxt->Tdy;
|
|
rcT.left = pps->rcPaint.left;
|
|
rcT.right = pps->rcPaint.right;
|
|
FillRect(pps->hdc, &rcT, hb);
|
|
}
|
|
else
|
|
{
|
|
TabbedTextOut(pps->hdc, xco, yco,
|
|
(LPSTR)*(pTxt->arLines[iQueue].hText),
|
|
pTxt->arLines[iQueue].iLen, nTabs, tabs, xco);
|
|
}
|
|
}
|
|
|
|
if (iQueue == iLast)
|
|
break;
|
|
|
|
yco += pTxt->Tdy;
|
|
INC(pTxt, iQueue);
|
|
}
|
|
|
|
DeleteObject((HANDLE)hb);
|
|
}
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
*| SetWindowClass (hInstance) |
|
|
| |
|
|
| Description: |
|
|
| Registers a class for a Printf window. |
|
|
| |
|
|
| Arguments: |
|
|
| hInstance instance handle of current instance |
|
|
| |
|
|
| Returns: |
|
|
| TRUE if successful, FALSE if not |
|
|
| |
|
|
\*----------------------------------------------------------------------------*/
|
|
|
|
PRIVATE BOOL
|
|
SetWindowClass(
|
|
HANDLE hInstance,
|
|
LPSTR lpch
|
|
)
|
|
{
|
|
WNDCLASS wc;
|
|
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
wc.lpfnWndProc = PrintfWndProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = sizeof(HANDLE);
|
|
wc.hInstance = hInstance;
|
|
wc.hIcon = NULL;
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = lpch;
|
|
|
|
return RegisterClass(&wc);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
*| CreatePrintfWin (hParent, lpchName, dwStyle, x, y, dx, dy, iMaxLines) |
|
|
| |
|
|
| Description: |
|
|
| Creates a window for the depositing of debuging messages. |
|
|
| |
|
|
| Arguments: |
|
|
| hwnd - Window handle of the parent window. |
|
|
| hInstance - Module instance handle.. |
|
|
| pcName - String to appear in the caption bar of the debuging window |
|
|
| dwStyle - Window style |
|
|
| x,y - Location of window |
|
|
| dx,dy - Size of the window |
|
|
| iMaxLines - The maximum number of text lines to display in the window |
|
|
| |
|
|
| Returns: |
|
|
| A window handle of the debuging window, or NULL if a error occured. |
|
|
| |
|
|
\*----------------------------------------------------------------------------*/
|
|
PUBLIC HWND APIENTRY
|
|
CreatePrintfWin (
|
|
HWND hParent,
|
|
HANDLE hInstance,
|
|
LPSTR lpchName,
|
|
DWORD dwStyle,
|
|
INT x,
|
|
INT y,
|
|
INT dx,
|
|
INT dy,
|
|
INT iMaxLines
|
|
)
|
|
{
|
|
static BOOL bClass = FALSE; /* Is the class registered */
|
|
|
|
HWND hwnd;
|
|
HTXT hTxt; /* handle to a debuging window struct */
|
|
PTXT pTxt;
|
|
static CHAR achClass[40];
|
|
|
|
/*
|
|
* Make a Class name that is unique across instances
|
|
*/
|
|
if (!bClass++) {
|
|
wsprintf(achClass, "WPRINTF_%4.4X", hInstance);
|
|
SetWindowClass(hInstance, achClass);
|
|
}
|
|
|
|
/* Allocate the window long before create the window, such that the
|
|
window proc can find the window long during the create. */
|
|
|
|
hTxt = (HTXT)LocalAlloc(LHND, sizeof(struct TEXT_STRUCT) + (iMaxLines
|
|
- VARSIZE) * sizeof(LINE));
|
|
|
|
if (!hTxt) {
|
|
return FALSE;
|
|
}
|
|
|
|
pTxt = *hTxt;
|
|
|
|
//InitializeCriticalSection(&pTxt->csSync);
|
|
|
|
pTxt->iFirst = 0; /* Set the queue up to have 1 NULL line */
|
|
pTxt->iCount = 1;
|
|
pTxt->iTop = 0;
|
|
pTxt->iLeft = 0;
|
|
pTxt->MaxLen = 0;
|
|
pTxt->iMaxLines = iMaxLines;
|
|
pTxt->arLines[0].hText = NULL;
|
|
pTxt->arLines[0].iLen = 0;
|
|
|
|
hwnd = CreateWindow((LPSTR)achClass, (LPSTR)lpchName, dwStyle, x, y,
|
|
dx, dy, (HWND)hParent, /* parent window */
|
|
(HMENU)NULL, /* use class menu */
|
|
(HANDLE)hInstance, /* handle to window instance */
|
|
(LPSTR)hTxt /* used by WM_CREATE to set the window long */
|
|
);
|
|
|
|
if (!hwnd) {
|
|
return FALSE;
|
|
}
|
|
|
|
wprintfSetScrollRange(hwnd, FALSE);
|
|
|
|
/* Make window visible */
|
|
ShowWindow(hwnd, SHOW_OPENWINDOW);
|
|
return hwnd;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
*| SetPrintfFont (hwnd,hFont) |
|
|
| |
|
|
| Description: |
|
|
| |
|
|
| Arguments: |
|
|
| hwnd - Window handle of the printf window. |
|
|
| hFont - Font handle |
|
|
| |
|
|
| Returns: |
|
|
| |
|
|
\*----------------------------------------------------------------------------*/
|
|
|
|
VOID
|
|
SetPrintfFont(
|
|
HWND hwnd,
|
|
HFONT hfont
|
|
)
|
|
{
|
|
PTXT pTxt;
|
|
HDC hDC;
|
|
TEXTMETRIC tm;
|
|
HFONT hfontOld;
|
|
|
|
pTxt = *(HTXT)GetWindowLong(hwnd, 0);
|
|
pTxt->hFont = hfont;
|
|
|
|
/* Find out the size of a Char in the font */
|
|
hDC = GetDC(hwnd);
|
|
hfontOld = SelectObject(hDC, hfont);
|
|
DeleteObject(hfontOld);
|
|
GetTextMetrics(hDC, &tm);
|
|
pTxt->Tdy = tm.tmHeight;
|
|
pTxt->Tdx = tm.tmAveCharWidth;
|
|
ReleaseDC(hwnd, hDC);
|
|
|
|
CalculatePrintfTabs(hfont);
|
|
|
|
InvalidateRect(hwnd, NULL, TRUE);
|
|
UpdateWindow(hwnd);
|
|
}
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
*| SetPrintfTabs |
|
|
| |
|
|
| Returns: |
|
|
| |
|
|
\*----------------------------------------------------------------------------*/
|
|
|
|
VOID
|
|
SetPrintfTabs(
|
|
INT n,
|
|
LPINT pTabs
|
|
)
|
|
{
|
|
INT i;
|
|
|
|
nTabs = n;
|
|
for (i = 0; i < nTabs; i++)
|
|
tabs[i] = *pTabs++;
|
|
}
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
*| ClearPrintfWindow
|
|
| |
|
|
| Clear all text from the window |
|
|
| |
|
|
| Arguments: |
|
|
| hwnd window handle for the Degubing window |
|
|
| |
|
|
\*----------------------------------------------------------------------------*/
|
|
|
|
VOID
|
|
ClearPrintfWindow(
|
|
HWND hwnd
|
|
)
|
|
{
|
|
INT i, iQueue;
|
|
PTXT pTxt;
|
|
HTXT hTxt;
|
|
|
|
if (hwnd != NULL && IsWindow(hwnd)) {
|
|
hTxt = (HTXT)GetWindowLong(hwnd, 0);
|
|
pTxt = *hTxt;
|
|
|
|
EnterCrit(pTxt);
|
|
|
|
iQueue = TOP(pTxt);
|
|
for (i = 0; i < (pTxt)->iCount; i++, INC(pTxt, iQueue))
|
|
if ((pTxt)->arLines[iQueue].hText != NULL) {
|
|
LocalFree ((HANDLE)pTxt->arLines[iQueue].hText);
|
|
pTxt->arLines[iQueue].hText = NULL;
|
|
}
|
|
|
|
pTxt->iFirst = 0; /* Set the queue up to have 1 NULL line */
|
|
pTxt->iCount = 1;
|
|
pTxt->iTop = 0;
|
|
pTxt->iLeft = 0;
|
|
pTxt->MaxLen = 0;
|
|
pTxt->arLines[0].hText = NULL;
|
|
pTxt->arLines[0].iLen = 0;
|
|
|
|
wprintfSetScrollRange(hwnd, FALSE);
|
|
InvalidateRect(hwnd, NULL, TRUE);
|
|
|
|
LeaveCrit(pTxt);
|
|
}
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
*| |
|
|
| w i n d o w p r o c s |
|
|
| |
|
|
\*----------------------------------------------------------------------------*/
|
|
|
|
/*----------------------------------------------------------------------------
|
|
*| PrintfWndProc( hwnd, uiMessage, wParam, lParam ) |
|
|
| |
|
|
| Description: |
|
|
| The window proc for the debugging window. This processes all |
|
|
| of the window's messages. |
|
|
| |
|
|
| Arguments: |
|
|
| hwnd window handle for the parent window |
|
|
| uiMessage message number |
|
|
| wParam message-dependent |
|
|
| lParam message-dependent |
|
|
| |
|
|
| Returns: |
|
|
| 0 if processed, nonzero if ignored |
|
|
| |
|
|
\*----------------------------------------------------------------------------*/
|
|
PUBLIC LONG APIENTRY
|
|
PrintfWndProc(
|
|
HWND hwnd,
|
|
UINT uiMessage,
|
|
WPARAM wParam,
|
|
LONG lParam
|
|
)
|
|
{
|
|
PAINTSTRUCT rPS;
|
|
HTXT hTxt;
|
|
PTXT pTxt;
|
|
|
|
hTxt = (HTXT)GetWindowLong(hwnd, 0);
|
|
|
|
if ( hTxt ) {
|
|
pTxt = *hTxt;
|
|
}
|
|
|
|
switch (uiMessage) {
|
|
case WM_CREATE:
|
|
{
|
|
/* set the WindowLong before any other message tries to
|
|
* reference it during the create of a window
|
|
*/
|
|
LPCREATESTRUCT csWindowLong = (LPCREATESTRUCT) lParam;
|
|
|
|
hTxt = (HTXT)csWindowLong->lpCreateParams;
|
|
|
|
SetWindowLong(hwnd, 0, (LONG)hTxt);
|
|
SetPrintfFont(hwnd, ghfontPrintf);
|
|
wprintfSetScrollRange(hwnd, FALSE);
|
|
}
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
{
|
|
INT i, iQueue;
|
|
|
|
EnterCrit(pTxt);
|
|
|
|
iQueue = TOP(pTxt);
|
|
for (i = 0; i < (pTxt)->iCount; i++, INC(pTxt, iQueue))
|
|
if ((pTxt)->arLines[iQueue].hText != NULL) {
|
|
LocalFree ((HANDLE)(pTxt)->arLines[iQueue].hText);
|
|
pTxt->arLines[iQueue].hText = NULL;
|
|
}
|
|
|
|
LeaveCrit(pTxt);
|
|
// DeleteCriticalSection(&pTxt->csSync);
|
|
|
|
LocalFree((HANDLE)hTxt);
|
|
break;
|
|
}
|
|
|
|
case WM_SIZE:
|
|
EnterCrit(pTxt);
|
|
if (!iSem) {
|
|
wprintfSetScrollRange(hwnd, TRUE);
|
|
}
|
|
DebugVScroll(hwnd, pTxt, 0);
|
|
LeaveCrit(pTxt);
|
|
break;
|
|
|
|
case WM_VSCROLL:
|
|
EnterCrit(pTxt);
|
|
|
|
switch (LOWORD(wParam)) {
|
|
case SB_LINEDOWN:
|
|
DebugVScroll(hwnd, pTxt, 1);
|
|
break;
|
|
case SB_LINEUP:
|
|
DebugVScroll(hwnd, pTxt, -1);
|
|
break;
|
|
case SB_PAGEUP:
|
|
DebugVScroll(hwnd, pTxt, -LinesInDebugWindow(hwnd));
|
|
break;
|
|
case SB_PAGEDOWN:
|
|
DebugVScroll(hwnd, pTxt, LinesInDebugWindow(hwnd));
|
|
break;
|
|
case SB_THUMBTRACK:
|
|
case SB_THUMBPOSITION:
|
|
DebugVScroll(hwnd, pTxt, HIWORD(wParam) - pTxt->iTop);
|
|
break;
|
|
case SB_ENDSCROLL:
|
|
break;
|
|
}
|
|
|
|
LeaveCrit(pTxt);
|
|
break;
|
|
|
|
case WM_HSCROLL:
|
|
EnterCrit(pTxt);
|
|
|
|
switch (LOWORD(wParam)) {
|
|
case SB_LINEDOWN:
|
|
DebugHScroll (hwnd, pTxt, 1);
|
|
break;
|
|
case SB_LINEUP:
|
|
DebugHScroll (hwnd, pTxt, -1);
|
|
break;
|
|
case SB_PAGEUP:
|
|
DebugHScroll (hwnd, pTxt, -CharsInDebugWindow(hwnd));
|
|
break;
|
|
case SB_PAGEDOWN:
|
|
DebugHScroll (hwnd, pTxt, CharsInDebugWindow(hwnd));
|
|
break;
|
|
case SB_THUMBTRACK:
|
|
case SB_THUMBPOSITION:
|
|
DebugHScroll(hwnd, pTxt, HIWORD(wParam) - pTxt->iLeft);
|
|
break;
|
|
case SB_ENDSCROLL:
|
|
break;
|
|
}
|
|
|
|
LeaveCrit(pTxt);
|
|
break;
|
|
|
|
case WM_PAINT:
|
|
EnterCrit(pTxt);
|
|
|
|
BeginPaint(hwnd, (LPPAINTSTRUCT) & rPS);
|
|
DebugPaint(hwnd, &rPS);
|
|
EndPaint(hwnd, (LPPAINTSTRUCT) & rPS);
|
|
|
|
LeaveCrit(pTxt);
|
|
break;
|
|
|
|
case WM_KEYDOWN:
|
|
EnterCrit(pTxt);
|
|
|
|
switch (wParam) {
|
|
case VK_UP:
|
|
DebugVScroll(hwnd, pTxt, -1);
|
|
break;
|
|
case VK_DOWN:
|
|
DebugVScroll(hwnd, pTxt, 1);
|
|
break;
|
|
case VK_PRIOR:
|
|
DebugVScroll(hwnd, pTxt, -LinesInDebugWindow(hwnd));
|
|
break;
|
|
case VK_NEXT:
|
|
DebugVScroll(hwnd, pTxt, LinesInDebugWindow(hwnd));
|
|
break;
|
|
case VK_LEFT:
|
|
DebugHScroll(hwnd, pTxt, -1);
|
|
break;
|
|
case VK_RIGHT:
|
|
DebugHScroll(hwnd, pTxt, 1);
|
|
break;
|
|
}
|
|
|
|
LeaveCrit(pTxt);
|
|
break;
|
|
|
|
case WM_KEYUP:
|
|
break;
|
|
|
|
case WM_VWPRINTF:
|
|
return mwprintf( hwnd, (LPSTR)"%s", (LPSTR)wParam );
|
|
|
|
default:
|
|
return DefWindowProc(hwnd, uiMessage, wParam, lParam);
|
|
}
|
|
return 0L;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
*| |
|
|
\*----------------------------------------------------------------------------*/
|
|
PRIVATE VOID
|
|
DebugVScroll(
|
|
HWND hwnd,
|
|
PTXT pTxt,
|
|
INT n
|
|
)
|
|
{
|
|
RECT rect;
|
|
INT iMinPos, iMaxPos;
|
|
|
|
DPRINT((">>>>DVS: Req Scrl %d lines\n", n));
|
|
|
|
GetScrollRange(hwnd, SB_VERT, (LPINT) &iMinPos, (LPINT) &iMaxPos);
|
|
GetClientRect(hwnd, (LPRECT) &rect);
|
|
rect.left += OFFSETX;
|
|
rect.top += OFFSETY;
|
|
|
|
|
|
n = BOUND(pTxt->iTop + n, iMinPos, iMaxPos) - pTxt->iTop;
|
|
|
|
DPRINT((">>>>DVS: n:%d\tiTop:%d\tiMin:%d\tiMax:%d\n", n, pTxt->iTop, iMinPos, iMaxPos));
|
|
|
|
if (n == 0)
|
|
return;
|
|
|
|
pTxt->iTop += n;
|
|
|
|
DPRINT((">>>>DVS: Scrolling %d lines (iTop=%d)\n", n, pTxt->iTop ));
|
|
|
|
ScrollWindow(hwnd, 0, -n * pTxt->Tdy, (LPRECT) &rect, (LPRECT) &rect);
|
|
SetScrollPos(hwnd, SB_VERT, pTxt->iTop, TRUE);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
*| |
|
|
\*----------------------------------------------------------------------------*/
|
|
PRIVATE VOID
|
|
DebugHScroll(
|
|
HWND hwnd,
|
|
PTXT pTxt,
|
|
INT n
|
|
)
|
|
{
|
|
RECT rect;
|
|
INT iMinPos, iMaxPos;
|
|
|
|
GetScrollRange (hwnd, SB_HORZ, (LPINT) &iMinPos, (LPINT) &iMaxPos);
|
|
GetClientRect (hwnd, (LPRECT) & rect);
|
|
rect.left += OFFSETX;
|
|
rect.top += OFFSETY;
|
|
|
|
n = BOUND(pTxt->iLeft + n, iMinPos, iMaxPos) - pTxt->iLeft;
|
|
if (n == 0)
|
|
return;
|
|
|
|
pTxt->iLeft += n;
|
|
ScrollWindow(hwnd, -n * pTxt->Tdx, 0, (LPRECT) & rect, (LPRECT) & rect);
|
|
SetScrollPos(hwnd, SB_HORZ, pTxt->iLeft, TRUE);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
*| |
|
|
\*----------------------------------------------------------------------------*/
|
|
PRIVATE INT
|
|
LinesInDebugWindow (
|
|
HWND hwnd
|
|
)
|
|
{
|
|
RECT CRect;
|
|
PTXT pTxt;
|
|
|
|
pTxt = *(HTXT)GetWindowLong(hwnd, 0);
|
|
GetClientRect(hwnd, &CRect);
|
|
if ( pTxt->Tdy == 0 ) {
|
|
return 0;
|
|
}
|
|
return pTxt ? (CRect.bottom - CRect.top - OFFSETY) / pTxt->Tdy : 0;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
*| |
|
|
\*----------------------------------------------------------------------------*/
|
|
PRIVATE INT
|
|
CharsInDebugWindow (
|
|
HWND hwnd
|
|
)
|
|
{
|
|
RECT CRect;
|
|
PTXT pTxt;
|
|
|
|
pTxt = *(HTXT)GetWindowLong (hwnd, 0);
|
|
GetClientRect(hwnd, (LPRECT) & CRect);
|
|
if ( pTxt->Tdx == 0 ) {
|
|
return 0;
|
|
}
|
|
return pTxt ? (CRect.right - CRect.left - OFFSETX) / pTxt->Tdx : 0;
|
|
}
|
|
|
|
|
|
PRIVATE INT
|
|
mwprintf(
|
|
HWND hwnd,
|
|
LPSTR format,
|
|
...
|
|
)
|
|
{
|
|
va_list marker;
|
|
INT i;
|
|
|
|
va_start(marker, format);
|
|
|
|
i = vwprintf(hwnd, format, marker);
|
|
|
|
va_end(marker);
|
|
|
|
return i;
|
|
}
|
|
|
|
|
|
PUBLIC INT FAR cdecl
|
|
vwprintf(
|
|
HWND hwnd,
|
|
LPSTR format,
|
|
va_list marker
|
|
)
|
|
{
|
|
static HWND hwndLast = NULL;
|
|
static CHAR pchBuf[MAXBUFLEN];
|
|
RECT rect, rcClient;
|
|
INT iRet;
|
|
INT cLinesDisplayed; // lines of output to show
|
|
INT cLinesFitInWindow; // lines that can fit in the current window
|
|
INT cLinesNew; // how much left to scroll
|
|
PTXT pTxt;
|
|
HTXT hTxt;
|
|
BOOL fNoScrollB;
|
|
|
|
if (hwnd == NULL)
|
|
hwnd = hwndLast;
|
|
|
|
if (hwnd == NULL || !IsWindow(hwnd))
|
|
return 0; /* exit if bad window handle */
|
|
|
|
hwndLast = hwnd;
|
|
|
|
//
|
|
// First format the line and wait until we can play with the Txt structure
|
|
//
|
|
iRet = wvsprintf((LPSTR)pchBuf, format, marker);
|
|
hTxt = (HTXT)GetWindowLong(hwnd, 0);
|
|
pTxt = (PTXT)LocalLock((HANDLE)hTxt);
|
|
|
|
EnterCrit(pTxt);
|
|
|
|
//
|
|
// Number of lines that we can display stuff in
|
|
//
|
|
cLinesFitInWindow = LinesInDebugWindow(hwnd);
|
|
|
|
DPRINT(("LnDW:%d\tMxL:%d\t", cLinesFitInWindow, pTxt->iMaxLines));
|
|
|
|
if (cLinesFitInWindow > pTxt->iMaxLines) {
|
|
fNoScrollB = TRUE;
|
|
cLinesFitInWindow = pTxt->iMaxLines;
|
|
} else {
|
|
fNoScrollB = FALSE;
|
|
}
|
|
|
|
//
|
|
// Number of lines actually displayed in the current window
|
|
//
|
|
cLinesDisplayed = min(pTxt->iCount, cLinesFitInWindow);
|
|
|
|
DPRINT(("cLFit:%d\tcLDsp:%d\t", cLinesFitInWindow, cLinesDisplayed));
|
|
|
|
|
|
//
|
|
// Return value is number of new lines to display
|
|
//
|
|
cLinesNew = InsertString(pTxt, pchBuf);
|
|
|
|
DPRINT(("cLNew:%d\n", cLinesNew));
|
|
|
|
//
|
|
// Now make sure the new text is painted only if visable
|
|
//
|
|
GetClientRect(hwnd, (LPRECT) & rect);
|
|
rcClient = rect;
|
|
|
|
|
|
//
|
|
// Calculate how much of the window to invalidate
|
|
//
|
|
rect.top += (cLinesDisplayed - 1) * pTxt->Tdy;
|
|
|
|
InvalidateRect(hwnd, (LPRECT)&rect, TRUE);
|
|
|
|
//
|
|
// If we have more lines than we can display, scroll the window
|
|
// such that the last line printed is now at the bottom
|
|
//
|
|
if (cLinesDisplayed + cLinesNew > cLinesFitInWindow) {
|
|
cLinesNew = cLinesDisplayed + cLinesNew - cLinesFitInWindow;
|
|
|
|
if (fNoScrollB) {
|
|
rcClient.bottom = cLinesDisplayed * pTxt->Tdy;
|
|
ScrollWindow(hwnd, 0, -cLinesNew * pTxt->Tdy, (LPRECT) &rcClient, (LPRECT) &rcClient);
|
|
} else {
|
|
wprintfSetScrollRange(hwnd, FALSE);
|
|
DebugVScroll(hwnd, pTxt, cLinesNew);
|
|
}
|
|
LeaveCrit(pTxt);
|
|
} else {
|
|
LeaveCrit(pTxt);
|
|
}
|
|
|
|
LocalUnlock((HANDLE)hTxt);
|
|
|
|
return(iRet); /* return the count of arguments printed */
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
*| |
|
|
\*----------------------------------------------------------------------------*/
|
|
PRIVATE VOID
|
|
wprintfSetScrollRange (
|
|
HWND hwnd,
|
|
BOOL bRedraw
|
|
)
|
|
{
|
|
PTXT pTxt;
|
|
INT iRange;
|
|
int iLeftCritSect = 0;
|
|
|
|
iSem++;
|
|
pTxt = *(HTXT)GetWindowLong(hwnd, 0);
|
|
|
|
/* Update the scroll bars */
|
|
iRange = pTxt->iCount - 1 - LinesInDebugWindow(hwnd);
|
|
|
|
if (iRange < 0) {
|
|
iRange = 0;
|
|
DebugVScroll(hwnd, pTxt, -pTxt->iTop);
|
|
}
|
|
|
|
while (GetCurrentThreadId() == (DWORD)pTxt->csSync.OwningThread) {
|
|
LeaveCrit(pTxt);
|
|
iLeftCritSect++;
|
|
}
|
|
|
|
SetScrollRange(hwnd, SB_VERT, 0, iRange, FALSE);
|
|
SetScrollPos(hwnd, SB_VERT, pTxt->iTop, bRedraw);
|
|
|
|
if (iLeftCritSect) {
|
|
EnterCrit(pTxt);
|
|
}
|
|
|
|
iRange = pTxt->MaxLen - CharsInDebugWindow(hwnd) + 1;
|
|
if (iRange < 0) {
|
|
iRange = 0;
|
|
DebugHScroll(hwnd, pTxt, -pTxt->iLeft);
|
|
}
|
|
|
|
if (iLeftCritSect)
|
|
LeaveCrit(pTxt);
|
|
|
|
SetScrollRange(hwnd, SB_HORZ, 0, iRange, FALSE);
|
|
SetScrollPos(hwnd, SB_HORZ, pTxt->iLeft, bRedraw);
|
|
|
|
while (iLeftCritSect--) {
|
|
EnterCrit(pTxt);
|
|
}
|
|
|
|
iSem--;
|
|
}
|
|
|
|
|
|
PRIVATE VOID
|
|
NewLine (
|
|
PTXT pTxt
|
|
)
|
|
{
|
|
INT iLast = LAST(pTxt);
|
|
|
|
if (pTxt->iCount == pTxt->iMaxLines) {
|
|
LocalFree ((HANDLE)pTxt->arLines[pTxt->iFirst].hText);
|
|
pTxt->arLines[pTxt->iFirst].hText = NULL;
|
|
INC (pTxt, pTxt->iFirst);
|
|
|
|
//BUGBUG - should this be DEC(pTxt, pTxt->iTop)????
|
|
if (pTxt->iTop > 0) {
|
|
pTxt->iTop--;
|
|
}
|
|
} else {
|
|
pTxt->iCount++;
|
|
}
|
|
iLast = LAST(pTxt);
|
|
pTxt->arLines[iLast].hText = NULL;
|
|
pTxt->arLines[iLast].iLen = 0;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
*| |
|
|
\*----------------------------------------------------------------------------*/
|
|
PRIVATE INT
|
|
InsertString (
|
|
PTXT pTxt,
|
|
CHAR *str
|
|
)
|
|
{
|
|
CHAR pchBuf[MAXBUFLEN]; /* intermediate buffer */
|
|
INT iBuf;
|
|
INT iLast = LAST(pTxt);
|
|
INT cLine = 0;
|
|
|
|
for (iBuf = 0; iBuf < pTxt->arLines[iLast].iLen; iBuf++)
|
|
pchBuf[iBuf] = (*pTxt->arLines[iLast].hText)[iBuf];
|
|
|
|
while (*str != '\0') {
|
|
while ((*str != '\n') && (*str != '\0'))
|
|
pchBuf[iBuf++] = *str++;
|
|
|
|
if (pTxt->arLines[iLast].hText != NULL)
|
|
LocalFree((HANDLE)pTxt->arLines[iLast].hText);
|
|
|
|
/* Test for the case of a zero length line, Only brian would do this */
|
|
|
|
if (iBuf == 0)
|
|
pTxt->arLines[iLast].hText == NULL;
|
|
else {
|
|
if ((pTxt->arLines[iLast].hText = (CHAR **)LocalAlloc(LHND, iBuf))
|
|
== NULL) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
pTxt->arLines[iLast].iLen = iBuf;
|
|
while (--iBuf >= 0 )
|
|
(*pTxt->arLines[iLast].hText)[iBuf] = pchBuf[iBuf];
|
|
|
|
if (*str == '\n') { /* Now do the next string after the \n */
|
|
str++;
|
|
cLine++;
|
|
iBuf = 0;
|
|
NewLine(pTxt);
|
|
INC(pTxt, iLast);
|
|
}
|
|
}
|
|
|
|
return cLine;
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************\
|
|
* CopyToClipboard
|
|
*
|
|
* Copies all lines to the clipboard in text format.
|
|
*
|
|
* Returns:
|
|
* TRUE if successful, FALSE if not.
|
|
*
|
|
\*****************************************************************************/
|
|
|
|
BOOL
|
|
CopyToClipboard(
|
|
VOID
|
|
)
|
|
{
|
|
PTXT pTxt;
|
|
INT iQueue;
|
|
INT cch;
|
|
INT i;
|
|
BOOL fSuccess = FALSE;
|
|
LPSTR pBuf = NULL;
|
|
LPSTR pb;
|
|
|
|
pTxt = *(HTXT)GetWindowLong(ghwndPrintf, 0);
|
|
|
|
EnterCrit(pTxt);
|
|
|
|
iQueue = FIRST(pTxt);
|
|
cch = 0;
|
|
for (i = 0; i < pTxt->iCount; i++, INC(pTxt, iQueue))
|
|
{
|
|
if (pTxt->arLines[iQueue].hText != NULL)
|
|
{
|
|
//
|
|
// Count the characters in the line, plus room for the
|
|
// carriage return and newline.
|
|
//
|
|
cch += pTxt->arLines[iQueue].iLen;
|
|
cch += 2;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add one for the terminating null.
|
|
//
|
|
cch++;
|
|
|
|
if (!(pBuf = (LPSTR)GlobalAlloc(GMEM_DDESHARE, cch * sizeof(TCHAR))))
|
|
{
|
|
LeaveCrit(pTxt);
|
|
return FALSE;
|
|
}
|
|
|
|
pb = pBuf;
|
|
iQueue = FIRST(pTxt);
|
|
for (i = 0; i < pTxt->iCount; i++, INC(pTxt, iQueue))
|
|
{
|
|
if (pTxt->arLines[iQueue].hText != NULL)
|
|
{
|
|
lstrcpy(pb, *pTxt->arLines[iQueue].hText);
|
|
pb += pTxt->arLines[iQueue].iLen;
|
|
*pb++ = '\r';
|
|
*pb++ = '\n';
|
|
}
|
|
}
|
|
|
|
LeaveCrit(pTxt);
|
|
|
|
if (OpenClipboard(ghwndSpyApp))
|
|
{
|
|
EmptyClipboard();
|
|
fSuccess = SetClipboardData(CF_TEXT, pBuf) ? TRUE : FALSE;
|
|
CloseClipboard();
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************\
|
|
* IsPrintfEmpty
|
|
*
|
|
* Used to determine if the printf window is empty or not.
|
|
*
|
|
* Returns:
|
|
* TRUE if the printf window is empty, FALSE if there is at least
|
|
* one line in the window.
|
|
*
|
|
\*****************************************************************************/
|
|
|
|
BOOL
|
|
IsPrintfEmpty(
|
|
VOID
|
|
)
|
|
{
|
|
PTXT pTxt;
|
|
|
|
pTxt = *(HTXT)GetWindowLong(ghwndPrintf, 0);
|
|
|
|
//
|
|
// It is empty if the line count is zero (doesn't currently happen)
|
|
// or if there is only one line and it is NULL.
|
|
//
|
|
return (pTxt->iCount == 0 ||
|
|
(pTxt->iCount == 1 && pTxt->arLines[FIRST(pTxt)].hText == NULL))
|
|
? TRUE : FALSE;
|
|
}
|