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