📄 wprintf.c
字号:
...
)
{
va_list marker;
INT i;
va_start(marker, format);
i = vwprintf(hwnd, format, marker);
va_end(marker);
return i;
}
/*****************************************************************************\
* vwprintf
*
* variable printf - works like the C runtime printf
*
* Arguments:
* HWND hwnd - handle to the debug window
* LPSTR format - pointer to the format string
* va_list marker - pointer to marker
*
* Returns:
* INT - number of arguments printed
\*****************************************************************************/
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);
if(pTxt == NULL)
return 0; // exit if bad memory block
EnterCrit(pTxt);
//
// Number of lines that we can display stuff in
//
cLinesFitInWindow = LinesInDebugWindow(hwnd);
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);
//
// Return value is number of new lines to display
//
cLinesNew = InsertString(pTxt, pchBuf);
//
// 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 */
}
/*****************************************************************************\
* wprintfSetScrollRange
*
* Sets the scroll range of the debug window
*
* Arguments:
* HWND hwnd - handle to the debug window
* BOOL fRedraw - whether or not to redraw the window
*
* Returns:
* VOID
\*****************************************************************************/
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--;
}
/*****************************************************************************\
* NewLine
*
* Calculates when a new line is needed in the debug window
*
* Arguments:
* PTXT pTxt - pointer to the text
*
* Returns:
* VOID
\*****************************************************************************/
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);
if (pTxt->iTop > 0) {
pTxt->iTop--;
}
} else {
pTxt->iCount++;
}
iLast = LAST(pTxt);
pTxt->arLines[iLast].hText = NULL;
pTxt->arLines[iLast].iLen = 0;
}
/*****************************************************************************\
* InsertString
*
* Inserts a string into the debug window
*
* Arguments:
* PTXT pTxt - pointer to the text
* CHAR *str - pointer to insertion string
*
* Returns:
* INT - Line number at which string was inserted
\*****************************************************************************/
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.
*
* Arguments:
* none
*
* 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.
*
* Arguments:
* none
*
* 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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -