|
|
/*
* WPF.C * * WPF line output/input windows. Taken from the wpf.dll library, * originally written by ToddLa. * * History: * 10/02/86 Todd Laney Created * 04/14/87 toddla Added new function CreateDebugWin * 07/08/87 brianc added iMaxLines parm to CreateDebugWin[dow] * 2/90 russellw moved into Wincom and cleaned up. * 10/1/92 robinsp moved to NT * * NT conversion * remove the tricks on dereferencing and passing a pointer to * the stack in wvsprintf. This means we can't do the printf * thing so have to use a macro, sprintf etc which means wpfprintf * must be coded : * wpfprintf(hwnd, lpszFormat, (args)) * */
#include <windows.h>
#include <mmsystem.h>
#include "wincom.h"
#include "sbtest.h"
#include <stdarg.h>
/*
* This code appears to make use of the fact that a local handle can be * double de-referenced to get the actual pointer that the local handle * refers to. This is a somewhat shady practice.. maybe eliminate it? * */
/*--------------------------------------------------------------------------*\
| | | g e n e r a l c o n s t a n t s | | | \*--------------------------------------------------------------------------*/
#define MAXBUFLEN 200 /* Maximum string length for wprintf */
/* Macros to manipulate the printf window array of lines. This array
* wraps around, thus the need for the modulo arithmetic */ #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 HWinInfo(hwnd) ((HTXT)GetWindowLong((hwnd),0))
#define LockWinInfo(hwnd) ((PTXT)LocalLock((HANDLE)HWinInfo(hwnd)))
#define UnlockWinInfo(hwnd) ((PTXT)LocalUnlock((HANDLE)HWinInfo(hwnd)))
#define VK(vk) ((vk) | 0x0100)
/* The pad values used between the edge of the window and the text.
* x = 1/2 ave char width, y = 1 pixel */ #define OFFSETX (pTxt->Tdx/2)
#define OFFSETY 1
#define VARSIZE 1
#define BOUND(x,min,max) ((x) < (min) ? (min) : ((x) > (max) ? (max) : (x)))
#define SEEK_CUR 1
#define SEEK_END 2
#define SEEK_SET 0
/*--------------------------------------------------------------------------*\
| | | g l o b a l v a r i a b l e s | | | \*--------------------------------------------------------------------------*/ #define QUESIZE 128
/*
* QUEUE STRUCTURE: Support queuing of input characters. * */ typedef struct { int iLen; char ach[QUESIZE]; } QUE; typedef QUE *PQUE; /* pointer to a char que */ typedef PQUE *HQUE; /* handle (**) to a char que */
/*
* WPF WINDOW INSTANCE DATA STRUCTURE * */ typedef struct { int iLen; char **hText; } LINE;
struct TEXT_STRUCT { HWND hwnd; // Window displaying the text
WORD wID; // window ID code, for WM_COMMAND messages
BOOL fScrollSemaphore; WORD wOutputLocation; int iFile; int iFirst; // First line in que
int iCount; // Number of lines in que
int iTop; // Line at top of window
int iLeft; // X offset of the window
int MaxLen; // length of longest string currently stored.
int iMaxLines; // max number of LINEs
int iRangeH; int iRangeV; HFONT hFont; // Font to draw with
int Tdx,Tdy; // Font Size
HQUE hQue; int nTabs; PINT pTabs; 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 */
static int iSem=0; static BOOL gbRedraw=TRUE;
static HWND hwndLast = NULL;
/* External buffer for scratch space */ char bufTmp[MAXBUFLEN]; /* intermediate buffer */
static char szClass[] = "WPFWIN"; static BOOL fInit = FALSE;
/*--------------------------------------------------------------------------*\
| | | f u n c t i o n d e f i n i t i o n s | | | \*--------------------------------------------------------------------------*/
LONG FAR PASCAL PrintfWndProc(HWND, unsigned, UINT, LONG);
void NEAR PASCAL WpfSetFont(HWND hWnd, HFONT hFont); void NEAR PASCAL WpfClear(HWND hWnd); void NEAR PASCAL WpfSetTabs(HWND hwnd, int nTabs, LPINT pTabs); BOOL NEAR PASCAL WpfGetTabs(HWND hwnd, LPINT pTabs); void NEAR PASCAL WpfPaint(HWND hwnd, HDC hdc);
void NEAR PASCAL WpfVScroll(HWND hWnd, PTXT pTxt, int n); void NEAR PASCAL WpfHScroll(HWND hWnd, PTXT pTxt, int n); int NEAR PASCAL LinesInWpfWindow(HWND hWnd); int NEAR PASCAL CharsInWpfWindow(HWND hWnd); void NEAR PASCAL WpfMaxLen(PTXT pTxt); void NEAR PASCAL WpfSetScrollRange(HWND hWnd, BOOL bRedraw);
void NEAR PASCAL NewLine(PTXT pTxt); int NEAR PASCAL ChangeLine(PTXT pTxt, int iLine, LPSTR lpch); int NEAR PASCAL InsertString(PTXT pTxt, LPSTR lpstr);
BOOL NEAR PASCAL EnQueChar(HTXT hTxt, WORD vk); void NEAR PASCAL UpdateCursorPos(PTXT pTxt);
WORD NEAR PASCAL SetOutput(HWND hwnd, UINT wParam, LONG lParam); WORD NEAR PASCAL GetOutput(HWND hwnd);
BOOL NEAR PASCAL wpfWrtTTY(HWND hWnd, LPSTR sz);
// BOOL FAR PASCAL DbgDestroy(HWND hwnd);
void wpfWrtFile(int fh, LPSTR sz);
/*
* fSuccess = WpfInit(hInst) * * Register the WinPrintf window class. * */ BOOL FAR PASCAL WpfInit(HANDLE hInstance);
#pragma alloc_text(init, WpfInit)
BOOL FAR PASCAL WpfInit(HANDLE hInstance) { WNDCLASS rClass;
if (!fInit) { rClass.hCursor = LoadCursor(NULL,IDC_ARROW); rClass.hIcon = (HICON)NULL; rClass.lpszMenuName = (LPSTR)NULL; rClass.lpszClassName = szClass; rClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); rClass.hInstance = hInstance; rClass.style = CS_GLOBALCLASS; rClass.lpfnWndProc = PrintfWndProc; rClass.cbWndExtra = sizeof (HTXT); rClass.cbClsExtra = 0;
if (!RegisterClass(&rClass)) return FALSE;
fInit++; }
return TRUE; }
/*
* @doc EXTERNAL WINCOM WPFWINDOW * * @api HWND | wpfCreateWindow | This function creates a * text output window. WPF windows allow <f printf> style output * and line oriented input. WPF windows also remember a fixed number of * lines of previous output for scrolling back. * * @parm HWND | hwndParent | Specifies the parent window. * * @parm HANDLE | hInst | Specifies the module instance handle of the * DLL owner. If the parameter is NULL, the module instance handle of * the WINCOM DLL is used. * * @parm LPSTR | lpszTitle | Points to the window title. This * information is ignored when the style specified by <p dwStyle> does * not create a title bar for the window. * * @parm DWORD | dwStyle | Specifies the window style flags. All * standard window style flags are valid. The WPF window class also defines * the following additional flags: * * @flag WPF_CHARINPUT | The WPF window allows the user to input * characters and sends its parent <m WPF_NCHAR> and <m WPF_NTEXT> messages. * * @parm WORD | x | Specifies the x position of the window. * @parm WORD | y | Specifies the y position of the window. * @parm WORD | dx | Specifies the width of the window. * @parm WORD | dy | Specifies the height of the window. * * @parm int | iMaxLines | Specifies the maximum number of lines that * the WPF window remembers for scrolling purposes. If this * parameter is zero, a default value of 100 is supplied. * * @parm WORD | wID | Specifies the window ID of the WPF window. This * code is used in WM_COMMAND message to notify the owner of the WPF * window when key events have occurred. * * @rdesc Returns the window handle of the new WPF window, or NULL if * an error occurs. The returned window handle may be used with the * normal Windows window-management APIs. * * @comm A WPF window behaves like a partial Windows control. The * owner may change the parameters of a WPF window by sending control * messages (including WM_SETFONT, WM_GETFONT, and the WPF messages * documented with the WINCOM DLL). The WPF window notifies its owner * of state changes by sending the owner WM_COMMAND messages with a * control ID of <p wID>. WPF windows are not full controls, however, * as they cannot be used in dialog boxes. WPF windows also do not * respond to WM_GETTEXT and WM_SETTEXT messages. * */ HWND FAR PASCAL wpfCreateWindow(HWND hwndParent, HANDLE hInst,LPSTR lpszTitle, DWORD dwStyle, WORD x, WORD y, WORD dx, WORD dy, int iMaxLines, WORD wID) { HWND hWnd;
if (!fInit) if (!WpfInit(ghInst)) /* Return NULL if the class could not be registered */ return NULL;
if (iMaxLines == 0) iMaxLines = 100;
if (hInst == NULL) hInst = ghInst;
hWnd = CreateWindow((LPSTR)szClass, (LPSTR)lpszTitle, dwStyle, x,y, dx,dy, (HWND) hwndParent, (HMENU) NULL, (HANDLE) hInst, (LPSTR) MAKELONG(iMaxLines, wID) );
return hWnd; }
/*****************************************************
* * UTILITY PROCEDURES * *****************************************************/
/*
* WpfSetFont(hwnd, hfont) * * Changes the font of a winprintf window to be the specified handle. * Rebuilds the internal character size measurements, and causes the * window to repaint. * * Is there a problem with scroll ranges changing here? * */ void NEAR PASCAL WpfSetFont(HWND hWnd, HFONT hFont) { PTXT pTxt; HDC hDC; TEXTMETRIC tm;
pTxt = LockWinInfo(hWnd);
pTxt->hFont = hFont;
/* Find out the size of a Char in the font */ hDC = GetDC(hWnd); SelectObject(hDC, hFont); GetTextMetrics(hDC, (LPTEXTMETRIC) &tm); pTxt->Tdy = tm.tmHeight; pTxt->Tdx = tm.tmAveCharWidth; ReleaseDC (hWnd, hDC); InvalidateRect(hWnd, NULL, TRUE); UnlockWinInfo(hWnd); }
/*
* WpfClear(hwnd) * * Clears all text from the window. Frees all allocated memory. The * current queue is not modified? * */ void NEAR PASCAL WpfClear(HWND hWnd) { int i,iQue; PTXT pTxt;
pTxt = LockWinInfo(hWnd);
iQue = FIRST(pTxt); for (i=0; i < pTxt->iCount; i++, INC(pTxt,iQue)) if (pTxt->arLines[iQue].hText != NULL) LocalFree((HANDLE) pTxt->arLines[iQue].hText);
pTxt->iFirst = 0; /* Set the que 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;
UnlockWinInfo(hWnd);
InvalidateRect(hWnd,NULL,TRUE); WpfSetScrollRange(hWnd,TRUE); UpdateWindow(hWnd); }
/*
* WpfSetTabs(hwnd, nTabs, pTabs) * * Sets up hwnd to use the tabs stops specified by pTabs. Copies these * tabs into a local-alloc'ed buffer. Any pre-existing tab stops are * deallocated. * */ void NEAR PASCAL WpfSetTabs(HWND hwnd, int nTabs, LPINT pTabs) { PTXT pTxt; int i;
pTxt = LockWinInfo(hwnd);
/* Discard old tabs, allocate space for new tab settings */ if (pTxt->pTabs) LocalFree((HANDLE)pTxt->pTabs);
if (pTabs == NULL || nTabs == 0) { pTxt->pTabs = NULL; pTxt->nTabs = 0; } else { pTxt->pTabs = (PINT)LocalAlloc(LPTR, nTabs * sizeof(int)); pTxt->nTabs = nTabs;
/* Copy caller's tab settings into the current tab table */ if (pTxt->pTabs) { for (i=0; i < nTabs; i++) pTxt->pTabs[i] = *pTabs++; } }
InvalidateRect(hwnd,NULL,TRUE); UnlockWinInfo(hwnd); }
/*
* fIsTabs = WpfGetTabs(hwnd, pTabs) * * Responds to a WPF_GETTABSTOPS message by filling in the supplied * buffer with the current tab settings. Returns TRUE if there are tabs * stops, or FALSE if there aren't any tab stops in use. * */ BOOL NEAR PASCAL WpfGetTabs(HWND hwnd, LPINT pTabs) { PTXT pTxt; int i;
pTxt = LockWinInfo(hwnd);
/* If there are no current tabs, return FALSE */ if (pTxt->nTabs == 0 || pTxt->pTabs == NULL) { UnlockWinInfo(hwnd); return FALSE; }
/* Otherwise, copy my tabs into the caller's buffer. Assume
* that the caller's buffer is large enough. */ for (i=0; i < pTxt->nTabs; i++) { *pTabs++ = pTxt->pTabs[i]; }
UnlockWinInfo(hwnd); return TRUE; }
/***********************************
* * WINDOW PROCEDURE * ***********************************/
/*--------------------------------------------------------------------------*\
| WpfPaint(hWnd, hDC ) | | | | Description: | | The paint function. | | | | Arguments: | | hWnd Window to paint to. | | hDC handle to update region's display context | | | | Returns: | | nothing | | | \*--------------------------------------------------------------------------*/ void NEAR PASCAL WpfPaint(HWND hwnd, HDC hdc) { PTXT pTxt; int i; int iQue; int xco; int yco; int iLast; RECT rc; RECT rcClip; HFONT hfontOld;
//LockData(0); /* need from spy DS not locked! */
pTxt = LockWinInfo(hwnd);
GetClientRect(hwnd, &rc); rc.left += OFFSETX; rc.top += OFFSETY; IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom); SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
/* If a font (other than the system font) has been specified, use it */ if (pTxt->hFont) hfontOld = SelectObject(hdc, pTxt->hFont);
/* Setup counters as appropriate. Get indexes of first and last
* lines visible within the window. */ iLast = LAST(pTxt); iQue = TOP(pTxt); /* The x and y initial points for the text line.
* xco is shifted left to account for any horizonal scrolling * that may be going on */ xco = OFFSETX - pTxt->iLeft * pTxt->Tdx; // shifted for h-scrolling
yco = OFFSETY; // starting y pix value
/* RC is the bounding rect for the current line.
* * Calc initial line bounding rect.. top = top of window (padded), * bottom = top + height of one line. */ rc.left = xco; rc.top = yco; rc.bottom = yco + pTxt->Tdy;
/* Get the clipping rectangle */ GetClipBox(hdc, &rcClip);
/* Iter over all lines that are visible - if the bounding rect
* for the current line intersects the clip rect, draw the line. */ for (;;) { if (rc.bottom >= rcClip.top) { /* If we're using tabs, then tab out the text.
*/ char *pStr; pStr = LocalLock(pTxt->arLines[iQue].hText); if (pTxt->nTabs > 0) { /* Erase the background */ ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
/* Using *pTxt->arLines[iQue].hText returns the local
* string that is refered to by local handle hText. */ TabbedTextOut(hdc, xco, yco, (LPSTR)pStr, pTxt->arLines[iQue].iLen, pTxt->nTabs, pTxt->pTabs, xco); } else { /* Otherwise, blow it out using ExtTextOut */ ExtTextOut(hdc, xco, yco, ETO_OPAQUE, &rc, (LPSTR)pStr, pTxt->arLines[iQue].iLen, NULL); } LocalUnlock(pTxt->arLines[iQue].hText); }
/* Bail out when finished printing window contents */ if (iQue == iLast) break;
INC(pTxt, iQue); /* Advance the boundry rect & char positions down one line */ yco = rc.top = rc.bottom; rc.bottom += pTxt->Tdy;
if (yco > rcClip.bottom) break; }
/* Restore the old font */ if (hfontOld) SelectObject(hdc, hfontOld);
// UnlockData(0);
}
LONG FAR PASCAL PrintfWndProc(HWND hWnd, unsigned uiMessage, UINT wParam, LONG lParam) { PAINTSTRUCT rPS; PTXT pTxt; HTXT hTxt; int i; int iQue; DWORD rc = 0L;
hTxt = (HTXT)GetWindowLong(hWnd,0); if (hTxt) pTxt = LocalLock(hTxt);
#define lpCreate ((LPCREATESTRUCT)lParam)
switch (uiMessage) { case WM_CREATE: i = LOWORD((DWORD)lpCreate->lpCreateParams);
/* Allocate and initialize the window instance structure
* The storage for the current lines is placed at the end * end of the instance data structure. allocate room for it. */ hTxt = (HTXT) LocalAlloc(LHND, sizeof(struct TEXT_STRUCT) + (i - VARSIZE) * sizeof(LINE));
if (!hTxt) return -1L;
pTxt = (PTXT)LocalLock((HANDLE)hTxt);
pTxt->hwnd = hWnd; pTxt->wID = HIWORD(lpCreate->lpCreateParams); pTxt->iFile = -1; pTxt->wOutputLocation = WPFOUT_WINDOW; pTxt->iFirst = 0; // initially 1 null line
pTxt->iCount = 1; pTxt->iTop = 0; pTxt->iLeft = 0; // no initial hscroll offset
pTxt->MaxLen = 0; pTxt->iMaxLines = i; pTxt->nTabs = 0; /* If user specified character input, allocate a buffer */ if (lpCreate->style & WPF_CHARINPUT) pTxt->hQue = (HQUE) LocalAlloc(LHND | LMEM_ZEROINIT, sizeof(QUE)); else pTxt->hQue = NULL;
/* Null initial first line */ pTxt->arLines[0].hText = NULL; pTxt->arLines[0].iLen = 0;
/* Store the structure pointer onto the window */ SetWindowLong(hWnd, 0, (LONG) hTxt);
/* Setup to use the system font by default */ WpfSetFont(hWnd, GetStockObject(SYSTEM_FONT));
LocalUnlock((HANDLE) hTxt); return 0L;
case WM_DESTROY: // DbgDestroy(hWnd);
/* Flush any files in use by the window */ SetOutput(hWnd, WPFOUT_DISABLED, 0L);
/* Blow away all lines held by the window */ iQue = FIRST(pTxt); for (i=0; i < pTxt->iCount; i++, INC(pTxt,iQue)) if (pTxt->arLines[iQue].hText != NULL) LocalFree((HANDLE) pTxt->arLines[iQue].hText);
/* And kill char input and tab stop storage */ if (pTxt->hQue) LocalFree ((HANDLE) pTxt->hQue); if (pTxt->pTabs) LocalFree ((HANDLE) pTxt->pTabs);
LocalUnlock(hTxt); LocalFree((HANDLE)hTxt); hTxt = NULL; break;
// case WPF_SETNLINES:
// return 0L;
case WPF_GETNLINES: rc = pTxt->iMaxLines; break;
case WM_GETFONT: rc = pTxt->hFont; break;
case WM_SETFONT: WpfSetFont(hWnd, wParam); break;
/* Tab stop stuff */ case WPF_SETTABSTOPS: WpfSetTabs(hWnd, wParam, (LPINT) lParam); break;
case WPF_GETNUMTABS: rc = pTxt->pTabs ? pTxt->nTabs : 0; break;
case WPF_GETTABSTOPS: rc = (LONG) WpfGetTabs(hWnd, (LPINT) lParam); break;
case WPF_SETOUTPUT: rc = (LONG) SetOutput(hWnd, wParam, lParam); break;
case WPF_GETOUTPUT: rc = (LONG) GetOutput(hWnd); break;
case WPF_CLEARWINDOW: WpfClear(hWnd); break;
case WM_SIZE: /* It is possible to get WM_SIZEs as a result of
* dicking with scrollbars.. Avoid race conditions */ if (!pTxt->fScrollSemaphore) { pTxt->fScrollSemaphore++; WpfSetScrollRange(hWnd, TRUE); UpdateCursorPos(pTxt); pTxt->fScrollSemaphore--; } break;
case WM_VSCROLL: switch (wParam) { case SB_LINEDOWN: WpfVScroll (hWnd,pTxt,1); break; case SB_LINEUP: WpfVScroll (hWnd,pTxt,-1); break; case SB_PAGEUP: WpfVScroll (hWnd,pTxt,-LinesInWpfWindow(hWnd)); break; case SB_PAGEDOWN: WpfVScroll (hWnd,pTxt,LinesInWpfWindow(hWnd)); break; case SB_THUMBTRACK: WpfVScroll (hWnd,pTxt,LOWORD(lParam)-pTxt->iTop); break;
case SB_THUMBPOSITION: WpfVScroll (hWnd,pTxt,LOWORD(lParam)-pTxt->iTop); /* Fall through */
case SB_ENDSCROLL: WpfSetScrollRange(hWnd,TRUE); UpdateCursorPos(pTxt); break; } break;
case WM_HSCROLL: switch (wParam) { case SB_LINEDOWN: WpfHScroll (hWnd, pTxt, 1); break; case SB_LINEUP: WpfHScroll (hWnd, pTxt, -1); break; case SB_PAGEUP: WpfHScroll (hWnd, pTxt, -CharsInWpfWindow(hWnd)); break; case SB_PAGEDOWN: WpfHScroll (hWnd, pTxt, CharsInWpfWindow(hWnd)); break; case SB_THUMBTRACK: WpfHScroll (hWnd, pTxt, LOWORD(lParam) - pTxt->iLeft); break;
case SB_THUMBPOSITION: WpfHScroll (hWnd, pTxt, LOWORD(lParam) - pTxt->iLeft); /* Fall through */
case SB_ENDSCROLL: WpfSetScrollRange(hWnd,TRUE); UpdateCursorPos(pTxt); break; } break;
case WM_PAINT: BeginPaint(hWnd,&rPS); WpfPaint (hWnd,rPS.hdc); EndPaint(hWnd,&rPS); break;
/* Allow keyboard scrolling */ case WM_KEYDOWN: switch (wParam) { case VK_UP: PostMessage (hWnd,WM_VSCROLL,SB_LINEUP,0L); break; case VK_DOWN: PostMessage (hWnd,WM_VSCROLL,SB_LINEDOWN,0L); break; case VK_PRIOR: PostMessage (hWnd,WM_VSCROLL,SB_PAGEUP,0L); break; case VK_NEXT: PostMessage (hWnd,WM_VSCROLL,SB_PAGEDOWN,0L); break;
case VK_HOME: PostMessage (hWnd,WM_HSCROLL,SB_PAGEUP,0L); break; case VK_END: PostMessage (hWnd,WM_HSCROLL,SB_PAGEDOWN,0L); break; case VK_LEFT: PostMessage (hWnd,WM_HSCROLL,SB_LINEUP,0L); break; case VK_RIGHT: PostMessage (hWnd,WM_HSCROLL,SB_LINEDOWN,0L); break; } break;
/* Handle focus messages to hide and show the caret
* if the WPF window allows for character input. */ case WM_SETFOCUS: if (pTxt->hQue) { CreateCaret(hWnd,0,1,pTxt->Tdy); UpdateCursorPos(pTxt); ShowCaret(hWnd); } break;
case WM_KILLFOCUS: if (pTxt->hQue) DestroyCaret(); break;
case WM_CHAR: EnQueChar(hTxt,wParam); break;
case WM_KEYUP: switch (wParam) { case VK_F3: EnQueChar(hTxt,VK(wParam)); break;
/* Send endscroll when the key goes up - allows for
* type-a-matic action. */ case VK_UP: case VK_DOWN: case VK_PRIOR: case VK_NEXT: PostMessage (hWnd,WM_VSCROLL,SB_ENDSCROLL,0L); break;
case VK_HOME: case VK_END: case VK_LEFT: case VK_RIGHT: PostMessage (hWnd,WM_HSCROLL,SB_ENDSCROLL,0L); break; } break;
default: return DefWindowProc(hWnd,uiMessage,wParam,lParam); }
if (hTxt) LocalUnlock(hTxt); return rc; }
/***********************************************
* * SCROLLING STUFF * ***********************************************/
/*
* WpfVScroll(hwnd, pTxt, n) * * Vertical scroll the window by n number of lines. * */ void NEAR PASCAL WpfVScroll(HWND hWnd, PTXT pTxt, int n) { RECT rect; int iRange;
/* GetScrollRange (hWnd,SB_VERT,&iMinPos,&iMaxPos); */ iRange = pTxt->iRangeV; // where did this come from?
GetClientRect(hWnd, &rect); rect.left += OFFSETX; // adjust for pad boundry
rect.top += OFFSETY;
n = BOUND(pTxt->iTop + n, 0, iRange) - pTxt->iTop; pTxt->iTop += n; ScrollWindow(hWnd, 0, -n * pTxt->Tdy, &rect, &rect); SetScrollPos(hWnd, SB_VERT, pTxt->iTop, gbRedraw); UpdateWindow(hWnd); }
/*
* WpfHScroll(hwnd, ptxt, n) * * Horizontally scrolls the window by n number of character widths. * */ void NEAR PASCAL WpfHScroll(HWND hWnd, PTXT pTxt, int n) { RECT rect; int iRange;
/* GetScrollRange (hWnd,SB_HORZ,&iMinPos,&iMaxPos); */ iRange = pTxt->iRangeH; GetClientRect (hWnd,&rect); rect.left += OFFSETX; rect.top += OFFSETY;
n = BOUND(pTxt->iLeft + n, 0, iRange) - pTxt->iLeft; pTxt->iLeft += n; ScrollWindow(hWnd, -n * pTxt->Tdx, 0, &rect, &rect); SetScrollPos(hWnd, SB_HORZ, pTxt->iLeft, gbRedraw); UpdateWindow(hWnd); }
/*
* nLines = LinesInWpfWindow(hwnd) * * Returns the height in lines of the window. * */ int NEAR PASCAL LinesInWpfWindow(HWND hWnd) { RECT rRect; PTXT pTxt; int iLines;
pTxt = *(HTXT) GetWindowLong(hWnd, 0); GetClientRect(hWnd, &rRect); iLines = 0; if (pTxt) { iLines = (rRect.bottom - rRect.top - OFFSETY) / pTxt->Tdy; iLines = min(iLines, pTxt->iMaxLines); } return iLines; }
/*
* nChars = CharsInWpfWindow(hwnd) * * Returns the width in characters of the window. * */ int NEAR PASCAL CharsInWpfWindow(HWND hWnd) { RECT rRect; PTXT pTxt;
pTxt = *(HTXT)GetWindowLong (hWnd,0); GetClientRect(hWnd,&rRect); return pTxt ? (rRect.right - rRect.left - OFFSETX) / pTxt->Tdx : 0; }
/*
* WpfMaxLen(pTxt) * * This function sets the pTxt->MaxLen field to be the length in * characters of the longest string currently being stored by the WPF * window. * */ void NEAR PASCAL WpfMaxLen(PTXT pTxt) { int iQue; int iLast; int iLen; SIZE size; // DWORD dwLen;
// HDC hdc;
#if 0
hdc = GetDC(NULL);
if (pTxt->hFont) SelectObject(hdc, pTxt->hFont); #endif
iLast = LAST(pTxt); iQue = TOP(pTxt); pTxt->MaxLen = 0; for (;;) { iLen = pTxt->arLines[iQue].iLen;
#if 0
if (pTxt->nTabs) dwLen = GetTabbedTextExtent(hdc, (LPSTR) *pTxt->arLines[iQue].hText, iLen, pTxt->nTabs, (LPINT)pTxt->pTabs); else GetTextExtent(hdc, (LPSTR) *pTxt->arLines[iQue].hText,iLen,&size);
iLen = size.cx // pTxt->Tdx + 1;
#endif
if (iLen > pTxt->MaxLen) pTxt->MaxLen = iLen; if (iQue == iLast) break; INC(pTxt,iQue); }
// ReleaseDC(NULL,hdc);
}
/*
* WpfSetScrollRange(hwnd, bRedraw) * * This function sets the scrollbar ranges according to the current * character/line contents of the window. Both the horizontal and * vertical scrollbars are adjusted. * * This function then calls WpfVScroll/WpfHScroll to adjust the * scrollbar position accordingly. * */ void NEAR PASCAL WpfSetScrollRange(HWND hWnd, BOOL bRedraw) { PTXT pTxt; int iRange;
if (pTxt = *(HTXT) GetWindowLong(hWnd, 0)) { gbRedraw = bRedraw; /* Update the scroll bars */
iRange = pTxt->iCount - LinesInWpfWindow(hWnd) + 1;
/* Adjust for blank last line? */ if (pTxt->arLines[LAST(pTxt)].iLen == 0); iRange -= 1;
if (iRange < 0) iRange = 0;
/* Set the scrollbar range to that calculated */ pTxt->iRangeV = iRange; SetScrollRange(hWnd, SB_VERT, 0, iRange, FALSE); WpfVScroll(hWnd, pTxt, 0);
/* Setup the horizontal scrollbar range */ WpfMaxLen(pTxt); iRange = pTxt->MaxLen - CharsInWpfWindow(hWnd) + 1; if (iRange < 0) iRange = 0; pTxt->iRangeH = iRange; SetScrollRange(hWnd, SB_HORZ, 0, iRange, FALSE); WpfHScroll(hWnd, pTxt, 0);
gbRedraw = TRUE; } }
/***********************************************************
* * STUFF TO ADD NEW TEXT LINES * ***********************************************************/
/*
* NewLine(pTxt) * * Adjusts a WPF window when adding a line to the circular array. * iCount is the count of valid lines in the array. If we * haven't yet filled up the array, the count is merely increased. * Otherwise, if the array is full and we're about to wrap around, fixup * the wrap-around. * */ void NEAR PASCAL NewLine(PTXT pTxt) { int iLast = LAST(pTxt); int iLine,cLine; RECT rect;
if (pTxt->iCount == pTxt->iMaxLines) { /* If the array is full, check for wrap-around */ LocalFree ((HANDLE)pTxt->arLines[pTxt->iFirst].hText); pTxt->arLines[pTxt->iFirst].hText = NULL;
INC(pTxt, pTxt->iFirst);
if (pTxt->iTop > 0) pTxt->iTop--; else { GetClientRect (pTxt->hwnd,&rect); rect.left += OFFSETX; rect.top += OFFSETY; ScrollWindow (pTxt->hwnd, 0, -pTxt->Tdy, &rect, &rect); } } else { pTxt->iCount++; } iLast = LAST(pTxt); pTxt->arLines[iLast].hText = NULL; pTxt->arLines[iLast].iLen = 0; }
/*
* fSuccess = ChangeLine(pTxt, iLine, lpsz) * * Changes line number <iLine> to be the string pointed to by lpsz. * Frees any line currently occupying index <iLine>, and then alloc and * stores text lpsz. * */ int NEAR PASCAL ChangeLine(PTXT pTxt, int iLine, LPSTR lpch) { int iLen; LPSTR pData;
if (pTxt->arLines[iLine].hText != NULL) LocalFree((HANDLE)pTxt->arLines[iLine].hText);
iLen = lstrlen(lpch); if ((pTxt->arLines[iLine].hText = (char**)LocalAlloc(LHND,iLen+1))== NULL) return FALSE;
pTxt->arLines[iLine].iLen = iLen; pData = LocalLock(pTxt->arLines[iLine].hText); lstrcpy(pData, lpch); LocalUnlock(pTxt->arLines[iLine].hText); return TRUE; }
/*
*/ int NEAR PASCAL InsertString(PTXT pTxt, LPSTR lpstr) { int iBuf; int iLast = LAST(pTxt); int cLine = 0; char buf[MAXBUFLEN]; buf[0] = '\0';
/*
* copy the string already there */ { PSTR pch; HANDLE hText;
hText = pTxt->arLines[iLast].hText; if (hText) { pch = LocalLock(hText); // (LocalLock eqiv)
iBuf = lstrlen(pch); lstrcpy(buf, pch); // why?
LocalUnlock(pTxt->arLines[iLast].hText); } else { iBuf = 0; } }
while (*lpstr != '\0') { while (*lpstr != '\n' && *lpstr != '\0' && iBuf < MAXBUFLEN-2) switch (*lpstr) {
case '\b': /* Backspace, blow away one character */ iBuf--; lpstr++; break;
case '\r': /* Carriage return, go back to beginning of line */ iBuf = 0; lpstr++; break;
default: /* Otherwise, add this char to line */ buf[iBuf++] = *lpstr++; break; } buf[iBuf++] = 0;
/* Presto chango add the line */ ChangeLine(pTxt, iLast, buf); /* buf must be a asciiz string */
if (*lpstr == '\n') { /* Now do the next string after the \n */ lpstr++; iBuf = 0; cLine++; NewLine(pTxt); INC(pTxt, iLast); } } return cLine; /* the number of new lines added to list */ }
/**********************************************************
* * CHARACTER INPUT STUFF * **********************************************************/
BOOL NEAR PASCAL EnQueChar(HTXT hTxt, WORD vk) { PTXT pTxt; PQUE pQue; int i; HWND hwndP;
pTxt = (PTXT)LocalLock((HANDLE)hTxt);
if (!pTxt->hQue) goto noque;
pQue = (PQUE)LocalLock((HANDLE)pTxt->hQue);
i = pQue->iLen;
switch (vk) { case '\b': if (i > 0) { --i; wpfOut(pTxt->hwnd, "\b"); } break;
case VK(VK_F3): wpfOut(pTxt->hwnd, pQue->ach + i); i += lstrlen(pQue->ach + i); break;
case '\r': case '\n': if (GetKeyState(VK_CONTROL) < 0) { wpfOut(pTxt->hwnd,"\\\n"); } else { wpfOut(pTxt->hwnd, "\n"); pQue->ach[i] = '\0'; if (hwndP = GetParent(pTxt->hwnd)) SendMessage(hwndP, WPF_NTEXT, pTxt->wID, (LONG)(LPSTR)pQue->ach); i = 0; } break;
default: if (i < QUESIZE) { pQue->ach[i] = (char)vk; sprintf(ach, ("%c", vk)); wpfOut(pTxt->hwnd, ach); if (hwndP = GetParent(pTxt->hwnd)) SendMessage(hwndP, WPF_NCHAR, pTxt->wID, (LONG) vk); i++; } else { /* Input que is full, beep to notify */ MessageBeep(0); } break; }
pQue->iLen = i; LocalUnlock((HANDLE)pTxt->hQue);
noque: LocalUnlock((HANDLE)hTxt); return TRUE; }
void NEAR PASCAL UpdateCursorPos(PTXT pTxt) { int iLine; int y,x; int iLen; DWORD dw; HDC hdc; SIZE size; char **h; char *ptxt;
/* If I don't do char input, or don't have the focus, forget it */ if (!pTxt->hQue || GetFocus() != pTxt->hwnd) return;
hdc = GetDC(NULL); SelectObject(hdc, pTxt->hFont); iLen = pTxt->arLines[LAST(pTxt)].iLen - pTxt->iLeft; h = pTxt->arLines[LAST(pTxt)].hText;
// HACK HACK Need to account for tabs?
ptxt = LocalLock(h); dw = GetTextExtentPoint(hdc, (LPSTR) ptxt + pTxt->iLeft, iLen, &size); LocalUnlock(h); iLine = pTxt->iCount - pTxt->iTop; ReleaseDC(NULL,hdc);
y = OFFSETY + (iLine - 1) * pTxt->Tdy; x = OFFSETX + size.cx; SetCaretPos(x,y); }
/*************************************************
* * OUTPUT APIS * *************************************************/
/*
* fSuccess = SetOutput(hwnd, wCommand, lpszFile) * * Changes the output location of the window to be the location * designated by wParam, one of the WPFOUT_ codes. If this specifies a * file, lParam points to the filename. * * If the new output location cannot be opened/used, the previous output * location is not altered and FALSE is returned. Otherwise, the * previous output location is closed (for files) and TRUE is returned. * */ WORD NEAR PASCAL SetOutput(HWND hwnd, UINT wParam, LONG lParam) { PTXT pTxt; int i; HANDLE h; int fhOld = -1;
#define COM1_FH (3) // stdaux
/* Check for invalid command code */ if (!(wParam == WPFOUT_WINDOW || wParam == WPFOUT_COM1 || wParam == WPFOUT_NEWFILE || wParam == WPFOUT_APPENDFILE || wParam == WPFOUT_DISABLED)) { return FALSE; }
h = GetWindowLong(hwnd, 0); pTxt = (PTXT)LocalLock(h);
/* Save the old file handle */ fhOld = pTxt->iFile;
/* If I'm using a file output type, setup the file handle */ switch (wParam) { case WPFOUT_COM1: pTxt->iFile = COM1_FH; break;
case WPFOUT_APPENDFILE: /* Open file to see if it is there, then seek to end */ i = _lopen((LPSTR) lParam, OF_READWRITE); if (i == -1) { /* File didn't exist, just create it */ i = _lcreat((LPSTR) lParam, 0); if (i == -1) { /* Couldn't open, just return FALSE */ LocalUnlock(h); return FALSE; } } else { /* Seek to the end of existing file */ _llseek(i, 0L, 2); }
pTxt->iFile = i; break;
case WPFOUT_NEWFILE: i = _lcreat((LPSTR) lParam, 0); if (i == -1) { LocalUnlock(h); return FALSE; } pTxt->iFile = i; break;
case WPFOUT_DISABLED: case WPFOUT_WINDOW: pTxt->iFile = -1; break;
}
/* Clear any existing open file handle by closing it */ if (fhOld != -1 && fhOld != COM1_FH) { /* Close the file */ _lclose(fhOld); }
pTxt->wOutputLocation = wParam; LocalUnlock(h); return TRUE;
}
/*
* wOutput = GetOutput(hwnd) * * Returns the output location for window hwnd (one of the WPFOUT_ codes) * */ WORD NEAR PASCAL GetOutput(HWND hwnd) { PTXT pTxt; WORD w; HANDLE h;
h = GetWindowLong(hwnd, 0); pTxt = (PTXT) LocalLock(h);
w = pTxt->wOutputLocation;
LocalUnlock(h); return w; }
/*
* @doc EXTERNAL WINCOM WPFWINDOW * * @api int | wpfPrintf | This function prints a string to a WPF window * (or redirected output device) using <f printf> style formatting * codes. The output is placed at the end of the specified WPF window, * which is scrolled as required. This function does not yield. * * @parm HWND | hwnd | Specifies the WPF window. Output to the window * may be redirected to a file or COM1 by sending a WPF_SETOUTPUT window * message to <p hwnd>. If output has been redirected, this parameter * is still required as the current output location is stored in the WPF * window instance data. * * @parm LPSTR | lpszFormat | Points to the output string format * specification. This string uses the same formatting codes as the * Windows <f wsprintf> function. * * @parm argument | [ arguments, ...] | Extra parameters * as required by the * formatting string. Note that these parameters are in the form * required by <p wsprintf>, so that all string arguments must be far * pointers (LPSTR) or be cast to be far pointers. * * @rdesc Returns the number of characters output. If output to * the WPF window is disabled, zero is returned. The returned count of * characters output does not include the translation of newline * characters into carriage return newline sequences. * * @xref wpfVprintf * */ //int FAR cdecl wpfPrintf(HWND hwnd, LPSTR lpszFormat, ...)
//{
// return wpfVprintf(hwnd, lpszFormat, (LPSTR)(&lpszFormat + 1));
//}
/* wpfWrtTTY(hWnd, sz)
* * Print <sz> to wprintf window <hWnd>. * */ BOOL NEAR PASCAL wpfWrtTTY(HWND hWnd, LPSTR sz) { RECT rect; int iFree; int iLine; PTXT pTxt; HTXT hTxt; MSG rMsg; POINT rPoint;
if (!hWnd) hWnd = hwndLast;
if (!hWnd || !IsWindow(hWnd)) return FALSE; /* fail if bad window handle */
hwndLast = hWnd;
hTxt = (HTXT)GetWindowLong (hWnd,0); pTxt = (PTXT)LocalLock((HANDLE)hTxt);
iLine = pTxt->iCount - pTxt->iTop; /*
* invalidate the last line to the bottom of window so * new text will be painted. */ GetClientRect(hWnd,&rect); rect.top += (iLine-1) * pTxt->Tdy; InvalidateRect (hWnd,&rect,FALSE);
InsertString (pTxt, sz); /* Insert text in the que */ iLine = (pTxt->iCount - pTxt->iTop) - iLine;
if (iLine > 0) { WpfSetScrollRange (hWnd,FALSE); WpfVScroll (hWnd,pTxt,pTxt->iCount);/* scroll all the way to bottom */ } #if 0
else { WpfSetScrollRange (hWnd,TRUE); } #endif
UpdateCursorPos(pTxt); LocalUnlock((HANDLE)hTxt); UpdateWindow (hWnd);
return TRUE; }
/*
* @doc EXTERNAL WINCOM WPFWINDOW * * @api int | wpfVprintf | This function prints a string to a WPF window * (or redirected output device) using <f printf> style formatting * codes. This function is the same as the <f wpfOut> function, except * that arguments to the format string are placed in an array of WORDs * or DWORDs. * * @parm HWND | hwnd | Specifies the WPF window. Output to the window * may be redirected to a file or COM1 by sending a WPF_SETOUTPUT window * message to <p hwnd>. If output has been redirected, this parameter * is still required as the current output location is stored in the WPF * window instance data. * * @parm LPSTR | lpszFormat | Points to the output string format * specification. This string uses the same formatting codes as the * Windows <f wsprintf> function. * * @parm LPSTR | pargs | Points to an array of words, each of which * specifies an argument for the format string <p lspzFormat>. The * number, type, and interpretation of the arguments depend on the * corresponding format control sequences in <p lpszFormat>. * * @rdesc Returns the number of characters output. If output to the * WPF window is disabled, zero is returned. The returned count of * characters output does not include the translation of newline * characters into carriage return newline sequences. * * @xref wpfPrintf * */ //int FAR cdecl wpfVprintf(HWND hwnd, LPSTR lpszFormat, LPSTR pargs)
//{
// int i;
//
//
// i = wvsprintf(bufTmp, lpszFormat, pargs);
// wpfOut(hwnd, bufTmp);
//
// return i;
//}
/*
* @doc WINCOM EXTERNAL WPFWINDOW * * @api void | wpfOut | This function prints a string to a WPF window * or redirected output device. No formatting is carried out upon the * string, it is printed verbatim. * * @parm HWND | hwnd | Specifies the WPF window. Output to the window * may be redirected to a file or COM1 by sending a WPF_SETOUTPUT window * message to <p hwnd>. If output has been redirected, this parameter * is still required as the current output location is stored in the WPF * window instance data. * * @parm LPSTR | lpsz | Points to the string to be output. * * @rdesc None. * * @xref wpfPrintf * */ void FAR PASCAL wpfOut(HWND hwnd, LPSTR lpsz) { PTXT pTxt; HTXT hTxt;
if (!IsWindow(hwnd)) return;
hTxt = (HTXT) GetWindowLong(hwnd, 0); pTxt = (PTXT) LocalLock((HANDLE) hTxt);
if (pTxt->wOutputLocation != WPFOUT_DISABLED) { if (pTxt->wOutputLocation == WPFOUT_WINDOW) { wpfWrtTTY(hwnd, lpsz); } else { wpfWrtFile(pTxt->iFile, lpsz); } }
LocalUnlock((HANDLE) hTxt); }
void wpfWrtFile(int fh, LPSTR sz) { LPSTR p, q; char save;
if (fh == -1) return;
/* output to <fh>, but must convert \n's to \n\r's;
* code below is designed to minimize calls to write() */ for (p = q = sz; *p != 0; p++) { /* e.g. bufTmp="hello\nabc", q->'h', p->'\n' */ if (*p == '\n') { /* hack: temporarily replace next char by \r */ /* won't work if string is READ-ONLY!!! */ save = *++p; /* remember it */ p[0] = '\n'; /* replace by \r */ p[-1]= '\r'; /* replace by \r */ _lwrite(fh, q, p - q + 1); q = p; /* for next write() */ *p-- = save; /* un-hack */ *p = '\n'; } } if (p > q) /* any part of <bufTmp> left to write */ _lwrite(fh, q, p - q);
//
// flush the file, by closing a copy of the file
//
FlushFileBuffers(fh); }
|