home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 May / Pcwk5b98.iso / Borland / Cplus45 / BC45 / TSTAPP.PAK / TSTAPP.C < prev    next >
C/C++ Source or Header  |  1995-08-29  |  26KB  |  852 lines

  1. // Borland C++ - (C) Copyright 1991 by Borland International
  2.  
  3. //*******************************************************************
  4. //
  5. // program - TstApp.c
  6. // purpose - A windows program to send messages to msgwnd server.
  7. //           This illustrates how DDE messages can be sent from
  8. //       one application and received by another.
  9. //
  10. //           To use this program, build MSGWND and TSTAPP. There
  11. //       are project files for this. When you run TSTAPP, MSGWND
  12. //           will be started automatically.
  13. //
  14. //*******************************************************************
  15.  
  16. #define STRICT
  17. #include <windows.h>
  18. #include <dde.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <time.h>
  23. #include <bios.h>
  24. #include <ctype.h>
  25. #include <io.h>
  26. #include <dos.h>
  27. #include <windowsx.h>
  28.  
  29. #include "tstapp.h"
  30. #include "msgproc.h"
  31. #include "ddeclnt.h"
  32.  
  33. #define MAX_QRT_LEN 100
  34.  
  35. typedef struct scrollkeys
  36.   {
  37.     WORD wVirtkey;
  38.     int  iMessage;
  39.     WORD wRequest;
  40.   } SCROLLKEYS;
  41.  
  42. SCROLLKEYS key2scroll [] =
  43.   {
  44.     {VK_HOME,  WM_COMMAND, IDM_HOME},
  45.     {VK_END,   WM_VSCROLL, SB_BOTTOM},
  46.     {VK_PRIOR, WM_VSCROLL, SB_PAGEUP},
  47.     {VK_NEXT,  WM_VSCROLL, SB_PAGEDOWN},
  48.     {VK_UP,    WM_VSCROLL, SB_LINEUP},
  49.     {VK_DOWN,  WM_VSCROLL, SB_LINEDOWN},
  50.     {VK_LEFT,  WM_HSCROLL, SB_PAGEUP},
  51.     {VK_RIGHT, WM_HSCROLL, SB_PAGEDOWN}
  52.   };
  53.  
  54. # define NUMKEYS (sizeof key2scroll / sizeof key2scroll[0])
  55.  
  56. // data initialized by first instance
  57. typedef struct tagSETUPDATA
  58.   {
  59.     char   szAppName[10]; // name of application
  60.   } SETUPDATA;
  61.  
  62. SETUPDATA SetUpData;
  63.  
  64. // Data that can be referenced throughout the
  65. // program but not passed to other instances
  66.  
  67. HINSTANCE hInst;         // hInstance of application
  68. HWND      hWndMain;      // hWnd of main window
  69. //char      szAppName[10]; // name of application
  70.  
  71. int       xChar, yChar, yCharnl;
  72. int       xClient, yClient;
  73.  
  74. LOGFONT   cursfont;
  75. HFONT     holdsfont;
  76. HFONT     hnewsfont;
  77.  
  78. RECT      wrect;
  79.  
  80. // window scroll/paint stuff
  81. int       nVscrollMax, nHscrollMax;
  82. int       nVscrollPos, nHscrollPos;
  83. int       numlines;
  84. int       maxwidth;
  85. int       nVscrollInc, nHscrollInc;
  86. int       nPaintBeg, nPaintEnd;
  87. int       nPageMaxLines;
  88.  
  89. // for scroll print
  90. RECT      rect;
  91. int       blanklen;
  92. char      blanks[256];
  93.  
  94. // to keep lines
  95. # define  MAX_KEEP   50
  96. HANDLE    hkeep[MAX_KEEP + 1];
  97. int       hwm_keep;
  98.  
  99. // function prototypes
  100.  
  101. int      PASCAL        WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  102.                                LPSTR lpszCmdLine, int cmdShow);
  103.  
  104. void                   InitTstApp(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  105.                                  LPSTR lpszCmdLine, int cmdShow);
  106. void                   InitTstAppFirst(HINSTANCE hInstance);
  107. void                   InitTstAppEvery(HINSTANCE hInstance, int cmdShow);
  108. void                   CloseTstApp(void);
  109. BOOL FAR PASCAL        _export About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  110.  
  111. LRESULT CALLBACK       _export TstAppWndProc(HWND hWnd, UINT message,
  112.              WPARAM wParam, LPARAM lParam);
  113.  
  114. void                   SetupScroll(HWND hWnd);
  115. void                   TstAppPaint(HWND hWnd);
  116. void                   ScrollPrint(HWND hWnd, char *str);
  117. void                   ClearKeep(void);
  118.  
  119. //*******************************************************************
  120. // WinMain - TstApp main
  121. //
  122. // paramaters:
  123. //             hInstance     - The instance of this instance of this
  124. //                             application.
  125. //             hPrevInstance - The instance of the previous instance
  126. //                             of this application. This will be 0
  127. //                             if this is the first instance.
  128. //             lpszCmdLine   - A long pointer to the command line that
  129. //                             started this application.
  130. //             cmdShow       - Indicates how the window is to be shown
  131. //                             initially. ie. SW_SHOWNORMAL, SW_HIDE,
  132. //                             SW_MIMIMIZE.
  133. //
  134. // returns:
  135. //             wParam from last message.
  136. //
  137. //*******************************************************************
  138. int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  139.                    LPSTR lpszCmdLine, int cmdShow)
  140. {
  141.     MSG   msg;
  142.  
  143.     InitTstApp(hInstance, hPrevInstance, lpszCmdLine, cmdShow);
  144.  
  145.     while (GetMessage(&msg, NULL, 0, 0))
  146.     {
  147.         TranslateMessage(&msg);
  148.         DispatchMessage(&msg);
  149.     }
  150.  
  151.     return(msg.wParam);
  152. }
  153.  
  154. //*******************************************************************
  155.  
  156. #if !defined(__WIN32__)
  157. //*******************************************************************
  158. // InitTstAppAdded - done only for added instances of TstApp
  159. //
  160. // paramaters:
  161. //             hPrevInstance - The instance of the previous instance
  162. //                             of this application.
  163. //
  164. //*******************************************************************
  165. void InitTstAppAdded(HINSTANCE hPrevInstance)
  166. {
  167.     // get the results of the initialization of first instance
  168.     GetInstanceData(hPrevInstance, (BYTE*) &SetUpData, sizeof(SETUPDATA));
  169. }
  170. #endif
  171.  
  172. //*******************************************************************
  173. // InitTstApp - init the TstApp application
  174. //
  175. // paramaters:
  176. //             hInstance     - The instance of this instance of this
  177. //                             application.
  178. //             hPrevInstance - The instance of the previous instance
  179. //                             of this application. This will be 0
  180. //                             if this is the first instance.
  181. //             lpszCmdLine   - A long pointer to the command line that
  182. //                             started this application.
  183. //             cmdShow       - Indicates how the window is to be shown
  184. //                             initially. ie. SW_SHOWNORMAL, SW_HIDE,
  185. //                             SW_MIMIMIZE.
  186. //
  187. //*******************************************************************
  188. # pragma argsused
  189. void InitTstApp(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  190.                LPSTR lpszCmdLine, int cmdShow)
  191. {
  192.   #if defined(__WIN32__)
  193.     InitTstAppFirst(hInstance);
  194.   #else
  195.     if (! hPrevInstance)
  196.         InitTstAppFirst(hInstance);
  197.     else
  198.         InitTstAppAdded(hPrevInstance);
  199.   #endif
  200.  
  201.     InitTstAppEvery(hInstance, cmdShow);
  202. }
  203.  
  204. //*******************************************************************
  205. // InitTstAppFirst - done only for first instance of TstApp
  206. //
  207. // paramaters:
  208. //             hInstance     - The instance of this instance of this
  209. //                             application.
  210. //
  211. //*******************************************************************
  212. void InitTstAppFirst(HINSTANCE hInstance)
  213. {
  214.     WNDCLASS wcTstAppClass;
  215.  
  216.     LoadString(hInstance, IDS_NAME, (LPSTR) SetUpData.szAppName, 10);
  217.  
  218.     // fill in window class information
  219.  
  220.     wcTstAppClass.lpszClassName = SetUpData.szAppName;
  221.     wcTstAppClass.hInstance     = hInstance;
  222.     wcTstAppClass.lpfnWndProc   = TstAppWndProc;
  223.     wcTstAppClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
  224.     wcTstAppClass.hIcon         = LoadIcon(hInstance, SetUpData.szAppName);
  225.     wcTstAppClass.lpszMenuName  = (LPSTR) SetUpData.szAppName;
  226.     wcTstAppClass.hbrBackground = GetStockObject(WHITE_BRUSH);
  227.     wcTstAppClass.style         = CS_HREDRAW | CS_VREDRAW;
  228.     wcTstAppClass.cbClsExtra    = 0;
  229.     wcTstAppClass.cbWndExtra    = 0;
  230.  
  231.     // register the class
  232.  
  233.     RegisterClass(&wcTstAppClass);
  234. }
  235.  
  236. //*******************************************************************
  237. // InitTstAppEvery - done for every instance of TstApp
  238. //                   Will create the window and sets a fixed font
  239. //                   for tabular display.
  240. //
  241. // paramaters:
  242. //             hInstance     - The instance of this instance of this
  243. //                             application.
  244. //             cmdShow       - Indicates how the window is to be shown
  245. //                             initially. ie. SW_SHOWNORMAL, SW_HIDE,
  246. //                             SW_MIMIMIZE.
  247. //
  248. //*******************************************************************
  249. void InitTstAppEvery(HINSTANCE hInstance, int cmdShow)
  250. {
  251.     TEXTMETRIC tm;
  252.     HDC        hDC;
  253.  
  254.     hInst = hInstance;       // save for use by window procs
  255.  
  256.     hWndMain = CreateWindow(
  257.                   SetUpData.szAppName,     // window class name
  258.                   SetUpData.szAppName,     // window title
  259.                   WS_OVERLAPPEDWINDOW |    // type of window
  260.                     WS_HSCROLL |
  261.                     WS_VSCROLL,
  262.       CW_USEDEFAULT,           // x  window location
  263.                   0,                       // y
  264.                   500,                     // cx and size
  265.                   150,                     // cy
  266.                   NULL,                    // no parent for this window
  267.                   NULL,                    // use the class menu
  268.                   hInstance,               // who created this window
  269.                   NULL                     // no parms to pass on
  270.                   );
  271.  
  272.     hDC = GetDC(hWndMain);
  273.  
  274.     // build fied screen font
  275.     cursfont.lfHeight         =  6;
  276.     cursfont.lfWidth          =  6;
  277.     cursfont.lfEscapement     =  0;
  278.     cursfont.lfOrientation    =  0;
  279.     cursfont.lfWeight         =  FW_NORMAL;
  280.     cursfont.lfItalic         =  FALSE;
  281.     cursfont.lfUnderline      =  FALSE;
  282.     cursfont.lfStrikeOut      =  FALSE;
  283.     cursfont.lfCharSet        =  ANSI_CHARSET;
  284.     cursfont.lfOutPrecision   =  OUT_DEFAULT_PRECIS;
  285.     cursfont.lfClipPrecision  =  CLIP_DEFAULT_PRECIS;
  286.     cursfont.lfQuality        =  DEFAULT_QUALITY;
  287.     cursfont.lfPitchAndFamily =  FIXED_PITCH | FF_DONTCARE;
  288.     strcpy((char *)cursfont.lfFaceName, "System");
  289.  
  290.     hnewsfont = CreateFontIndirect((LPLOGFONT) &cursfont);
  291.     holdsfont = SelectObject(hDC, hnewsfont);
  292.  
  293.     // get text metrics for paint
  294.     GetTextMetrics(hDC, &tm);
  295.     xChar = tm.tmAveCharWidth;
  296.     yChar = tm.tmHeight + tm.tmExternalLeading;
  297.     yCharnl = tm.tmHeight;
  298.  
  299.     // init blank line
  300.     blanklen = 255;
  301.     memset(blanks, ' ', blanklen);
  302.  
  303.     ReleaseDC(hWndMain, hDC);
  304.  
  305.     ShowWindow(hWndMain, cmdShow);
  306.     UpdateWindow(hWndMain);
  307. }
  308.  
  309. //*******************************************************************
  310. // CloseTstApp - done at termination of every instance of TstApp
  311. //               This is where wrapup code that should be run
  312. //               at the termination of the application should go.
  313. //
  314. //*******************************************************************
  315. void CloseTstApp()
  316. {
  317.     ClearKeep();
  318.     CloseMsgWnd();
  319.     DeleteObject(hnewsfont);
  320. }
  321.  
  322. //*******************************************************************
  323. // About - handle about dialog box messages
  324. //
  325. // paramaters:
  326. //             hDlg          - The window handle for this dialog box
  327. //             message       - The message number
  328. //             wParam        - The WPARAM parameter for this message
  329. //             lParam        - The LPARAM parameter for this message
  330. //
  331. //*******************************************************************
  332. # pragma argsused
  333. BOOL FAR PASCAL _export About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  334. {
  335.     if (message == WM_INITDIALOG)
  336.         return(TRUE);
  337.  
  338.     else if (message == WM_COMMAND)
  339.     {
  340.   switch (GET_WM_COMMAND_ID(wParam, lParam))
  341.   {
  342.       case IDOK:
  343.     EndDialog(hDlg, TRUE);
  344.     return(TRUE);
  345.  
  346.       default:
  347.     return(TRUE);
  348.   }
  349.     }
  350.  
  351.     return(FALSE);
  352. }
  353.  
  354. //*******************************************************************
  355.  
  356. //*******************************************************************
  357. // TstAppWndProc - every message for this instance will come here
  358. //
  359. //   Handle the messages for this application.
  360. //
  361. // paramaters:
  362. //             hWnd          - The window handle for this message
  363. //             message       - The message number
  364. //             wParam        - The WPARAM parameter for this message
  365. //             lParam        - The LPARAM parameter for this message
  366. //
  367. // returns:
  368. //             depends on message.
  369. //
  370. //*******************************************************************
  371. LRESULT CALLBACK _export TstAppWndProc(HWND hWnd, UINT message,
  372.              WPARAM wParam, LPARAM lParam)
  373. {
  374.     static   int msgno;
  375.  
  376.     FARPROC  lpproc;
  377.     char     buf[128];
  378.     int      i;
  379.     HANDLE   hTmp;
  380.     LPSTR    lpTmp;
  381.  
  382.     switch (message)
  383.     {
  384.         case WMU_DDE_CLOSED:
  385.             // This message is sent by the ddeclnt module when the dde
  386.             // conversation is terminated.
  387.             CloseMsgWnd();
  388.             break;
  389.  
  390.   case WM_COMMAND:
  391.       switch (GET_WM_COMMAND_ID(wParam, lParam))
  392.       {
  393.     case IDM_QUIT:
  394.         // User has selected QUIT from menu.
  395.         PostMessage(hWnd, WM_CLOSE, 0, 0L);
  396.         break;
  397.  
  398.     case IDM_HOME:
  399.         // Home key was hit.
  400.         SendMessage(hWnd, WM_HSCROLL, GET_WM_COMMAND_MPS (SB_TOP, 0, 0));
  401.         SendMessage(hWnd, WM_VSCROLL, GET_WM_COMMAND_MPS (SB_TOP, 0, 0));
  402.         break;
  403.  
  404.     case IDM_ABOUT:
  405.         // User has selected ABOUT from menu.
  406.         lpproc = MakeProcInstance((FARPROC)About, hInst);
  407.         DialogBox(hInst,
  408.             MAKEINTRESOURCE(ABOUT),
  409.             hWnd,
  410.             (DLGPROC)lpproc);
  411.         FreeProcInstance(lpproc);
  412.         break;
  413.  
  414.     case IDM_MESSAGE:
  415.         // User has selected MSG from menu.
  416.  
  417.         // Format the message to send.
  418.         sprintf(buf, "TstApp hWnd %04X Msg # %04d: ", hWnd, ++msgno);
  419.  
  420.                     // Show it in our window.
  421.                     ScrollPrint(hWnd, buf);
  422.  
  423.         // Send it via dde to msgwnd application.
  424.                     SendMsgWndMsg(hWnd, "print", buf);
  425.                     break;
  426.  
  427.                 case IDM_CLEAR:
  428.                     // User has selected CLEAR from menu.
  429.  
  430.                     // Tell msgwnd applicaton to clear its window.
  431.                     SendMsgWndMsg(hWnd, "clear", NULL);
  432.                     break;
  433.  
  434.                 case IDM_LINES:
  435.                     // User has selected LINES from menu.
  436.  
  437.                     // Ask msgwnd applicaton how many lines it has recieved.
  438.                     hTmp = GetLines(hWnd);
  439.                     if (hTmp)
  440.                     {
  441.                         lpTmp = GlobalLock(hTmp);
  442.                         if (lpTmp)
  443.       {
  444.                             _fstrcpy(buf, lpTmp);
  445.                             ScrollPrint(hWnd, buf);
  446.                             GlobalUnlock(hTmp);
  447.                         }
  448.  
  449.                         GlobalFree(hTmp);
  450.                     }
  451.                     break;
  452.  
  453.                 default:
  454.                     break;
  455.             }
  456.             break;
  457.  
  458.         case WM_SIZE:
  459.             // Save size of window client area.
  460.  
  461.             yClient = HIWORD(lParam);
  462.             xClient = LOWORD(lParam);
  463.  
  464.             // Go setup scroll ranges and file display area based upon
  465.             // client area size.
  466.  
  467.             SetupScroll(hWnd);
  468.             break;
  469.  
  470.         case WM_VSCROLL:
  471.             // React to the various vertical scroll related actions.
  472.       switch (GET_WM_VSCROLL_CODE(wParam, lParam))
  473.       {
  474.     case SB_TOP:
  475.         nVscrollInc = -nVscrollPos;
  476.         break;
  477.  
  478.     case SB_BOTTOM:
  479.         nVscrollInc = nVscrollMax - nVscrollPos;
  480.         break;
  481.  
  482.     case SB_LINEUP:
  483.         nVscrollInc = -1;
  484.         break;
  485.  
  486.     case SB_LINEDOWN:
  487.         nVscrollInc = 1;
  488.         break;
  489.  
  490.     case SB_PAGEUP:
  491.         nVscrollInc = -max(1, yClient / yChar);
  492.         break;
  493.  
  494.     case SB_PAGEDOWN:
  495.         nVscrollInc = max(1, yClient / yChar);
  496.         break;
  497.  
  498.     case SB_THUMBPOSITION:
  499.         nVscrollInc = GET_WM_VSCROLL_POS(wParam, lParam) - nVscrollPos;
  500.         break;
  501.  
  502.     case SB_THUMBTRACK:
  503.         nVscrollInc = GET_WM_VSCROLL_POS(wParam, lParam) - nVscrollPos;
  504.         break;
  505.  
  506.     default:
  507.         nVscrollInc = 0;
  508.       }
  509.  
  510.             nVscrollInc = max(-nVscrollPos,
  511.                               min(nVscrollInc, nVscrollMax - nVscrollPos));
  512.             if (nVscrollInc)
  513.             {
  514.                 nVscrollPos += nVscrollInc;
  515.                 ScrollWindow(hWnd, 0, -yChar * nVscrollInc, NULL, NULL);
  516.                 SetScrollPos(hWnd, SB_VERT, nVscrollPos, TRUE);
  517.     UpdateWindow(hWnd);
  518.             }
  519.             break;
  520.  
  521.   case WM_HSCROLL:
  522.       // React to the various horizontal scroll related actions.
  523.       switch (GET_WM_HSCROLL_CODE(wParam, lParam))
  524.       {
  525.     case SB_LINEUP:
  526.         nHscrollInc = -1;
  527.         break;
  528.  
  529.     case SB_LINEDOWN:
  530.         nHscrollInc = 1;
  531.         break;
  532.  
  533.     case SB_PAGEUP:
  534.         nHscrollInc = -8;
  535.         break;
  536.  
  537.     case SB_PAGEDOWN:
  538.         nHscrollInc = 8;
  539.         break;
  540.  
  541.     case SB_THUMBPOSITION:
  542.         nHscrollInc = GET_WM_HSCROLL_POS(wParam, lParam) - nHscrollPos;
  543.         break;
  544.  
  545.     case SB_THUMBTRACK:
  546.         nHscrollInc = GET_WM_HSCROLL_POS(wParam, lParam) - nHscrollPos;
  547.         break;
  548.  
  549.     default:
  550.         nHscrollInc = 0;
  551.       }
  552.  
  553.       nHscrollInc = max(-nHscrollPos,
  554.             min(nHscrollInc, nHscrollMax - nHscrollPos));
  555.       if (nHscrollInc)
  556.       {
  557.     nHscrollPos += nHscrollInc;
  558.     ScrollWindow(hWnd, -xChar * nHscrollInc, 0, NULL, NULL);
  559.     SetScrollPos(hWnd, SB_HORZ, nHscrollPos, TRUE);
  560.     UpdateWindow(hWnd);
  561.       }
  562.       break;
  563.  
  564.   case WM_KEYDOWN:
  565.       // Translate various keydown messages to appropriate horizontal
  566.       // and vertical scroll actions.
  567.  
  568.       for (i = 0; i < NUMKEYS; i++)
  569.       {
  570.                 if (wParam == key2scroll[i].wVirtkey)
  571.                 {
  572.                     SendMessage(hWnd, key2scroll[i].iMessage,
  573.                                 key2scroll[i].wRequest, 0L);
  574.         break;
  575.                 }
  576.             }
  577.             break;
  578.  
  579.         case WM_PAINT:
  580.             // Go paint the client area of the window with the appropriate
  581.             // part of the selected file.
  582.  
  583.       TstAppPaint(hWnd);
  584.             break;
  585.  
  586.         case WM_DESTROY:
  587.       // This is the end if we were closed by a DestroyWindow call.
  588.             CloseTstApp();         // take any necessary wrapup action.
  589.             PostQuitMessage(0);    // this is the end...
  590.             break;
  591.  
  592.         case WM_QUERYENDSESSION:
  593.             // If we return TRUE we are saying it's ok with us to end the
  594.             // windows session.
  595.             CloseTstApp();         // take any necessary wrapup action.
  596.             return((long) TRUE);   // we agree to end session.
  597.  
  598.         case WM_CLOSE:
  599.             // Tell windows to terminate us.
  600.       DestroyWindow(hWnd);
  601.             break;
  602.  
  603.   default:
  604.             // Let windows handle all messages we choose to ignore.
  605.             return(DefWindowProc(hWnd, message, wParam, lParam));
  606.     }
  607.  
  608.     return(0L);
  609. }
  610.  
  611. //*******************************************************************
  612. // SetupScroll - setup scroll ranges
  613. //
  614. //   Setup the vertical and horizontal scroll ranges and positions
  615. //   of the applicatons main window based on:
  616. //
  617. //       numlines - The maximum number of lines to display.
  618. //       maxwidth - The maximum width of any line to display.
  619. //
  620. //   The resulting variables, nVscrollPos and nPageMaxLines, are used
  621. //   by the function TstAppPaint to determine what part of the selected
  622. //   file to display in the window.
  623. //
  624. // paramaters:
  625. //             hWnd          - The callers window handle
  626. //
  627. //*******************************************************************
  628. void SetupScroll(HWND hWnd)
  629. {
  630.     // numlines established during open
  631.     nVscrollMax = max(0, numlines - yClient / yChar);
  632.     nVscrollPos = min(nVscrollPos, nVscrollMax);
  633.  
  634.     nHscrollMax = max(0, maxwidth - xClient / xChar);
  635.     nHscrollPos = min(nHscrollPos, nHscrollMax);
  636.  
  637.     SetScrollRange (hWnd, SB_VERT, 0, nVscrollMax, FALSE);
  638.     SetScrollPos   (hWnd, SB_VERT, nVscrollPos, TRUE);
  639.  
  640.     SetScrollRange (hWnd, SB_HORZ, 0, nHscrollMax, FALSE);
  641.     SetScrollPos   (hWnd, SB_HORZ, nHscrollPos, TRUE);
  642.  
  643.     nPageMaxLines = min(numlines, yClient / yChar);
  644.  
  645.     rect.left = 0;
  646.     rect.top = 0;
  647.     rect.right = xClient;
  648.     rect.bottom = yClient;
  649.  
  650.     blanklen = rect.right / xChar + 1;
  651. }
  652.  
  653. //*******************************************************************
  654. // TstAppPaint - paint the main window
  655. //
  656. // This function is responsible for redisplaying a portion of the saved
  657. // strings.  Which strings it displays depends on the current scroll
  658. // position.
  659. //
  660. // paramaters:
  661. //             hWnd          - The callers window handle
  662. //
  663. //*******************************************************************
  664. void TstAppPaint(HWND hWnd)
  665. {
  666.     PAINTSTRUCT  ps;
  667.     HDC          hDC;
  668.     char         currec[256];
  669.     int          ypos;
  670.     LPSTR        lcp;
  671.     int          i;
  672.     int          ndone;
  673.  
  674.     // Get display context.
  675.     BeginPaint(hWnd, (LPPAINTSTRUCT) &ps);
  676.     hDC = ps.hdc;
  677.  
  678.     // Select fixed font.
  679.     SelectObject(hDC, hnewsfont);
  680.  
  681.     // Setup scroll ranges.
  682.     SetupScroll(hWnd);
  683.  
  684.     // See if we have any lines to show.
  685.     if (hwm_keep)
  686.       {
  687.         // Y position of bottom line in client area.
  688.         ypos = rect.bottom - yChar;
  689.  
  690.   // Index into keep list of first line (from bottom) to show.
  691.   i = nVscrollMax - nVscrollPos;
  692.  
  693.         ndone = 1;
  694.         while (ndone)
  695.           {
  696.             lcp = GlobalLock(hkeep[i]);
  697.             if (lcp)
  698.               {
  699.                 // We must fill line with blanks to width of window
  700.                 // or else some previous longet text might show through.
  701.                 _fstrcpy(currec, blanks);
  702.  
  703.                 // Line to show.
  704.     _fstrncpy(currec, lcp, _fstrlen(lcp));
  705.  
  706.                 // Send to window.
  707.                 TextOut(hDC,
  708.                         xChar * (-nHscrollPos + 0),
  709.                         ypos,
  710.                         currec,
  711.                         blanklen);
  712.  
  713.                 // New Y is one character height higher.
  714.                 ypos -= yChar;
  715.  
  716.                 GlobalUnlock(hkeep[i]);
  717.         }
  718.  
  719.             // Index of next keep string to show.
  720.             i++;
  721.  
  722.             // No use drawing lines beyond top of client area.
  723.             // They would not show, so don't wast the energy.
  724.             if (ypos < -yChar)
  725.               ndone = 0;
  726.  
  727.             // Have we done all of the lines?
  728.             if (i > (hwm_keep - 1))
  729.               ndone = 0;
  730.     }
  731.       }
  732.  
  733.     // Release the display context.
  734.     EndPaint(hWnd, (LPPAINTSTRUCT) &ps);
  735. }
  736.  
  737. //*******************************************************************
  738. // ScrollPrint - saves string sent to it and cause it to display
  739. //
  740. // This function gets a string and saves it in a list of strings.
  741. // The oldest string is deleted when the list reaches its maximum
  742. // size.
  743. //
  744. // Depending on the scroll position at the time the string is recieved
  745. // one of two methods of displaying the string will be used:
  746. //
  747. // If the scroll position was at the bottom, the window is scrolled up
  748. // one line, the bottom line is made invalid, and windows is told to
  749. // repaint. This will cause only the new string to be output, resulting
  750. // in minimum redraw on the screen.
  751. //
  752. // If the scroll position was not at the bottom of the window because
  753. // the user had been looking at previous messages, windows will be told
  754. // to redraw the entire window starting with the new string.
  755. //
  756. // paramaters:
  757. //             hWnd          - The window to put the message in.
  758. //             str           - the string to print in window.
  759. //
  760. //*******************************************************************
  761. void ScrollPrint(HWND hWnd, char *str)
  762. {
  763.     int   i;
  764.     int   lstr;
  765.     LPSTR lcp;
  766.     RECT  trect;
  767.  
  768.     // If our keep stack is full free oldest member.
  769.     if (hwm_keep >= MAX_KEEP)
  770.       GlobalFree(hkeep[hwm_keep]);
  771.  
  772.     // Move all handles to make room for new one.
  773.     for (i = hwm_keep; i > 0; i--)
  774.       hkeep[i] = hkeep[i - 1];
  775.  
  776.     // If keep stack not yet full add one to high watter mark.
  777.     if (hwm_keep < MAX_KEEP)
  778.       hwm_keep++;
  779.  
  780.     // Make sure we know how many saved lines there are.
  781.     numlines = hwm_keep;
  782.  
  783.     // Length of new string.
  784.     lstr = strlen(str);
  785.  
  786.     // Is it longer than any previous string.
  787.     if (lstr > maxwidth)
  788.       maxwidth = lstr;
  789.  
  790.     // Get storage to save it.
  791.     hkeep[0] = GlobalAlloc(GMEM_MOVEABLE, (DWORD) (lstr + 1));
  792.     if (hkeep[0])
  793.       {
  794.         // Lock it down to get address.
  795.   lcp = GlobalLock(hkeep[0]);
  796.         if (lcp)
  797.           {
  798.       // Save string.
  799.             _fstrcpy(lcp, str);
  800.             GlobalUnlock(hkeep[0]);
  801.           }
  802.       }
  803.  
  804.     // See what we have to do to display it efficently.
  805.     if (!(nVscrollMax - nVscrollPos))
  806.       {
  807.         // We are scrolled to bottom of list.
  808.  
  809.         // Scroll contents of window up one character hehght.
  810.         ScrollWindow(hWnd, 0, -yChar, &rect, &rect);
  811.  
  812.         // Set scroll position to last line
  813.         nVscrollPos = numlines - yChar / yClient;
  814.  
  815.         // Tell windows to repaint only the bottom line of window.
  816.         GetClientRect(hWnd, &trect);
  817.         trect.top = trect.bottom - yChar;
  818.   InvalidateRect(hWnd, &trect, TRUE);
  819.       }
  820.     else
  821.       {
  822.         // We are not scrolled to bottom of list.
  823.  
  824.         // Set scroll position to last line.
  825.         nVscrollPos = numlines - yChar / yClient;
  826.  
  827.         // Tell windows to repaint the entire window.
  828.         InvalidateRect(hWnd, NULL, TRUE);
  829.       }
  830. }
  831.  
  832. //*******************************************************************
  833. // ClearKeep - free all saved strings
  834. //
  835. //
  836. //*******************************************************************
  837. void ClearKeep()
  838.   {
  839.     int i;
  840.  
  841.     for (i = 0; i < hwm_keep; i++)
  842.       {
  843.         GlobalFree(hkeep[i]);
  844.         hkeep[i] = 0;
  845.       }
  846.  
  847.     // Reset counters.
  848.     numlines = hwm_keep = 0;
  849.   }
  850.  
  851. //*******************************************************************
  852.