Source code of Windows XP (NT5)
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.

1631 lines
44 KiB

  1. /*
  2. * WPF.C
  3. *
  4. * WPF line output/input windows. Taken from the wpf.dll library,
  5. * originally written by ToddLa.
  6. *
  7. * History:
  8. * 10/02/86 Todd Laney Created
  9. * 04/14/87 toddla Added new function CreateDebugWin
  10. * 07/08/87 brianc added iMaxLines parm to CreateDebugWin[dow]
  11. * 2/90 russellw moved into Wincom and cleaned up.
  12. * 10/1/92 robinsp moved to NT
  13. *
  14. * NT conversion
  15. * remove the tricks on dereferencing and passing a pointer to
  16. * the stack in wvsprintf. This means we can't do the printf
  17. * thing so have to use a macro, sprintf etc which means wpfprintf
  18. * must be coded :
  19. * wpfprintf(hwnd, lpszFormat, (args))
  20. *
  21. */
  22. #include <windows.h>
  23. #include <mmsystem.h>
  24. #include "wincom.h"
  25. #include "sbtest.h"
  26. #include <stdarg.h>
  27. /*
  28. * This code appears to make use of the fact that a local handle can be
  29. * double de-referenced to get the actual pointer that the local handle
  30. * refers to. This is a somewhat shady practice.. maybe eliminate it?
  31. *
  32. */
  33. /*--------------------------------------------------------------------------*\
  34. | |
  35. | g e n e r a l c o n s t a n t s |
  36. | |
  37. \*--------------------------------------------------------------------------*/
  38. #define MAXBUFLEN 200 /* Maximum string length for wprintf */
  39. /* Macros to manipulate the printf window array of lines. This array
  40. * wraps around, thus the need for the modulo arithmetic
  41. */
  42. #define FIRST(pTxt) ((pTxt)->iFirst)
  43. #define TOP(pTxt) (((pTxt)->iFirst + (pTxt)->iTop) % (pTxt)->iMaxLines)
  44. #define LAST(pTxt) (((pTxt)->iFirst + (pTxt)->iCount-1) % (pTxt)->iMaxLines)
  45. #define INC(pTxt,x) ((x) = ++(x) % (pTxt)->iMaxLines)
  46. #define DEC(pTxt,x) ((x) = --(x) % (pTxt)->iMaxLines)
  47. #define HWinInfo(hwnd) ((HTXT)GetWindowLong((hwnd),0))
  48. #define LockWinInfo(hwnd) ((PTXT)LocalLock((HANDLE)HWinInfo(hwnd)))
  49. #define UnlockWinInfo(hwnd) ((PTXT)LocalUnlock((HANDLE)HWinInfo(hwnd)))
  50. #define VK(vk) ((vk) | 0x0100)
  51. /* The pad values used between the edge of the window and the text.
  52. * x = 1/2 ave char width, y = 1 pixel
  53. */
  54. #define OFFSETX (pTxt->Tdx/2)
  55. #define OFFSETY 1
  56. #define VARSIZE 1
  57. #define BOUND(x,min,max) ((x) < (min) ? (min) : ((x) > (max) ? (max) : (x)))
  58. #define SEEK_CUR 1
  59. #define SEEK_END 2
  60. #define SEEK_SET 0
  61. /*--------------------------------------------------------------------------*\
  62. | |
  63. | g l o b a l v a r i a b l e s |
  64. | |
  65. \*--------------------------------------------------------------------------*/
  66. #define QUESIZE 128
  67. /*
  68. * QUEUE STRUCTURE: Support queuing of input characters.
  69. *
  70. */
  71. typedef struct {
  72. int iLen;
  73. char ach[QUESIZE];
  74. } QUE;
  75. typedef QUE *PQUE; /* pointer to a char que */
  76. typedef PQUE *HQUE; /* handle (**) to a char que */
  77. /*
  78. * WPF WINDOW INSTANCE DATA STRUCTURE
  79. *
  80. */
  81. typedef struct {
  82. int iLen;
  83. char **hText;
  84. } LINE;
  85. struct TEXT_STRUCT {
  86. HWND hwnd; // Window displaying the text
  87. WORD wID; // window ID code, for WM_COMMAND messages
  88. BOOL fScrollSemaphore;
  89. WORD wOutputLocation;
  90. int iFile;
  91. int iFirst; // First line in que
  92. int iCount; // Number of lines in que
  93. int iTop; // Line at top of window
  94. int iLeft; // X offset of the window
  95. int MaxLen; // length of longest string currently stored.
  96. int iMaxLines; // max number of LINEs
  97. int iRangeH;
  98. int iRangeV;
  99. HFONT hFont; // Font to draw with
  100. int Tdx,Tdy; // Font Size
  101. HQUE hQue;
  102. int nTabs;
  103. PINT pTabs;
  104. LINE arLines[VARSIZE]; // array of iMaxLines LINEs
  105. };
  106. typedef struct TEXT_STRUCT *PTXT; /* pointer to a text struct */
  107. typedef PTXT *HTXT; /* Handle (**) to a text struct */
  108. static int iSem=0;
  109. static BOOL gbRedraw=TRUE;
  110. static HWND hwndLast = NULL;
  111. /* External buffer for scratch space */
  112. char bufTmp[MAXBUFLEN]; /* intermediate buffer */
  113. static char szClass[] = "WPFWIN";
  114. static BOOL fInit = FALSE;
  115. /*--------------------------------------------------------------------------*\
  116. | |
  117. | f u n c t i o n d e f i n i t i o n s |
  118. | |
  119. \*--------------------------------------------------------------------------*/
  120. LONG FAR PASCAL PrintfWndProc(HWND, unsigned, UINT, LONG);
  121. void NEAR PASCAL WpfSetFont(HWND hWnd, HFONT hFont);
  122. void NEAR PASCAL WpfClear(HWND hWnd);
  123. void NEAR PASCAL WpfSetTabs(HWND hwnd, int nTabs, LPINT pTabs);
  124. BOOL NEAR PASCAL WpfGetTabs(HWND hwnd, LPINT pTabs);
  125. void NEAR PASCAL WpfPaint(HWND hwnd, HDC hdc);
  126. void NEAR PASCAL WpfVScroll(HWND hWnd, PTXT pTxt, int n);
  127. void NEAR PASCAL WpfHScroll(HWND hWnd, PTXT pTxt, int n);
  128. int NEAR PASCAL LinesInWpfWindow(HWND hWnd);
  129. int NEAR PASCAL CharsInWpfWindow(HWND hWnd);
  130. void NEAR PASCAL WpfMaxLen(PTXT pTxt);
  131. void NEAR PASCAL WpfSetScrollRange(HWND hWnd, BOOL bRedraw);
  132. void NEAR PASCAL NewLine(PTXT pTxt);
  133. int NEAR PASCAL ChangeLine(PTXT pTxt, int iLine, LPSTR lpch);
  134. int NEAR PASCAL InsertString(PTXT pTxt, LPSTR lpstr);
  135. BOOL NEAR PASCAL EnQueChar(HTXT hTxt, WORD vk);
  136. void NEAR PASCAL UpdateCursorPos(PTXT pTxt);
  137. WORD NEAR PASCAL SetOutput(HWND hwnd, UINT wParam, LONG lParam);
  138. WORD NEAR PASCAL GetOutput(HWND hwnd);
  139. BOOL NEAR PASCAL wpfWrtTTY(HWND hWnd, LPSTR sz);
  140. // BOOL FAR PASCAL DbgDestroy(HWND hwnd);
  141. void wpfWrtFile(int fh, LPSTR sz);
  142. /*
  143. * fSuccess = WpfInit(hInst)
  144. *
  145. * Register the WinPrintf window class.
  146. *
  147. */
  148. BOOL FAR PASCAL WpfInit(HANDLE hInstance);
  149. #pragma alloc_text(init, WpfInit)
  150. BOOL FAR PASCAL WpfInit(HANDLE hInstance)
  151. {
  152. WNDCLASS rClass;
  153. if (!fInit) {
  154. rClass.hCursor = LoadCursor(NULL,IDC_ARROW);
  155. rClass.hIcon = (HICON)NULL;
  156. rClass.lpszMenuName = (LPSTR)NULL;
  157. rClass.lpszClassName = szClass;
  158. rClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  159. rClass.hInstance = hInstance;
  160. rClass.style = CS_GLOBALCLASS;
  161. rClass.lpfnWndProc = PrintfWndProc;
  162. rClass.cbWndExtra = sizeof (HTXT);
  163. rClass.cbClsExtra = 0;
  164. if (!RegisterClass(&rClass))
  165. return FALSE;
  166. fInit++;
  167. }
  168. return TRUE;
  169. }
  170. /*
  171. * @doc EXTERNAL WINCOM WPFWINDOW
  172. *
  173. * @api HWND | wpfCreateWindow | This function creates a
  174. * text output window. WPF windows allow <f printf> style output
  175. * and line oriented input. WPF windows also remember a fixed number of
  176. * lines of previous output for scrolling back.
  177. *
  178. * @parm HWND | hwndParent | Specifies the parent window.
  179. *
  180. * @parm HANDLE | hInst | Specifies the module instance handle of the
  181. * DLL owner. If the parameter is NULL, the module instance handle of
  182. * the WINCOM DLL is used.
  183. *
  184. * @parm LPSTR | lpszTitle | Points to the window title. This
  185. * information is ignored when the style specified by <p dwStyle> does
  186. * not create a title bar for the window.
  187. *
  188. * @parm DWORD | dwStyle | Specifies the window style flags. All
  189. * standard window style flags are valid. The WPF window class also defines
  190. * the following additional flags:
  191. *
  192. * @flag WPF_CHARINPUT | The WPF window allows the user to input
  193. * characters and sends its parent <m WPF_NCHAR> and <m WPF_NTEXT> messages.
  194. *
  195. * @parm WORD | x | Specifies the x position of the window.
  196. * @parm WORD | y | Specifies the y position of the window.
  197. * @parm WORD | dx | Specifies the width of the window.
  198. * @parm WORD | dy | Specifies the height of the window.
  199. *
  200. * @parm int | iMaxLines | Specifies the maximum number of lines that
  201. * the WPF window remembers for scrolling purposes. If this
  202. * parameter is zero, a default value of 100 is supplied.
  203. *
  204. * @parm WORD | wID | Specifies the window ID of the WPF window. This
  205. * code is used in WM_COMMAND message to notify the owner of the WPF
  206. * window when key events have occurred.
  207. *
  208. * @rdesc Returns the window handle of the new WPF window, or NULL if
  209. * an error occurs. The returned window handle may be used with the
  210. * normal Windows window-management APIs.
  211. *
  212. * @comm A WPF window behaves like a partial Windows control. The
  213. * owner may change the parameters of a WPF window by sending control
  214. * messages (including WM_SETFONT, WM_GETFONT, and the WPF messages
  215. * documented with the WINCOM DLL). The WPF window notifies its owner
  216. * of state changes by sending the owner WM_COMMAND messages with a
  217. * control ID of <p wID>. WPF windows are not full controls, however,
  218. * as they cannot be used in dialog boxes. WPF windows also do not
  219. * respond to WM_GETTEXT and WM_SETTEXT messages.
  220. *
  221. */
  222. HWND FAR PASCAL wpfCreateWindow(HWND hwndParent, HANDLE hInst,LPSTR lpszTitle,
  223. DWORD dwStyle, WORD x, WORD y,
  224. WORD dx, WORD dy, int iMaxLines, WORD wID)
  225. {
  226. HWND hWnd;
  227. if (!fInit)
  228. if (!WpfInit(ghInst))
  229. /* Return NULL if the class could not be registered */
  230. return NULL;
  231. if (iMaxLines == 0)
  232. iMaxLines = 100;
  233. if (hInst == NULL)
  234. hInst = ghInst;
  235. hWnd = CreateWindow((LPSTR)szClass,
  236. (LPSTR)lpszTitle,
  237. dwStyle,
  238. x,y,
  239. dx,dy,
  240. (HWND) hwndParent,
  241. (HMENU) NULL,
  242. (HANDLE) hInst,
  243. (LPSTR) MAKELONG(iMaxLines, wID)
  244. );
  245. return hWnd;
  246. }
  247. /*****************************************************
  248. *
  249. * UTILITY PROCEDURES
  250. *
  251. *****************************************************/
  252. /*
  253. * WpfSetFont(hwnd, hfont)
  254. *
  255. * Changes the font of a winprintf window to be the specified handle.
  256. * Rebuilds the internal character size measurements, and causes the
  257. * window to repaint.
  258. *
  259. * Is there a problem with scroll ranges changing here?
  260. *
  261. */
  262. void NEAR PASCAL WpfSetFont(HWND hWnd, HFONT hFont)
  263. {
  264. PTXT pTxt;
  265. HDC hDC;
  266. TEXTMETRIC tm;
  267. pTxt = LockWinInfo(hWnd);
  268. pTxt->hFont = hFont;
  269. /* Find out the size of a Char in the font */
  270. hDC = GetDC(hWnd);
  271. SelectObject(hDC, hFont);
  272. GetTextMetrics(hDC, (LPTEXTMETRIC) &tm);
  273. pTxt->Tdy = tm.tmHeight;
  274. pTxt->Tdx = tm.tmAveCharWidth;
  275. ReleaseDC (hWnd, hDC);
  276. InvalidateRect(hWnd, NULL, TRUE);
  277. UnlockWinInfo(hWnd);
  278. }
  279. /*
  280. * WpfClear(hwnd)
  281. *
  282. * Clears all text from the window. Frees all allocated memory. The
  283. * current queue is not modified?
  284. *
  285. */
  286. void NEAR PASCAL WpfClear(HWND hWnd)
  287. {
  288. int i,iQue;
  289. PTXT pTxt;
  290. pTxt = LockWinInfo(hWnd);
  291. iQue = FIRST(pTxt);
  292. for (i=0; i < pTxt->iCount; i++, INC(pTxt,iQue))
  293. if (pTxt->arLines[iQue].hText != NULL)
  294. LocalFree((HANDLE) pTxt->arLines[iQue].hText);
  295. pTxt->iFirst = 0; /* Set the que up to have 1 NULL line */
  296. pTxt->iCount = 1;
  297. pTxt->iTop = 0;
  298. pTxt->iLeft = 0;
  299. pTxt->MaxLen = 0;
  300. pTxt->arLines[0].hText = NULL;
  301. pTxt->arLines[0].iLen = 0;
  302. UnlockWinInfo(hWnd);
  303. InvalidateRect(hWnd,NULL,TRUE);
  304. WpfSetScrollRange(hWnd,TRUE);
  305. UpdateWindow(hWnd);
  306. }
  307. /*
  308. * WpfSetTabs(hwnd, nTabs, pTabs)
  309. *
  310. * Sets up hwnd to use the tabs stops specified by pTabs. Copies these
  311. * tabs into a local-alloc'ed buffer. Any pre-existing tab stops are
  312. * deallocated.
  313. *
  314. */
  315. void NEAR PASCAL WpfSetTabs(HWND hwnd, int nTabs, LPINT pTabs)
  316. {
  317. PTXT pTxt;
  318. int i;
  319. pTxt = LockWinInfo(hwnd);
  320. /* Discard old tabs, allocate space for new tab settings */
  321. if (pTxt->pTabs)
  322. LocalFree((HANDLE)pTxt->pTabs);
  323. if (pTabs == NULL || nTabs == 0) {
  324. pTxt->pTabs = NULL;
  325. pTxt->nTabs = 0;
  326. }
  327. else {
  328. pTxt->pTabs = (PINT)LocalAlloc(LPTR, nTabs * sizeof(int));
  329. pTxt->nTabs = nTabs;
  330. /* Copy caller's tab settings into the current tab table */
  331. if (pTxt->pTabs) {
  332. for (i=0; i < nTabs; i++)
  333. pTxt->pTabs[i] = *pTabs++;
  334. }
  335. }
  336. InvalidateRect(hwnd,NULL,TRUE);
  337. UnlockWinInfo(hwnd);
  338. }
  339. /*
  340. * fIsTabs = WpfGetTabs(hwnd, pTabs)
  341. *
  342. * Responds to a WPF_GETTABSTOPS message by filling in the supplied
  343. * buffer with the current tab settings. Returns TRUE if there are tabs
  344. * stops, or FALSE if there aren't any tab stops in use.
  345. *
  346. */
  347. BOOL NEAR PASCAL WpfGetTabs(HWND hwnd, LPINT pTabs)
  348. {
  349. PTXT pTxt;
  350. int i;
  351. pTxt = LockWinInfo(hwnd);
  352. /* If there are no current tabs, return FALSE */
  353. if (pTxt->nTabs == 0 || pTxt->pTabs == NULL) {
  354. UnlockWinInfo(hwnd);
  355. return FALSE;
  356. }
  357. /* Otherwise, copy my tabs into the caller's buffer. Assume
  358. * that the caller's buffer is large enough.
  359. */
  360. for (i=0; i < pTxt->nTabs; i++) {
  361. *pTabs++ = pTxt->pTabs[i];
  362. }
  363. UnlockWinInfo(hwnd);
  364. return TRUE;
  365. }
  366. /***********************************
  367. *
  368. * WINDOW PROCEDURE
  369. *
  370. ***********************************/
  371. /*--------------------------------------------------------------------------*\
  372. | WpfPaint(hWnd, hDC ) |
  373. | |
  374. | Description: |
  375. | The paint function. |
  376. | |
  377. | Arguments: |
  378. | hWnd Window to paint to. |
  379. | hDC handle to update region's display context |
  380. | |
  381. | Returns: |
  382. | nothing |
  383. | |
  384. \*--------------------------------------------------------------------------*/
  385. void NEAR PASCAL WpfPaint(HWND hwnd, HDC hdc)
  386. {
  387. PTXT pTxt;
  388. int i;
  389. int iQue;
  390. int xco;
  391. int yco;
  392. int iLast;
  393. RECT rc;
  394. RECT rcClip;
  395. HFONT hfontOld;
  396. //LockData(0); /* need from spy DS not locked! */
  397. pTxt = LockWinInfo(hwnd);
  398. GetClientRect(hwnd, &rc);
  399. rc.left += OFFSETX;
  400. rc.top += OFFSETY;
  401. IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom);
  402. SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
  403. SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
  404. /* If a font (other than the system font) has been specified, use it */
  405. if (pTxt->hFont)
  406. hfontOld = SelectObject(hdc, pTxt->hFont);
  407. /* Setup counters as appropriate. Get indexes of first and last
  408. * lines visible within the window.
  409. */
  410. iLast = LAST(pTxt);
  411. iQue = TOP(pTxt);
  412. /* The x and y initial points for the text line.
  413. * xco is shifted left to account for any horizonal scrolling
  414. * that may be going on
  415. */
  416. xco = OFFSETX - pTxt->iLeft * pTxt->Tdx; // shifted for h-scrolling
  417. yco = OFFSETY; // starting y pix value
  418. /* RC is the bounding rect for the current line.
  419. *
  420. * Calc initial line bounding rect.. top = top of window (padded),
  421. * bottom = top + height of one line.
  422. */
  423. rc.left = xco;
  424. rc.top = yco;
  425. rc.bottom = yco + pTxt->Tdy;
  426. /* Get the clipping rectangle */
  427. GetClipBox(hdc, &rcClip);
  428. /* Iter over all lines that are visible - if the bounding rect
  429. * for the current line intersects the clip rect, draw the line.
  430. */
  431. for (;;) {
  432. if (rc.bottom >= rcClip.top) {
  433. /* If we're using tabs, then tab out the text.
  434. */
  435. char *pStr;
  436. pStr = LocalLock(pTxt->arLines[iQue].hText);
  437. if (pTxt->nTabs > 0) {
  438. /* Erase the background */
  439. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  440. /* Using *pTxt->arLines[iQue].hText returns the local
  441. * string that is refered to by local handle hText.
  442. */
  443. TabbedTextOut(hdc, xco, yco,
  444. (LPSTR)pStr,
  445. pTxt->arLines[iQue].iLen,
  446. pTxt->nTabs, pTxt->pTabs, xco);
  447. }
  448. else {
  449. /* Otherwise, blow it out using ExtTextOut */
  450. ExtTextOut(hdc, xco, yco, ETO_OPAQUE, &rc,
  451. (LPSTR)pStr,
  452. pTxt->arLines[iQue].iLen, NULL);
  453. }
  454. LocalUnlock(pTxt->arLines[iQue].hText);
  455. }
  456. /* Bail out when finished printing window contents */
  457. if (iQue == iLast)
  458. break;
  459. INC(pTxt, iQue);
  460. /* Advance the boundry rect & char positions down one line */
  461. yco = rc.top = rc.bottom;
  462. rc.bottom += pTxt->Tdy;
  463. if (yco > rcClip.bottom)
  464. break;
  465. }
  466. /* Restore the old font */
  467. if (hfontOld)
  468. SelectObject(hdc, hfontOld);
  469. // UnlockData(0);
  470. }
  471. LONG FAR PASCAL PrintfWndProc(HWND hWnd, unsigned uiMessage,
  472. UINT wParam, LONG lParam)
  473. {
  474. PAINTSTRUCT rPS;
  475. PTXT pTxt;
  476. HTXT hTxt;
  477. int i;
  478. int iQue;
  479. DWORD rc = 0L;
  480. hTxt = (HTXT)GetWindowLong(hWnd,0);
  481. if (hTxt) pTxt = LocalLock(hTxt);
  482. #define lpCreate ((LPCREATESTRUCT)lParam)
  483. switch (uiMessage) {
  484. case WM_CREATE:
  485. i = LOWORD((DWORD)lpCreate->lpCreateParams);
  486. /* Allocate and initialize the window instance structure
  487. * The storage for the current lines is placed at the end
  488. * end of the instance data structure. allocate room for it.
  489. */
  490. hTxt = (HTXT) LocalAlloc(LHND, sizeof(struct TEXT_STRUCT) +
  491. (i - VARSIZE) * sizeof(LINE));
  492. if (!hTxt)
  493. return -1L;
  494. pTxt = (PTXT)LocalLock((HANDLE)hTxt);
  495. pTxt->hwnd = hWnd;
  496. pTxt->wID = HIWORD(lpCreate->lpCreateParams);
  497. pTxt->iFile = -1;
  498. pTxt->wOutputLocation = WPFOUT_WINDOW;
  499. pTxt->iFirst = 0; // initially 1 null line
  500. pTxt->iCount = 1;
  501. pTxt->iTop = 0;
  502. pTxt->iLeft = 0; // no initial hscroll offset
  503. pTxt->MaxLen = 0;
  504. pTxt->iMaxLines = i;
  505. pTxt->nTabs = 0;
  506. /* If user specified character input, allocate a buffer */
  507. if (lpCreate->style & WPF_CHARINPUT)
  508. pTxt->hQue = (HQUE) LocalAlloc(LHND | LMEM_ZEROINIT,
  509. sizeof(QUE));
  510. else
  511. pTxt->hQue = NULL;
  512. /* Null initial first line */
  513. pTxt->arLines[0].hText = NULL;
  514. pTxt->arLines[0].iLen = 0;
  515. /* Store the structure pointer onto the window */
  516. SetWindowLong(hWnd, 0, (LONG) hTxt);
  517. /* Setup to use the system font by default */
  518. WpfSetFont(hWnd, GetStockObject(SYSTEM_FONT));
  519. LocalUnlock((HANDLE) hTxt);
  520. return 0L;
  521. case WM_DESTROY:
  522. // DbgDestroy(hWnd);
  523. /* Flush any files in use by the window */
  524. SetOutput(hWnd, WPFOUT_DISABLED, 0L);
  525. /* Blow away all lines held by the window */
  526. iQue = FIRST(pTxt);
  527. for (i=0; i < pTxt->iCount; i++, INC(pTxt,iQue))
  528. if (pTxt->arLines[iQue].hText != NULL)
  529. LocalFree((HANDLE) pTxt->arLines[iQue].hText);
  530. /* And kill char input and tab stop storage */
  531. if (pTxt->hQue)
  532. LocalFree ((HANDLE) pTxt->hQue);
  533. if (pTxt->pTabs)
  534. LocalFree ((HANDLE) pTxt->pTabs);
  535. LocalUnlock(hTxt);
  536. LocalFree((HANDLE)hTxt);
  537. hTxt = NULL;
  538. break;
  539. // case WPF_SETNLINES:
  540. // return 0L;
  541. case WPF_GETNLINES:
  542. rc = pTxt->iMaxLines;
  543. break;
  544. case WM_GETFONT:
  545. rc = pTxt->hFont;
  546. break;
  547. case WM_SETFONT:
  548. WpfSetFont(hWnd, wParam);
  549. break;
  550. /* Tab stop stuff */
  551. case WPF_SETTABSTOPS:
  552. WpfSetTabs(hWnd, wParam, (LPINT) lParam);
  553. break;
  554. case WPF_GETNUMTABS:
  555. rc = pTxt->pTabs ? pTxt->nTabs : 0;
  556. break;
  557. case WPF_GETTABSTOPS:
  558. rc = (LONG) WpfGetTabs(hWnd, (LPINT) lParam);
  559. break;
  560. case WPF_SETOUTPUT:
  561. rc = (LONG) SetOutput(hWnd, wParam, lParam);
  562. break;
  563. case WPF_GETOUTPUT:
  564. rc = (LONG) GetOutput(hWnd);
  565. break;
  566. case WPF_CLEARWINDOW:
  567. WpfClear(hWnd);
  568. break;
  569. case WM_SIZE:
  570. /* It is possible to get WM_SIZEs as a result of
  571. * dicking with scrollbars.. Avoid race conditions
  572. */
  573. if (!pTxt->fScrollSemaphore) {
  574. pTxt->fScrollSemaphore++;
  575. WpfSetScrollRange(hWnd, TRUE);
  576. UpdateCursorPos(pTxt);
  577. pTxt->fScrollSemaphore--;
  578. }
  579. break;
  580. case WM_VSCROLL:
  581. switch (wParam) {
  582. case SB_LINEDOWN:
  583. WpfVScroll (hWnd,pTxt,1);
  584. break;
  585. case SB_LINEUP:
  586. WpfVScroll (hWnd,pTxt,-1);
  587. break;
  588. case SB_PAGEUP:
  589. WpfVScroll (hWnd,pTxt,-LinesInWpfWindow(hWnd));
  590. break;
  591. case SB_PAGEDOWN:
  592. WpfVScroll (hWnd,pTxt,LinesInWpfWindow(hWnd));
  593. break;
  594. case SB_THUMBTRACK:
  595. WpfVScroll (hWnd,pTxt,LOWORD(lParam)-pTxt->iTop);
  596. break;
  597. case SB_THUMBPOSITION:
  598. WpfVScroll (hWnd,pTxt,LOWORD(lParam)-pTxt->iTop);
  599. /* Fall through */
  600. case SB_ENDSCROLL:
  601. WpfSetScrollRange(hWnd,TRUE);
  602. UpdateCursorPos(pTxt);
  603. break;
  604. }
  605. break;
  606. case WM_HSCROLL:
  607. switch (wParam) {
  608. case SB_LINEDOWN:
  609. WpfHScroll (hWnd, pTxt, 1);
  610. break;
  611. case SB_LINEUP:
  612. WpfHScroll (hWnd, pTxt, -1);
  613. break;
  614. case SB_PAGEUP:
  615. WpfHScroll (hWnd, pTxt, -CharsInWpfWindow(hWnd));
  616. break;
  617. case SB_PAGEDOWN:
  618. WpfHScroll (hWnd, pTxt, CharsInWpfWindow(hWnd));
  619. break;
  620. case SB_THUMBTRACK:
  621. WpfHScroll (hWnd, pTxt, LOWORD(lParam) - pTxt->iLeft);
  622. break;
  623. case SB_THUMBPOSITION:
  624. WpfHScroll (hWnd, pTxt, LOWORD(lParam) - pTxt->iLeft);
  625. /* Fall through */
  626. case SB_ENDSCROLL:
  627. WpfSetScrollRange(hWnd,TRUE);
  628. UpdateCursorPos(pTxt);
  629. break;
  630. }
  631. break;
  632. case WM_PAINT:
  633. BeginPaint(hWnd,&rPS);
  634. WpfPaint (hWnd,rPS.hdc);
  635. EndPaint(hWnd,&rPS);
  636. break;
  637. /* Allow keyboard scrolling */
  638. case WM_KEYDOWN:
  639. switch (wParam) {
  640. case VK_UP:
  641. PostMessage (hWnd,WM_VSCROLL,SB_LINEUP,0L); break;
  642. case VK_DOWN:
  643. PostMessage (hWnd,WM_VSCROLL,SB_LINEDOWN,0L); break;
  644. case VK_PRIOR:
  645. PostMessage (hWnd,WM_VSCROLL,SB_PAGEUP,0L); break;
  646. case VK_NEXT:
  647. PostMessage (hWnd,WM_VSCROLL,SB_PAGEDOWN,0L); break;
  648. case VK_HOME:
  649. PostMessage (hWnd,WM_HSCROLL,SB_PAGEUP,0L); break;
  650. case VK_END:
  651. PostMessage (hWnd,WM_HSCROLL,SB_PAGEDOWN,0L); break;
  652. case VK_LEFT:
  653. PostMessage (hWnd,WM_HSCROLL,SB_LINEUP,0L); break;
  654. case VK_RIGHT:
  655. PostMessage (hWnd,WM_HSCROLL,SB_LINEDOWN,0L); break;
  656. }
  657. break;
  658. /* Handle focus messages to hide and show the caret
  659. * if the WPF window allows for character input.
  660. */
  661. case WM_SETFOCUS:
  662. if (pTxt->hQue) {
  663. CreateCaret(hWnd,0,1,pTxt->Tdy);
  664. UpdateCursorPos(pTxt);
  665. ShowCaret(hWnd);
  666. }
  667. break;
  668. case WM_KILLFOCUS:
  669. if (pTxt->hQue)
  670. DestroyCaret();
  671. break;
  672. case WM_CHAR:
  673. EnQueChar(hTxt,wParam);
  674. break;
  675. case WM_KEYUP:
  676. switch (wParam) {
  677. case VK_F3:
  678. EnQueChar(hTxt,VK(wParam));
  679. break;
  680. /* Send endscroll when the key goes up - allows for
  681. * type-a-matic action.
  682. */
  683. case VK_UP:
  684. case VK_DOWN:
  685. case VK_PRIOR:
  686. case VK_NEXT:
  687. PostMessage (hWnd,WM_VSCROLL,SB_ENDSCROLL,0L);
  688. break;
  689. case VK_HOME:
  690. case VK_END:
  691. case VK_LEFT:
  692. case VK_RIGHT:
  693. PostMessage (hWnd,WM_HSCROLL,SB_ENDSCROLL,0L);
  694. break;
  695. }
  696. break;
  697. default:
  698. return DefWindowProc(hWnd,uiMessage,wParam,lParam);
  699. }
  700. if (hTxt) LocalUnlock(hTxt);
  701. return rc;
  702. }
  703. /***********************************************
  704. *
  705. * SCROLLING STUFF
  706. *
  707. ***********************************************/
  708. /*
  709. * WpfVScroll(hwnd, pTxt, n)
  710. *
  711. * Vertical scroll the window by n number of lines.
  712. *
  713. */
  714. void NEAR PASCAL WpfVScroll(HWND hWnd, PTXT pTxt, int n)
  715. {
  716. RECT rect;
  717. int iRange;
  718. /* GetScrollRange (hWnd,SB_VERT,&iMinPos,&iMaxPos); */
  719. iRange = pTxt->iRangeV; // where did this come from?
  720. GetClientRect(hWnd, &rect);
  721. rect.left += OFFSETX; // adjust for pad boundry
  722. rect.top += OFFSETY;
  723. n = BOUND(pTxt->iTop + n, 0, iRange) - pTxt->iTop;
  724. pTxt->iTop += n;
  725. ScrollWindow(hWnd, 0, -n * pTxt->Tdy, &rect, &rect);
  726. SetScrollPos(hWnd, SB_VERT, pTxt->iTop, gbRedraw);
  727. UpdateWindow(hWnd);
  728. }
  729. /*
  730. * WpfHScroll(hwnd, ptxt, n)
  731. *
  732. * Horizontally scrolls the window by n number of character widths.
  733. *
  734. */
  735. void NEAR PASCAL WpfHScroll(HWND hWnd, PTXT pTxt, int n)
  736. {
  737. RECT rect;
  738. int iRange;
  739. /* GetScrollRange (hWnd,SB_HORZ,&iMinPos,&iMaxPos); */
  740. iRange = pTxt->iRangeH;
  741. GetClientRect (hWnd,&rect);
  742. rect.left += OFFSETX;
  743. rect.top += OFFSETY;
  744. n = BOUND(pTxt->iLeft + n, 0, iRange) - pTxt->iLeft;
  745. pTxt->iLeft += n;
  746. ScrollWindow(hWnd, -n * pTxt->Tdx, 0, &rect, &rect);
  747. SetScrollPos(hWnd, SB_HORZ, pTxt->iLeft, gbRedraw);
  748. UpdateWindow(hWnd);
  749. }
  750. /*
  751. * nLines = LinesInWpfWindow(hwnd)
  752. *
  753. * Returns the height in lines of the window.
  754. *
  755. */
  756. int NEAR PASCAL LinesInWpfWindow(HWND hWnd)
  757. {
  758. RECT rRect;
  759. PTXT pTxt;
  760. int iLines;
  761. pTxt = *(HTXT) GetWindowLong(hWnd, 0);
  762. GetClientRect(hWnd, &rRect);
  763. iLines = 0;
  764. if (pTxt) {
  765. iLines = (rRect.bottom - rRect.top - OFFSETY) / pTxt->Tdy;
  766. iLines = min(iLines, pTxt->iMaxLines);
  767. }
  768. return iLines;
  769. }
  770. /*
  771. * nChars = CharsInWpfWindow(hwnd)
  772. *
  773. * Returns the width in characters of the window.
  774. *
  775. */
  776. int NEAR PASCAL CharsInWpfWindow(HWND hWnd)
  777. {
  778. RECT rRect;
  779. PTXT pTxt;
  780. pTxt = *(HTXT)GetWindowLong (hWnd,0);
  781. GetClientRect(hWnd,&rRect);
  782. return pTxt ? (rRect.right - rRect.left - OFFSETX) / pTxt->Tdx : 0;
  783. }
  784. /*
  785. * WpfMaxLen(pTxt)
  786. *
  787. * This function sets the pTxt->MaxLen field to be the length in
  788. * characters of the longest string currently being stored by the WPF
  789. * window.
  790. *
  791. */
  792. void NEAR PASCAL WpfMaxLen(PTXT pTxt)
  793. {
  794. int iQue;
  795. int iLast;
  796. int iLen;
  797. SIZE size;
  798. // DWORD dwLen;
  799. // HDC hdc;
  800. #if 0
  801. hdc = GetDC(NULL);
  802. if (pTxt->hFont)
  803. SelectObject(hdc, pTxt->hFont);
  804. #endif
  805. iLast = LAST(pTxt);
  806. iQue = TOP(pTxt);
  807. pTxt->MaxLen = 0;
  808. for (;;) {
  809. iLen = pTxt->arLines[iQue].iLen;
  810. #if 0
  811. if (pTxt->nTabs)
  812. dwLen = GetTabbedTextExtent(hdc, (LPSTR) *pTxt->arLines[iQue].hText,
  813. iLen, pTxt->nTabs, (LPINT)pTxt->pTabs);
  814. else
  815. GetTextExtent(hdc, (LPSTR) *pTxt->arLines[iQue].hText,iLen,&size);
  816. iLen = size.cx // pTxt->Tdx + 1;
  817. #endif
  818. if (iLen > pTxt->MaxLen)
  819. pTxt->MaxLen = iLen;
  820. if (iQue == iLast) break;
  821. INC(pTxt,iQue);
  822. }
  823. // ReleaseDC(NULL,hdc);
  824. }
  825. /*
  826. * WpfSetScrollRange(hwnd, bRedraw)
  827. *
  828. * This function sets the scrollbar ranges according to the current
  829. * character/line contents of the window. Both the horizontal and
  830. * vertical scrollbars are adjusted.
  831. *
  832. * This function then calls WpfVScroll/WpfHScroll to adjust the
  833. * scrollbar position accordingly.
  834. *
  835. */
  836. void NEAR PASCAL WpfSetScrollRange(HWND hWnd, BOOL bRedraw)
  837. {
  838. PTXT pTxt;
  839. int iRange;
  840. if (pTxt = *(HTXT) GetWindowLong(hWnd, 0)) {
  841. gbRedraw = bRedraw;
  842. /* Update the scroll bars */
  843. iRange = pTxt->iCount - LinesInWpfWindow(hWnd) + 1;
  844. /* Adjust for blank last line? */
  845. if (pTxt->arLines[LAST(pTxt)].iLen == 0);
  846. iRange -= 1;
  847. if (iRange < 0) iRange = 0;
  848. /* Set the scrollbar range to that calculated */
  849. pTxt->iRangeV = iRange;
  850. SetScrollRange(hWnd, SB_VERT, 0, iRange, FALSE);
  851. WpfVScroll(hWnd, pTxt, 0);
  852. /* Setup the horizontal scrollbar range */
  853. WpfMaxLen(pTxt);
  854. iRange = pTxt->MaxLen - CharsInWpfWindow(hWnd) + 1;
  855. if (iRange < 0) iRange = 0;
  856. pTxt->iRangeH = iRange;
  857. SetScrollRange(hWnd, SB_HORZ, 0, iRange, FALSE);
  858. WpfHScroll(hWnd, pTxt, 0);
  859. gbRedraw = TRUE;
  860. }
  861. }
  862. /***********************************************************
  863. *
  864. * STUFF TO ADD NEW TEXT LINES
  865. *
  866. ***********************************************************/
  867. /*
  868. * NewLine(pTxt)
  869. *
  870. * Adjusts a WPF window when adding a line to the circular array.
  871. * iCount is the count of valid lines in the array. If we
  872. * haven't yet filled up the array, the count is merely increased.
  873. * Otherwise, if the array is full and we're about to wrap around, fixup
  874. * the wrap-around.
  875. *
  876. */
  877. void NEAR PASCAL NewLine(PTXT pTxt)
  878. {
  879. int iLast = LAST(pTxt);
  880. int iLine,cLine;
  881. RECT rect;
  882. if (pTxt->iCount == pTxt->iMaxLines) {
  883. /* If the array is full, check for wrap-around */
  884. LocalFree ((HANDLE)pTxt->arLines[pTxt->iFirst].hText);
  885. pTxt->arLines[pTxt->iFirst].hText = NULL;
  886. INC(pTxt, pTxt->iFirst);
  887. if (pTxt->iTop > 0)
  888. pTxt->iTop--;
  889. else {
  890. GetClientRect (pTxt->hwnd,&rect);
  891. rect.left += OFFSETX;
  892. rect.top += OFFSETY;
  893. ScrollWindow (pTxt->hwnd, 0, -pTxt->Tdy, &rect, &rect);
  894. }
  895. }
  896. else {
  897. pTxt->iCount++;
  898. }
  899. iLast = LAST(pTxt);
  900. pTxt->arLines[iLast].hText = NULL;
  901. pTxt->arLines[iLast].iLen = 0;
  902. }
  903. /*
  904. * fSuccess = ChangeLine(pTxt, iLine, lpsz)
  905. *
  906. * Changes line number <iLine> to be the string pointed to by lpsz.
  907. * Frees any line currently occupying index <iLine>, and then alloc and
  908. * stores text lpsz.
  909. *
  910. */
  911. int NEAR PASCAL ChangeLine(PTXT pTxt, int iLine, LPSTR lpch)
  912. {
  913. int iLen;
  914. LPSTR pData;
  915. if (pTxt->arLines[iLine].hText != NULL)
  916. LocalFree((HANDLE)pTxt->arLines[iLine].hText);
  917. iLen = lstrlen(lpch);
  918. if ((pTxt->arLines[iLine].hText = (char**)LocalAlloc(LHND,iLen+1))== NULL)
  919. return FALSE;
  920. pTxt->arLines[iLine].iLen = iLen;
  921. pData = LocalLock(pTxt->arLines[iLine].hText);
  922. lstrcpy(pData, lpch);
  923. LocalUnlock(pTxt->arLines[iLine].hText);
  924. return TRUE;
  925. }
  926. /*
  927. */
  928. int NEAR PASCAL InsertString(PTXT pTxt, LPSTR lpstr)
  929. {
  930. int iBuf;
  931. int iLast = LAST(pTxt);
  932. int cLine = 0;
  933. char buf[MAXBUFLEN];
  934. buf[0] = '\0';
  935. /*
  936. * copy the string already there
  937. */
  938. {
  939. PSTR pch;
  940. HANDLE hText;
  941. hText = pTxt->arLines[iLast].hText;
  942. if (hText) {
  943. pch = LocalLock(hText); // (LocalLock eqiv)
  944. iBuf = lstrlen(pch);
  945. lstrcpy(buf, pch); // why?
  946. LocalUnlock(pTxt->arLines[iLast].hText);
  947. } else {
  948. iBuf = 0;
  949. }
  950. }
  951. while (*lpstr != '\0') {
  952. while (*lpstr != '\n' && *lpstr != '\0' && iBuf < MAXBUFLEN-2)
  953. switch (*lpstr) {
  954. case '\b':
  955. /* Backspace, blow away one character */
  956. iBuf--;
  957. lpstr++;
  958. break;
  959. case '\r':
  960. /* Carriage return, go back to beginning of line */
  961. iBuf = 0;
  962. lpstr++;
  963. break;
  964. default:
  965. /* Otherwise, add this char to line */
  966. buf[iBuf++] = *lpstr++;
  967. break;
  968. }
  969. buf[iBuf++] = 0;
  970. /* Presto chango add the line */
  971. ChangeLine(pTxt, iLast, buf); /* buf must be a asciiz string */
  972. if (*lpstr == '\n') { /* Now do the next string after the \n */
  973. lpstr++;
  974. iBuf = 0;
  975. cLine++;
  976. NewLine(pTxt);
  977. INC(pTxt, iLast);
  978. }
  979. }
  980. return cLine; /* the number of new lines added to list */
  981. }
  982. /**********************************************************
  983. *
  984. * CHARACTER INPUT STUFF
  985. *
  986. **********************************************************/
  987. BOOL NEAR PASCAL EnQueChar(HTXT hTxt, WORD vk)
  988. {
  989. PTXT pTxt;
  990. PQUE pQue;
  991. int i;
  992. HWND hwndP;
  993. pTxt = (PTXT)LocalLock((HANDLE)hTxt);
  994. if (!pTxt->hQue)
  995. goto noque;
  996. pQue = (PQUE)LocalLock((HANDLE)pTxt->hQue);
  997. i = pQue->iLen;
  998. switch (vk)
  999. {
  1000. case '\b':
  1001. if (i > 0)
  1002. {
  1003. --i;
  1004. wpfOut(pTxt->hwnd, "\b");
  1005. }
  1006. break;
  1007. case VK(VK_F3):
  1008. wpfOut(pTxt->hwnd, pQue->ach + i);
  1009. i += lstrlen(pQue->ach + i);
  1010. break;
  1011. case '\r':
  1012. case '\n':
  1013. if (GetKeyState(VK_CONTROL) < 0)
  1014. {
  1015. wpfOut(pTxt->hwnd,"\\\n");
  1016. }
  1017. else
  1018. {
  1019. wpfOut(pTxt->hwnd, "\n");
  1020. pQue->ach[i] = '\0';
  1021. if (hwndP = GetParent(pTxt->hwnd))
  1022. SendMessage(hwndP, WPF_NTEXT, pTxt->wID,
  1023. (LONG)(LPSTR)pQue->ach);
  1024. i = 0;
  1025. }
  1026. break;
  1027. default:
  1028. if (i < QUESIZE)
  1029. {
  1030. pQue->ach[i] = (char)vk;
  1031. sprintf(ach, ("%c", vk));
  1032. wpfOut(pTxt->hwnd, ach);
  1033. if (hwndP = GetParent(pTxt->hwnd))
  1034. SendMessage(hwndP, WPF_NCHAR, pTxt->wID, (LONG) vk);
  1035. i++;
  1036. }
  1037. else
  1038. {
  1039. /* Input que is full, beep to notify */
  1040. MessageBeep(0);
  1041. }
  1042. break;
  1043. }
  1044. pQue->iLen = i;
  1045. LocalUnlock((HANDLE)pTxt->hQue);
  1046. noque:
  1047. LocalUnlock((HANDLE)hTxt);
  1048. return TRUE;
  1049. }
  1050. void NEAR PASCAL UpdateCursorPos(PTXT pTxt)
  1051. {
  1052. int iLine;
  1053. int y,x;
  1054. int iLen;
  1055. DWORD dw;
  1056. HDC hdc;
  1057. SIZE size;
  1058. char **h;
  1059. char *ptxt;
  1060. /* If I don't do char input, or don't have the focus, forget it */
  1061. if (!pTxt->hQue || GetFocus() != pTxt->hwnd)
  1062. return;
  1063. hdc = GetDC(NULL);
  1064. SelectObject(hdc, pTxt->hFont);
  1065. iLen = pTxt->arLines[LAST(pTxt)].iLen - pTxt->iLeft;
  1066. h = pTxt->arLines[LAST(pTxt)].hText;
  1067. // HACK HACK Need to account for tabs?
  1068. ptxt = LocalLock(h);
  1069. dw = GetTextExtentPoint(hdc, (LPSTR) ptxt + pTxt->iLeft, iLen, &size);
  1070. LocalUnlock(h);
  1071. iLine = pTxt->iCount - pTxt->iTop;
  1072. ReleaseDC(NULL,hdc);
  1073. y = OFFSETY + (iLine - 1) * pTxt->Tdy;
  1074. x = OFFSETX + size.cx;
  1075. SetCaretPos(x,y);
  1076. }
  1077. /*************************************************
  1078. *
  1079. * OUTPUT APIS
  1080. *
  1081. *************************************************/
  1082. /*
  1083. * fSuccess = SetOutput(hwnd, wCommand, lpszFile)
  1084. *
  1085. * Changes the output location of the window to be the location
  1086. * designated by wParam, one of the WPFOUT_ codes. If this specifies a
  1087. * file, lParam points to the filename.
  1088. *
  1089. * If the new output location cannot be opened/used, the previous output
  1090. * location is not altered and FALSE is returned. Otherwise, the
  1091. * previous output location is closed (for files) and TRUE is returned.
  1092. *
  1093. */
  1094. WORD NEAR PASCAL SetOutput(HWND hwnd, UINT wParam, LONG lParam)
  1095. {
  1096. PTXT pTxt;
  1097. int i;
  1098. HANDLE h;
  1099. int fhOld = -1;
  1100. #define COM1_FH (3) // stdaux
  1101. /* Check for invalid command code */
  1102. if (!(wParam == WPFOUT_WINDOW || wParam == WPFOUT_COM1 ||
  1103. wParam == WPFOUT_NEWFILE || wParam == WPFOUT_APPENDFILE ||
  1104. wParam == WPFOUT_DISABLED)) {
  1105. return FALSE;
  1106. }
  1107. h = GetWindowLong(hwnd, 0);
  1108. pTxt = (PTXT)LocalLock(h);
  1109. /* Save the old file handle */
  1110. fhOld = pTxt->iFile;
  1111. /* If I'm using a file output type, setup the file handle */
  1112. switch (wParam) {
  1113. case WPFOUT_COM1:
  1114. pTxt->iFile = COM1_FH;
  1115. break;
  1116. case WPFOUT_APPENDFILE:
  1117. /* Open file to see if it is there, then seek to end */
  1118. i = _lopen((LPSTR) lParam, OF_READWRITE);
  1119. if (i == -1) {
  1120. /* File didn't exist, just create it */
  1121. i = _lcreat((LPSTR) lParam, 0);
  1122. if (i == -1) {
  1123. /* Couldn't open, just return FALSE */
  1124. LocalUnlock(h);
  1125. return FALSE;
  1126. }
  1127. }
  1128. else {
  1129. /* Seek to the end of existing file */
  1130. _llseek(i, 0L, 2);
  1131. }
  1132. pTxt->iFile = i;
  1133. break;
  1134. case WPFOUT_NEWFILE:
  1135. i = _lcreat((LPSTR) lParam, 0);
  1136. if (i == -1) {
  1137. LocalUnlock(h);
  1138. return FALSE;
  1139. }
  1140. pTxt->iFile = i;
  1141. break;
  1142. case WPFOUT_DISABLED:
  1143. case WPFOUT_WINDOW:
  1144. pTxt->iFile = -1;
  1145. break;
  1146. }
  1147. /* Clear any existing open file handle by closing it */
  1148. if (fhOld != -1 && fhOld != COM1_FH) {
  1149. /* Close the file */
  1150. _lclose(fhOld);
  1151. }
  1152. pTxt->wOutputLocation = wParam;
  1153. LocalUnlock(h);
  1154. return TRUE;
  1155. }
  1156. /*
  1157. * wOutput = GetOutput(hwnd)
  1158. *
  1159. * Returns the output location for window hwnd (one of the WPFOUT_ codes)
  1160. *
  1161. */
  1162. WORD NEAR PASCAL GetOutput(HWND hwnd)
  1163. {
  1164. PTXT pTxt;
  1165. WORD w;
  1166. HANDLE h;
  1167. h = GetWindowLong(hwnd, 0);
  1168. pTxt = (PTXT) LocalLock(h);
  1169. w = pTxt->wOutputLocation;
  1170. LocalUnlock(h);
  1171. return w;
  1172. }
  1173. /*
  1174. * @doc EXTERNAL WINCOM WPFWINDOW
  1175. *
  1176. * @api int | wpfPrintf | This function prints a string to a WPF window
  1177. * (or redirected output device) using <f printf> style formatting
  1178. * codes. The output is placed at the end of the specified WPF window,
  1179. * which is scrolled as required. This function does not yield.
  1180. *
  1181. * @parm HWND | hwnd | Specifies the WPF window. Output to the window
  1182. * may be redirected to a file or COM1 by sending a WPF_SETOUTPUT window
  1183. * message to <p hwnd>. If output has been redirected, this parameter
  1184. * is still required as the current output location is stored in the WPF
  1185. * window instance data.
  1186. *
  1187. * @parm LPSTR | lpszFormat | Points to the output string format
  1188. * specification. This string uses the same formatting codes as the
  1189. * Windows <f wsprintf> function.
  1190. *
  1191. * @parm argument | [ arguments, ...] | Extra parameters
  1192. * as required by the
  1193. * formatting string. Note that these parameters are in the form
  1194. * required by <p wsprintf>, so that all string arguments must be far
  1195. * pointers (LPSTR) or be cast to be far pointers.
  1196. *
  1197. * @rdesc Returns the number of characters output. If output to
  1198. * the WPF window is disabled, zero is returned. The returned count of
  1199. * characters output does not include the translation of newline
  1200. * characters into carriage return newline sequences.
  1201. *
  1202. * @xref wpfVprintf
  1203. *
  1204. */
  1205. //int FAR cdecl wpfPrintf(HWND hwnd, LPSTR lpszFormat, ...)
  1206. //{
  1207. // return wpfVprintf(hwnd, lpszFormat, (LPSTR)(&lpszFormat + 1));
  1208. //}
  1209. /* wpfWrtTTY(hWnd, sz)
  1210. *
  1211. * Print <sz> to wprintf window <hWnd>.
  1212. *
  1213. */
  1214. BOOL NEAR PASCAL wpfWrtTTY(HWND hWnd, LPSTR sz)
  1215. {
  1216. RECT rect;
  1217. int iFree;
  1218. int iLine;
  1219. PTXT pTxt;
  1220. HTXT hTxt;
  1221. MSG rMsg;
  1222. POINT rPoint;
  1223. if (!hWnd) hWnd = hwndLast;
  1224. if (!hWnd || !IsWindow(hWnd))
  1225. return FALSE; /* fail if bad window handle */
  1226. hwndLast = hWnd;
  1227. hTxt = (HTXT)GetWindowLong (hWnd,0);
  1228. pTxt = (PTXT)LocalLock((HANDLE)hTxt);
  1229. iLine = pTxt->iCount - pTxt->iTop;
  1230. /*
  1231. * invalidate the last line to the bottom of window so
  1232. * new text will be painted.
  1233. */
  1234. GetClientRect(hWnd,&rect);
  1235. rect.top += (iLine-1) * pTxt->Tdy;
  1236. InvalidateRect (hWnd,&rect,FALSE);
  1237. InsertString (pTxt, sz); /* Insert text in the que */
  1238. iLine = (pTxt->iCount - pTxt->iTop) - iLine;
  1239. if (iLine > 0) {
  1240. WpfSetScrollRange (hWnd,FALSE);
  1241. WpfVScroll (hWnd,pTxt,pTxt->iCount);/* scroll all the way to bottom */
  1242. }
  1243. #if 0
  1244. else {
  1245. WpfSetScrollRange (hWnd,TRUE);
  1246. }
  1247. #endif
  1248. UpdateCursorPos(pTxt);
  1249. LocalUnlock((HANDLE)hTxt);
  1250. UpdateWindow (hWnd);
  1251. return TRUE;
  1252. }
  1253. /*
  1254. * @doc EXTERNAL WINCOM WPFWINDOW
  1255. *
  1256. * @api int | wpfVprintf | This function prints a string to a WPF window
  1257. * (or redirected output device) using <f printf> style formatting
  1258. * codes. This function is the same as the <f wpfOut> function, except
  1259. * that arguments to the format string are placed in an array of WORDs
  1260. * or DWORDs.
  1261. *
  1262. * @parm HWND | hwnd | Specifies the WPF window. Output to the window
  1263. * may be redirected to a file or COM1 by sending a WPF_SETOUTPUT window
  1264. * message to <p hwnd>. If output has been redirected, this parameter
  1265. * is still required as the current output location is stored in the WPF
  1266. * window instance data.
  1267. *
  1268. * @parm LPSTR | lpszFormat | Points to the output string format
  1269. * specification. This string uses the same formatting codes as the
  1270. * Windows <f wsprintf> function.
  1271. *
  1272. * @parm LPSTR | pargs | Points to an array of words, each of which
  1273. * specifies an argument for the format string <p lspzFormat>. The
  1274. * number, type, and interpretation of the arguments depend on the
  1275. * corresponding format control sequences in <p lpszFormat>.
  1276. *
  1277. * @rdesc Returns the number of characters output. If output to the
  1278. * WPF window is disabled, zero is returned. The returned count of
  1279. * characters output does not include the translation of newline
  1280. * characters into carriage return newline sequences.
  1281. *
  1282. * @xref wpfPrintf
  1283. *
  1284. */
  1285. //int FAR cdecl wpfVprintf(HWND hwnd, LPSTR lpszFormat, LPSTR pargs)
  1286. //{
  1287. // int i;
  1288. //
  1289. //
  1290. // i = wvsprintf(bufTmp, lpszFormat, pargs);
  1291. // wpfOut(hwnd, bufTmp);
  1292. //
  1293. // return i;
  1294. //}
  1295. /*
  1296. * @doc WINCOM EXTERNAL WPFWINDOW
  1297. *
  1298. * @api void | wpfOut | This function prints a string to a WPF window
  1299. * or redirected output device. No formatting is carried out upon the
  1300. * string, it is printed verbatim.
  1301. *
  1302. * @parm HWND | hwnd | Specifies the WPF window. Output to the window
  1303. * may be redirected to a file or COM1 by sending a WPF_SETOUTPUT window
  1304. * message to <p hwnd>. If output has been redirected, this parameter
  1305. * is still required as the current output location is stored in the WPF
  1306. * window instance data.
  1307. *
  1308. * @parm LPSTR | lpsz | Points to the string to be output.
  1309. *
  1310. * @rdesc None.
  1311. *
  1312. * @xref wpfPrintf
  1313. *
  1314. */
  1315. void FAR PASCAL wpfOut(HWND hwnd, LPSTR lpsz)
  1316. {
  1317. PTXT pTxt;
  1318. HTXT hTxt;
  1319. if (!IsWindow(hwnd))
  1320. return;
  1321. hTxt = (HTXT) GetWindowLong(hwnd, 0);
  1322. pTxt = (PTXT) LocalLock((HANDLE) hTxt);
  1323. if (pTxt->wOutputLocation != WPFOUT_DISABLED) {
  1324. if (pTxt->wOutputLocation == WPFOUT_WINDOW) {
  1325. wpfWrtTTY(hwnd, lpsz);
  1326. }
  1327. else {
  1328. wpfWrtFile(pTxt->iFile, lpsz);
  1329. }
  1330. }
  1331. LocalUnlock((HANDLE) hTxt);
  1332. }
  1333. void wpfWrtFile(int fh, LPSTR sz)
  1334. {
  1335. LPSTR p, q;
  1336. char save;
  1337. if (fh == -1)
  1338. return;
  1339. /* output to <fh>, but must convert \n's to \n\r's;
  1340. * code below is designed to minimize calls to write()
  1341. */
  1342. for (p = q = sz; *p != 0; p++) {
  1343. /* e.g. bufTmp="hello\nabc", q->'h', p->'\n' */
  1344. if (*p == '\n') {
  1345. /* hack: temporarily replace next char by \r */
  1346. /* won't work if string is READ-ONLY!!! */
  1347. save = *++p; /* remember it */
  1348. p[0] = '\n'; /* replace by \r */
  1349. p[-1]= '\r'; /* replace by \r */
  1350. _lwrite(fh, q, p - q + 1);
  1351. q = p; /* for next write() */
  1352. *p-- = save; /* un-hack */
  1353. *p = '\n';
  1354. }
  1355. }
  1356. if (p > q) /* any part of <bufTmp> left to write */
  1357. _lwrite(fh, q, p - q);
  1358. //
  1359. // flush the file, by closing a copy of the file
  1360. //
  1361. FlushFileBuffers(fh);
  1362. }