home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c081_7 / 2.ddi / WEXAMPLE.ZIP / MSGWND.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-02-13  |  30.6 KB  |  1,026 lines

  1. // Borland C++ - (C) Copyright 1991 by Borland International
  2.  
  3. //*******************************************************************
  4. //
  5. // program - Msgwnd.c
  6. // purpose - A windows program to recieve and display messages.
  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. #include <windows.h>
  17. #include <dde.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <time.h>
  22. #include <bios.h>
  23. #include <ctype.h>
  24. #include <io.h>
  25. #include <dos.h>
  26.  
  27. #include "msgwnd.h"
  28. #include "msgproc.h"
  29. #include "ddesrvr.h"
  30.  
  31. #define MAX_QRT_LEN 100
  32.  
  33. typedef struct scrollkeys
  34.   {
  35.     WORD wVirtkey;
  36.     int  iMessage;
  37.     WORD wRequest;
  38.   } SCROLLKEYS;
  39.  
  40. SCROLLKEYS key2scroll [] =
  41.   {
  42.     VK_HOME,  WM_COMMAND, IDM_HOME,
  43.     VK_END,   WM_VSCROLL, SB_BOTTOM,
  44.     VK_PRIOR, WM_VSCROLL, SB_PAGEUP,
  45.     VK_NEXT,  WM_VSCROLL, SB_PAGEDOWN,
  46.     VK_UP,    WM_VSCROLL, SB_LINEUP,
  47.     VK_DOWN,  WM_VSCROLL, SB_LINEDOWN,
  48.     VK_LEFT,  WM_HSCROLL, SB_PAGEUP,
  49.     VK_RIGHT, WM_HSCROLL, SB_PAGEDOWN
  50.   };
  51.  
  52. # define NUMKEYS (sizeof key2scroll / sizeof key2scroll[0])
  53.  
  54. // data initialized by first instance
  55. typedef struct tagSETUPDATA
  56.   {
  57.     char   szAppName[10]; // name of application
  58.   } SETUPDATA;
  59.  
  60. SETUPDATA SetUpData;
  61.  
  62. // Data that can be referenced throughout the
  63. // program but not passed to other instances
  64.  
  65. HANDLE    hInst;         // hInstance of application
  66. HWND      hWndMain;      // hWnd of main window
  67. //char      szAppName[10]; // name of application
  68.  
  69. int       xChar, yChar, yCharnl;
  70. int       xClient, yClient;
  71.  
  72. LOGFONT   cursfont;
  73. HANDLE    holdsfont;
  74. HANDLE    hnewsfont;
  75.  
  76. RECT      wrect;
  77.  
  78. // window scroll/paint stuff
  79. int       nVscrollMax, nHscrollMax;
  80. int       nVscrollPos, nHscrollPos;
  81. int       numlines;
  82. int       maxwidth;
  83. int       nVscrollInc, nHscrollInc;
  84. int       nPaintBeg, nPaintEnd;
  85. int       nPageMaxLines;
  86. int       plines;
  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(HANDLE hInstance, HANDLE hPrevInstance,
  101.                    LPSTR lpszCmdLine, int cmdShow);
  102.  
  103. BOOL                   InitMsgwnd(HANDLE hInstance, HANDLE hPrevInstance,
  104.                                  LPSTR lpszCmdLine, int cmdShow);
  105. BOOL                   InitMsgwndFirst(HANDLE hInstance);
  106. BOOL                   InitMsgwndAdded(HANDLE hPrevInstance);
  107. BOOL                   InitMsgwndEvery(HANDLE hInstance, int cmdShow);
  108. void                   CloseMsgwnd(HWND hWnd);
  109. BOOL FAR PASCAL        About(HWND hDlg, WORD message, WORD wParam, LONG lParam);
  110.  
  111. long FAR PASCAL        MsgwndWndProc(HWND hWnd, WORD message,
  112.                                     WORD wParam, LONG lParam);
  113.  
  114. void                   SetupScroll(HWND hWnd);
  115. void                   MsgwndPaint(HWND hWnd);
  116. void                   ScrollPrint(HWND hWnd, char *str);
  117. void                   ClearKeep(void);
  118.  
  119. //*******************************************************************
  120. // WinMain - Msgwnd 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(HANDLE hInstance, HANDLE hPrevInstance,
  139.                    LPSTR lpszCmdLine, int cmdShow)
  140. {
  141.     MSG   msg;
  142.     BOOL  brc;
  143.  
  144.     brc = InitMsgwnd(hInstance, hPrevInstance, lpszCmdLine, cmdShow);
  145.     if (brc == FALSE)
  146.         return(0);
  147.  
  148.     while (GetMessage(&msg, NULL, 0, 0))
  149.     {
  150.         TranslateMessage(&msg);
  151.         DispatchMessage(&msg);
  152.     }
  153.  
  154.     return(msg.wParam);
  155. }
  156.  
  157. //*******************************************************************
  158.  
  159. //*******************************************************************
  160. // InitMsgwnd - init the Msgwnd application
  161. //
  162. // paramaters:
  163. //             hInstance     - The instance of this instance of this
  164. //                             application.
  165. //             hPrevInstance - The instance of the previous instance
  166. //                             of this application. This will be 0
  167. //                             if this is the first instance.
  168. //             lpszCmdLine   - A long pointer to the command line that
  169. //                             started this application.
  170. //             cmdShow       - Indicates how the window is to be shown
  171. //                             initially. ie. SW_SHOWNORMAL, SW_HIDE,
  172. //                             SW_MIMIMIZE.
  173. //
  174. // returns:
  175. //             TRUE if successful.
  176. //               or
  177. //             FALSE if failure.
  178. //
  179. //*******************************************************************
  180. # pragma argsused
  181. BOOL InitMsgwnd(HANDLE hInstance, HANDLE hPrevInstance,
  182.                LPSTR lpszCmdLine, int cmdShow)
  183. {
  184.     BOOL brc;
  185.  
  186.     if (! hPrevInstance)
  187.         brc = InitMsgwndFirst(hInstance);
  188.     else
  189.         brc = InitMsgwndAdded(hPrevInstance);
  190.  
  191.     if (brc == TRUE)
  192.         brc = InitMsgwndEvery(hInstance, cmdShow);
  193.  
  194.     return(brc);
  195. }
  196.  
  197. //*******************************************************************
  198. // InitMsgwndFirst - done only for first instance of Msgwnd
  199. //
  200. // paramaters:
  201. //             hInstance     - The instance of this instance of this
  202. //                             application.
  203. //
  204. // returns:
  205. //             TRUE if successful.
  206. //               or
  207. //             FALSE if failure.
  208. //
  209. //*******************************************************************
  210. BOOL InitMsgwndFirst(HANDLE hInstance)
  211. {
  212.     WNDCLASS wcMsgwndClass;
  213.  
  214.     LoadString(hInstance, IDS_NAME, (LPSTR) SetUpData.szAppName, 10);
  215.  
  216.     // fill in window class information
  217.  
  218.     wcMsgwndClass.lpszClassName = SetUpData.szAppName;
  219.     wcMsgwndClass.hInstance     = hInstance;
  220.     wcMsgwndClass.lpfnWndProc   = MsgwndWndProc;
  221.     wcMsgwndClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
  222.     wcMsgwndClass.hIcon         = LoadIcon(hInstance, SetUpData.szAppName);
  223.     wcMsgwndClass.lpszMenuName  = (LPSTR) SetUpData.szAppName;
  224.     wcMsgwndClass.hbrBackground = GetStockObject(WHITE_BRUSH);
  225.     wcMsgwndClass.style         = CS_HREDRAW | CS_VREDRAW;
  226.     wcMsgwndClass.cbClsExtra    = 0;
  227.     wcMsgwndClass.cbWndExtra    = 0;
  228.  
  229.     // register the class
  230.  
  231.     if (!RegisterClass(&wcMsgwndClass))
  232.         return(FALSE);
  233.  
  234.     return(TRUE);
  235. }
  236.  
  237. //*******************************************************************
  238. // InitMsgwndAdded - done only for added instances of Msgwnd
  239. //
  240. // paramaters:
  241. //             hPrevInstance - The instance of the previous instance
  242. //                             of this application.
  243. //
  244. // returns:
  245. //             FALSE to indicate multiple instances are not allowed.
  246. //
  247. //*******************************************************************
  248. BOOL InitMsgwndAdded(HANDLE hPrevInstance)
  249. {
  250.     // get the results of the initialization of first instance
  251.     GetInstanceData(hPrevInstance, (PSTR) &SetUpData, sizeof(SETUPDATA));
  252.  
  253.     return(FALSE); // We are not allowing multiple MsgWnd apps.
  254. }
  255.  
  256. //*******************************************************************
  257. // InitMsgwndEvery - done for every instance of Msgwnd
  258. //
  259. // paramaters:
  260. //             hInstance     - The instance of this instance of this
  261. //                             application.
  262. //             cmdShow       - Indicates how the window is to be shown
  263. //                             initially. ie. SW_SHOWNORMAL, SW_HIDE,
  264. //                             SW_MIMIMIZE.
  265. //
  266. // returns:
  267. //             TRUE if successful.
  268. //
  269. //*******************************************************************
  270. BOOL InitMsgwndEvery(HANDLE hInstance, int cmdShow)
  271. {
  272.     TEXTMETRIC tm;
  273.     HDC        hDC;
  274.     char      *cp;
  275.     char       szWinLocStr[40];
  276.     int        x, y, w, h;
  277.  
  278.     hInst = hInstance;       // save for use by window procs
  279.  
  280.     // Get last location and size of Msgwnd from WIN.INI file.
  281.     GetProfileString("Msgwnd",
  282.                      "Window",
  283.                      "0,160,500,150",
  284.                      szWinLocStr,
  285.                      sizeof(szWinLocStr));
  286.  
  287.     // Decode location and size of window from profile string.
  288.     cp = szWinLocStr;
  289.     x = (int) strtol(cp, &cp, 10);
  290.     cp++;
  291.     y = (int) strtol(cp, &cp, 10);
  292.     cp++;
  293.     w = (int) strtol(cp, &cp, 10);
  294.     cp++;
  295.     h = (int) strtol(cp, &cp, 10);
  296.  
  297.     // Create our window.
  298.     hWndMain = CreateWindow(
  299.                   SetUpData.szAppName,     // window class name
  300.                   SetUpData.szAppName,     // window title
  301.                   WS_OVERLAPPEDWINDOW |    // type of window
  302.                     WS_HSCROLL |
  303.                     WS_VSCROLL,
  304.                   x,                       // x  window location
  305.           y,                       // y
  306.                   w,                       // cx and size
  307.                   h,                       // cy
  308.                   NULL,                    // no parent for this window
  309.                   NULL,                    // use the class menu
  310.                   hInstance,               // who created this window
  311.                   NULL                     // no parms to pass on
  312.                   );
  313.  
  314.     // Get window display context.
  315.     hDC = GetDC(hWndMain);
  316.  
  317.     // Build fixed screen font.
  318.     cursfont.lfHeight         =  6;
  319.     cursfont.lfWidth          =  6;
  320.     cursfont.lfEscapement     =  0;
  321.     cursfont.lfOrientation    =  0;
  322.     cursfont.lfWeight         =  FW_NORMAL;
  323.     cursfont.lfItalic         =  FALSE;
  324.     cursfont.lfUnderline      =  FALSE;
  325.     cursfont.lfStrikeOut      =  FALSE;
  326.     cursfont.lfCharSet        =  ANSI_CHARSET;
  327.     cursfont.lfOutPrecision   =  OUT_DEFAULT_PRECIS;
  328.     cursfont.lfClipPrecision  =  CLIP_DEFAULT_PRECIS;
  329.     cursfont.lfQuality        =  DEFAULT_QUALITY;
  330.     cursfont.lfPitchAndFamily =  FIXED_PITCH | FF_DONTCARE;
  331.     strcpy(cursfont.lfFaceName, "System");
  332.  
  333.     hnewsfont = CreateFontIndirect((LPLOGFONT) &cursfont);
  334.  
  335.     // Install fixed font in display context so text metrics will reflect
  336.     // that font.
  337.     holdsfont = SelectObject(hDC, hnewsfont);
  338.  
  339.     // Get text metrics to be used when painting the window.
  340.     GetTextMetrics(hDC, &tm);
  341.     xChar = tm.tmAveCharWidth;
  342.     yChar = tm.tmHeight + tm.tmExternalLeading;
  343.     yCharnl = tm.tmHeight;
  344.  
  345.     // Init a blank line.
  346.     blanklen = 255;
  347.     memset(blanks, ' ', blanklen);
  348.  
  349.     // Release the display context.
  350.     ReleaseDC(hWndMain, hDC);
  351.  
  352.     ShowWindow(hWndMain, cmdShow);
  353.     UpdateWindow(hWndMain);
  354.  
  355.     return(TRUE);
  356. }
  357.  
  358. //*******************************************************************
  359. // CloseMsgwnd - done at termination of every instance of Msgwnd
  360. //
  361. // paramaters:
  362. //             hWnd          - The callers window handle.
  363. //
  364. //*******************************************************************
  365. void CloseMsgwnd(HWND hWnd)
  366. {
  367.     RECT  wrect;
  368.     char  szWinLocStr[40];
  369.     int   w, h;
  370.  
  371.     // Clear out kept strings.
  372.     ClearKeep();
  373.  
  374.     // Get location and size of our window on the screen so we can
  375.     // come back up in the same spot next time we are invoked.
  376.  
  377.     GetWindowRect(hWnd, (LPRECT) &wrect);
  378.     w = wrect.right - wrect.left;
  379.     h = wrect.bottom - wrect.top;
  380.  
  381.     // Make a string with our window location and size.
  382.     sprintf(szWinLocStr, "%d,%d,%d,%d", wrect.left, wrect.top, w, h);
  383.  
  384.     // Save in WIN.INI file.
  385.     WriteProfileString("Msgwnd",
  386.                        "Window",
  387.                        szWinLocStr);
  388. }
  389.  
  390. //*******************************************************************
  391. // About - handle about dialog messages
  392. //
  393. // paramaters:
  394. //             hDlg          - The window handle for this dialog box
  395. //             message       - The message number
  396. //             wParam        - The WORD parmater for this message
  397. //             lParam        - The LONG parmater for this message
  398. //
  399. // returns:
  400. //             Depends on message.
  401. //
  402. //*******************************************************************
  403. # pragma argsused
  404. BOOL FAR PASCAL About(HWND hDlg, WORD message, WORD wParam, LONG lParam)
  405. {
  406.     if (message == WM_INITDIALOG)
  407.     return(TRUE);
  408.  
  409.     else if (message == WM_COMMAND)
  410.     {
  411.         switch (wParam)
  412.         {
  413.             case IDOK:
  414.                 EndDialog(hDlg, TRUE);
  415.                 return(TRUE);
  416.  
  417.             default:
  418.                 return(TRUE);
  419.         }
  420.     }
  421.  
  422.     return(FALSE);
  423. }
  424.  
  425. //*******************************************************************
  426.  
  427. //*******************************************************************
  428. // MsgwndWndProc - every message for this instance will come here
  429. //
  430. // Handle the messages for this application.
  431. //
  432. // paramaters:
  433. //             hWnd          - The window handle for this message
  434. //             message       - The message number
  435. //             wParam        - The WORD parmater for this message
  436. //             lParam        - The LONG parmater for this message
  437. //
  438. // returns:
  439. //             Depends on message.
  440. //
  441. //*******************************************************************
  442. long FAR PASCAL MsgwndWndProc(HWND hWnd, WORD message,
  443.                              WORD wParam, LONG lParam)
  444. {
  445.     FARPROC  lpproc;
  446.     int      i;
  447.     HWND     hClientWnd;
  448.  
  449.     switch (message)
  450.     {
  451.         case WM_DDE_INITIATE:
  452.             // If this message is recieved, it is being sent by another
  453.             // applicaton that is looking for a server on a particular
  454.             // application/topic combination.
  455.  
  456.             // Get the handle of this potential client.
  457.             hClientWnd = (HWND) wParam;
  458.  
  459.             // Go see if we support the application and topic he wants.
  460.             DDEServerInit(hWnd, hClientWnd, lParam, "msgwnd", "screen");
  461.             break;
  462.  
  463.         case WM_COMMAND:
  464.             switch (wParam)
  465.             {
  466.                 case IDM_QUIT:
  467.                     // User selected Quit on menu
  468.                     PostMessage(hWnd, WM_CLOSE, 0, 0L);
  469.                     break;
  470.  
  471.                 case IDM_HOME:
  472.                     // Used to implement home to topleft from keyboard.
  473.                     SendMessage(hWnd, WM_HSCROLL, SB_TOP, 0L); /* not set up */
  474.                     SendMessage(hWnd, WM_VSCROLL, SB_TOP, 0L);
  475.             break;
  476.  
  477.                 case IDM_ABOUT:
  478.                     // Display about box.
  479.                     lpproc = MakeProcInstance(About, hInst);
  480.                     DialogBox(hInst,
  481.                               MAKEINTRESOURCE(ABOUT),
  482.                               hWnd,
  483.                               lpproc);
  484.                     FreeProcInstance(lpproc);
  485.                     break;
  486.  
  487.                 default:
  488.                     break;
  489.             }
  490.             break;
  491.  
  492.     case WM_SIZE:
  493.             // Save size of window client area.
  494.             yClient = HIWORD(lParam);
  495.             xClient = LOWORD(lParam);
  496.  
  497.             // Go setup scroll ranges and file display area based upon
  498.             // client area size.
  499.             SetupScroll(hWnd);
  500.             break;
  501.  
  502.         case WM_VSCROLL:
  503.             // React to the various vertical scroll related actions.
  504.             switch (wParam)
  505.             {
  506.                 case SB_TOP:
  507.                     nVscrollInc = -nVscrollPos;
  508.                     break;
  509.  
  510.                 case SB_BOTTOM:
  511.                     nVscrollInc = nVscrollMax - nVscrollPos;
  512.                     break;
  513.  
  514.                 case SB_LINEUP:
  515.                     nVscrollInc = -1;
  516.                     break;
  517.  
  518.                 case SB_LINEDOWN:
  519.                     nVscrollInc = 1;
  520.                     break;
  521.  
  522.                 case SB_PAGEUP:
  523.                     nVscrollInc = -max(1, yClient / yChar);
  524.                     break;
  525.  
  526.         case SB_PAGEDOWN:
  527.                     nVscrollInc = max(1, yClient / yChar);
  528.                     break;
  529.  
  530.                 case SB_THUMBPOSITION:
  531.                     nVscrollInc = LOWORD(lParam) - nVscrollPos;
  532.                     break;
  533.  
  534.                 case SB_THUMBTRACK:
  535.                     nVscrollInc = LOWORD(lParam) - nVscrollPos;
  536.                     break;
  537.  
  538.                 default:
  539.                     nVscrollInc = 0;
  540.             }
  541.  
  542.             nVscrollInc = max(-nVscrollPos,
  543.                   min(nVscrollInc, nVscrollMax - nVscrollPos));
  544.             if (nVscrollInc)
  545.             {
  546.                 nVscrollPos += nVscrollInc;
  547.                 ScrollWindow(hWnd, 0, -yChar * nVscrollInc, NULL, NULL);
  548.                 SetScrollPos(hWnd, SB_VERT, nVscrollPos, TRUE);
  549.                 UpdateWindow(hWnd);
  550.             }
  551.             break;
  552.  
  553.         case WM_HSCROLL:
  554.             // React to the various horizontal scroll related actions.
  555.             switch (wParam)
  556.             {
  557.                 case SB_LINEUP:
  558.                     nHscrollInc = -1;
  559.                     break;
  560.  
  561.                 case SB_LINEDOWN:
  562.                     nHscrollInc = 1;
  563.                     break;
  564.  
  565.                 case SB_PAGEUP:
  566.                     nHscrollInc = -8;
  567.                     break;
  568.  
  569.                 case SB_PAGEDOWN:
  570.                     nHscrollInc = 8;
  571.                     break;
  572.  
  573.                 case SB_THUMBPOSITION:
  574.                     nHscrollInc = LOWORD(lParam) - nHscrollPos;
  575.                     break;
  576.  
  577.         case SB_THUMBTRACK:
  578.                     nHscrollInc = LOWORD(lParam) - nHscrollPos;
  579.                     break;
  580.  
  581.                 default:
  582.                     nHscrollInc = 0;
  583.             }
  584.  
  585.             nHscrollInc = max(-nHscrollPos,
  586.                               min(nHscrollInc, nHscrollMax - nHscrollPos));
  587.             if (nHscrollInc)
  588.             {
  589.                 nHscrollPos += nHscrollInc;
  590.                 ScrollWindow(hWnd, -xChar * nHscrollInc, 0, NULL, NULL);
  591.                 SetScrollPos(hWnd, SB_HORZ, nHscrollPos, TRUE);
  592.                 UpdateWindow(hWnd);
  593.             }
  594.         break;
  595.  
  596.         case WM_KEYDOWN:
  597.             // Translate various keydown messages to appropriate horizontal
  598.             // and vertical scroll actions.
  599.             for (i = 0; i < NUMKEYS; i++)
  600.             {
  601.                 if (wParam == key2scroll[i].wVirtkey)
  602.                 {
  603.                     SendMessage(hWnd, key2scroll[i].iMessage,
  604.                                 key2scroll[i].wRequest, 0L);
  605.                     break;
  606.                 }
  607.             }
  608.             break;
  609.  
  610.         case WM_PAINT:
  611.         // Go paint the client area of the window with the appropriate
  612.             // part of the selected file.
  613.             MsgwndPaint(hWnd);
  614.             break;
  615.  
  616.         case WM_DESTROY:
  617.             // This is the end if we were closed by a DestroyWindow call.
  618.             CloseMsgwnd(hWnd);    // take any necessary wrapup action.
  619.             PostQuitMessage(0);   // this is the end...
  620.             break;
  621.  
  622.         case WM_QUERYENDSESSION:
  623.             // If we return TRUE we are saying it's ok with us to end the
  624.             // windows session.
  625.             CloseMsgwnd(hWnd);    // take any necessary wrapup action.
  626.             return((long) TRUE);  // we agree to end session.
  627.  
  628.     case WM_CLOSE:
  629.             // Tell windows to destroy our window.
  630.             DestroyWindow(hWnd);
  631.             break;
  632.  
  633.         default:
  634.             // Let windows handle all messages we choose to ignore.
  635.             return(DefWindowProc(hWnd, message, wParam, lParam));
  636.     }
  637.  
  638.     return(0L);
  639. }
  640.  
  641. //*******************************************************************
  642. // SetupScroll - setup scroll ranges
  643. //
  644. //   Setup the vertical and horizontal scroll ranges and positions
  645. //   of the applicatons main window based on:
  646. //
  647. //       numlines - The maximum number of lines to display.
  648. //       maxwidth - The maximum width of any line to display.
  649. //
  650. //   The resulting variables, nVscrollPos and nPageMaxLines, are used
  651. //   by the function MsgwndPaint to determine what part of the selected
  652. //   file to display in the window.
  653. //
  654. // paramaters:
  655. //             hWnd          - The callers window handle.
  656. //
  657. //*******************************************************************
  658. void SetupScroll(HWND hWnd)
  659. {
  660.     // numlines established during open
  661.     nVscrollMax = max(0, numlines - yClient / yChar);
  662.     nVscrollPos = min(nVscrollPos, nVscrollMax);
  663.  
  664.     nHscrollMax = max(0, maxwidth - xClient / xChar);
  665.     nHscrollPos = min(nHscrollPos, nHscrollMax);
  666.  
  667.     SetScrollRange (hWnd, SB_VERT, 0, nVscrollMax, FALSE);
  668.     SetScrollPos   (hWnd, SB_VERT, nVscrollPos, TRUE);
  669.  
  670.     SetScrollRange (hWnd, SB_HORZ, 0, nHscrollMax, FALSE);
  671.     SetScrollPos   (hWnd, SB_HORZ, nHscrollPos, TRUE);
  672.  
  673.     nPageMaxLines = min(numlines, yClient / yChar);
  674.  
  675.     rect.left = 0;
  676.     rect.top = 0;
  677.     rect.right = xClient;
  678.     rect.bottom = yClient;
  679.  
  680.     blanklen = rect.right / xChar + 1;
  681. }
  682.  
  683. //*******************************************************************
  684. // MsgwndPaint - paint the main window
  685. //
  686. // This function is responsible for redisplaying a portion of the saved
  687. // strings.  Which strings it displays depends on the current scroll
  688. // position.
  689. //
  690. // paramaters:
  691. //             hWnd          - The callers window handle
  692. //
  693. //*******************************************************************
  694. void MsgwndPaint(HWND hWnd)
  695. {
  696.     PAINTSTRUCT  ps;
  697.     HDC          hDC;
  698.     char         currec[256];
  699.     int          ypos;
  700.     LPSTR        lcp;
  701.     int          i;
  702.     int          ndone;
  703.  
  704.     // Get display context.
  705.     BeginPaint(hWnd, (LPPAINTSTRUCT) &ps);
  706.     hDC = ps.hdc;
  707.  
  708.     // Select fixed font.
  709.     SelectObject(hDC, hnewsfont);
  710.  
  711.     // Setup scroll ranges.
  712.     SetupScroll(hWnd);
  713.  
  714.     // See if we have any lines to show.
  715.     if (hwm_keep)
  716.       {
  717.         // Y position of bottom line in client area.
  718.         ypos = rect.bottom - yChar;
  719.  
  720.         // Index into keep list of first line (from bottom) to show.
  721.         i = nVscrollMax - nVscrollPos;
  722.  
  723.         ndone = 1;
  724.         while (ndone)
  725.           {
  726.             lcp = GlobalLock(hkeep[i]);
  727.             if (lcp)
  728.               {
  729.                 // We must fill line with blanks to width of window
  730.         // or else some previous longet text might show through.
  731.                 _fstrcpy(currec, blanks);
  732.  
  733.                 // Line to show.
  734.                 _fstrncpy(currec, lcp, _fstrlen(lcp));
  735.  
  736.                 // Send to window.
  737.                 TextOut(hDC,
  738.                         xChar * (-nHscrollPos + 0),
  739.                         ypos,
  740.                         currec,
  741.                         blanklen);
  742.  
  743.                 // New Y is one character height higher.
  744.                 ypos -= yChar;
  745.  
  746.                 GlobalUnlock(hkeep[i]);
  747.           }
  748.  
  749.             // Index of next keep string to show.
  750.             i++;
  751.  
  752.             // No use drawing lines beyond top of client area.
  753.             // They would not show, so don't wast the energy.
  754.             if (ypos < -yChar)
  755.               ndone = 0;
  756.  
  757.             // Have we done all of the lines?
  758.             if (i > (hwm_keep - 1))
  759.               ndone = 0;
  760.           }
  761.       }
  762.  
  763.     // Release the display context.
  764.     ReleaseDC(hWnd, hDC);
  765.  
  766.     EndPaint(hWnd, (LPPAINTSTRUCT) &ps);
  767. }
  768.  
  769. //*******************************************************************
  770. // ScrollPrint - saves string sent to it and cause it to display
  771. //
  772. // This function gets a string and saves it in a list of strings.
  773. // The oldest string is deleted when the list reaches its maximum
  774. // size.
  775. //
  776. // Depending on the scroll position at the time the string is recieved
  777. // one of two methods of displaying the string will be used:
  778. //
  779. // If the scroll position was at the bottom, the window is scrolled up
  780. // one line, the bottom line is made invalid, and windows is told to
  781. // repaint. This will cause only the new string to be output, resulting
  782. // in minimum redraw on the screen.
  783. //
  784. // If the scroll position was not at the bottom of the window because
  785. // the user had been looking at previous messages, windows will be told
  786. // to redraw the entire window starting with the new string.
  787. //
  788. // paramaters:
  789. //             hWnd          - The window to put the message in.
  790. //             str           - the string to print in window.
  791. //
  792. //*******************************************************************
  793. void ScrollPrint(HWND hWnd, char *str)
  794. {
  795.     HDC   hDC;
  796.     char  currec[256];
  797.     int   i;
  798.     int   lstr;
  799.     LPSTR lcp;
  800.     RECT  trect;
  801.  
  802.     // If our keep stack is full free oldest member.
  803.     if (hwm_keep >= MAX_KEEP)
  804.       GlobalFree(hkeep[hwm_keep]);
  805.  
  806.     // Move all handles to make room for new one.
  807.     for (i = hwm_keep; i > 0; i--)
  808.       hkeep[i] = hkeep[i - 1];
  809.  
  810.     // If keep stack not yet full add one to high watter mark.
  811.     if (hwm_keep < MAX_KEEP)
  812.       hwm_keep++;
  813.  
  814.     // Make sure we know how many saved lines there are.
  815.     numlines = hwm_keep;
  816.  
  817.     // Length of new string.
  818.     lstr = strlen(str);
  819.  
  820.     // Is it longer than any previous string.
  821.     if (lstr > maxwidth)
  822.       maxwidth = lstr;
  823.  
  824.     // Get storage to save it.
  825.     hkeep[0] = GlobalAlloc(GMEM_MOVEABLE, (DWORD) (lstr + 1));
  826.     if (hkeep[0])
  827.       {
  828.         // Lock it down to get address.
  829.         lcp = GlobalLock(hkeep[0]);
  830.         if (lcp)
  831.       {
  832.             // Save string.
  833.             _fstrcpy(lcp, str);
  834.             GlobalUnlock(hkeep[0]);
  835.           }
  836.       }
  837.  
  838.     // See what we have to do to display it efficently.
  839.     if (!(nVscrollMax - nVscrollPos))
  840.       {
  841.         // We are scrolled to bottom of list.
  842.  
  843.         // Scroll contents of window up one character hehght.
  844.         ScrollWindow(hWnd, 0, -yChar, &rect, &rect);
  845.  
  846.         // Set scroll position to last line
  847.         nVscrollPos = numlines - yChar / yClient;
  848.  
  849.         // Tell windows to repaint only the bottom line of window.
  850.         GetClientRect(hWnd, &trect);
  851.         trect.top = trect.bottom - yChar;
  852.         InvalidateRect(hWnd, &trect, TRUE);
  853.       }
  854.     else
  855.       {
  856.         // We are not scrolled to bottom of list.
  857.  
  858.         // Set scroll position to last line.
  859.         nVscrollPos = numlines - yChar / yClient;
  860.  
  861.     // Tell windows to repaint the entire window.
  862.     InvalidateRect(hWnd, NULL, TRUE);
  863.       }
  864. }
  865.  
  866. //*******************************************************************
  867. // ClearKeep - free all saved strings
  868. //*******************************************************************
  869. void ClearKeep()
  870.   {
  871.     int i;
  872.  
  873.     for (i = 0; i < hwm_keep; i++)
  874.       {
  875.     GlobalFree(hkeep[i]);
  876.     hkeep[i] = 0;
  877.       }
  878.  
  879.     // Reset counters.
  880.     numlines = hwm_keep = 0;
  881.   }
  882.  
  883. //*******************************************************************
  884.  
  885. //*******************************************************************
  886. // DDEExecuteCommand - execute a command send by client
  887. //
  888. // paramaters:
  889. //             lpCommand  - command from client to be executed.
  890. //
  891. //             commands supported:
  892. //
  893. //               print   - print a line in window.
  894. //                         [print ("line to print")]
  895. //
  896. //               clear   - clear the window.
  897. //                         [clear]
  898. //
  899. // returns:
  900. //             1 - if command successful.
  901. //             0 - if not successful.
  902. //
  903. //*******************************************************************
  904. int DDEExecuteCommand(LPSTR lpCommand)
  905. {
  906.     int   nRc;
  907.     LPSTR lcp;
  908.     LPSTR lcp1;
  909.     LPSTR lcp2;
  910.     char  buf[256];
  911.  
  912.     // Init return code.
  913.     nRc = 0;
  914.  
  915.     // Find start of command.
  916.     lcp = _fstrchr(lpCommand, '[');
  917.     if (lcp)
  918.     {
  919.         // See what the command is.
  920.         lcp++;
  921.  
  922.         if (!_fstrncmp(lcp, "print", 5)) // Print a line to window.
  923.         {
  924.             // Find string between quotes (does not support embeded quotes)
  925.             lcp1 = _fstrchr(lcp, '\"');
  926.             if (lcp1)
  927.             {
  928.                 lcp1++;
  929.                 lcp2 = _fstrchr(lcp1, '\"');
  930.         if (lcp2)
  931.                 {
  932.                     *lcp2 = 0;
  933.                     _fstrcpy(buf, lcp1);
  934.  
  935.                     // Print the string to window.
  936.                     ScrollPrint(hWndMain, buf);
  937.  
  938.                     // Increment line count.
  939.                     plines++;
  940.  
  941.             nRc = 1;
  942.                 }
  943.             }
  944.         }
  945.  
  946.         else if (!_fstrncmp(lcp, "clear", 5))  // Clear window.
  947.     {
  948.             // Delete saved strings.
  949.             ClearKeep();
  950.  
  951.             // Clear the window.
  952.             InvalidateRect(hWndMain, NULL, TRUE);
  953.             UpdateWindow(hWndMain);
  954.  
  955.             // Reset line count.
  956.             plines = 0;
  957.  
  958.         nRc = 1;
  959.         }
  960.     }
  961.  
  962.     return(nRc);
  963. }
  964.  
  965. //*******************************************************************
  966. // DDEData - get data requested by client
  967. //
  968. // paramaters:
  969. //             szItem     - name of data item requested.
  970. //
  971. //             items supported:
  972. //
  973. //               lines   - the number lines printed to window.
  974. //
  975. // returns:
  976. //             Size of data item.
  977. //               or
  978. //             Zero if no data item.
  979. //
  980. //*******************************************************************
  981. int DDEData(char *szItem, HANDLE *hData)
  982. {
  983.     int   nRc;
  984.     int   len;
  985.     char  buf[30];
  986.     LPSTR lpData;
  987.  
  988.     // Init return code.
  989.     nRc = 0;
  990.  
  991.     // See what data item is being requested.
  992.     if (!stricmp(szItem, "lines"))
  993.     {
  994.         // Format response.
  995.         sprintf(buf, "Lines = %d", plines);
  996.  
  997.         // Get length of response.
  998.     len = strlen(buf);
  999.  
  1000.         // Get memory for response.
  1001.         *hData = GlobalAlloc(GMEM_MOVEABLE, (DWORD) (len + 1));
  1002.         if (*hData)
  1003.         {
  1004.             lpData = GlobalLock(*hData);
  1005.             if (lpData)
  1006.             {
  1007.                 // Copy response to memory.
  1008.                 _fstrcpy(lpData, buf);
  1009.         GlobalUnlock(*hData);
  1010.  
  1011.                 // Set return code to length of data returned.
  1012.                 nRc = len;
  1013.             }
  1014.             else
  1015.         {
  1016.                 GlobalFree(*hData);
  1017.                 *hData = 0;
  1018.             }
  1019.         }
  1020.     }
  1021.  
  1022.     return(nRc);
  1023. }
  1024.  
  1025. //*******************************************************************
  1026.