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

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