home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c082_122 / 6.ddi / WEXAMPLE.ZIP / MSGWND.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-10  |  30.6 KB  |  1,024 lines

  1. // Borland C++ - (C) Copyright 1991, 1992 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. #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 "msgwnd.h"
  29. #include "msgproc.h"
  30. #include "ddesrvr.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.  
  69. int       xChar, yChar, yCharnl;
  70. int       xClient, yClient;
  71.  
  72. LOGFONT   cursfont;
  73. HFONT     holdsfont;
  74. HFONT     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(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  101.                    LPSTR lpszCmdLine, int cmdShow);
  102.  
  103. BOOL                   InitMsgwnd(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  104.                                  LPSTR lpszCmdLine, int cmdShow);
  105. BOOL                   InitMsgwndFirst(HINSTANCE hInstance);
  106. BOOL                   InitMsgwndAdded(HINSTANCE hPrevInstance);
  107. BOOL                   InitMsgwndEvery(HINSTANCE hInstance, int cmdShow);
  108. void                   CloseMsgwnd(HWND hWnd);
  109. BOOL CALLBACK          About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  110.  
  111. LRESULT CALLBACK       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. //*******************************************************************
  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(HINSTANCE hInstance, HINSTANCE 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(HINSTANCE 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(HINSTANCE hPrevInstance)
  249. {
  250.     // get the results of the initialization of first instance
  251.     GetInstanceData(hPrevInstance, (BYTE*) &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(HINSTANCE 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((char *)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.     // Delete font
  390.     DeleteObject(hnewsfont);
  391. }
  392.  
  393. //*******************************************************************
  394. // About - handle about dialog messages
  395. //
  396. // paramaters:
  397. //             hDlg          - The window handle for this dialog box
  398. //             message       - The message number
  399. //             wParam        - The WPARAM parameter for this message
  400. //             lParam        - The LPARAM parameter for this message
  401. //
  402. // returns:
  403. //             Depends on message.
  404. //
  405. //*******************************************************************
  406. # pragma argsused
  407. BOOL CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  408. {
  409.     if (message == WM_INITDIALOG)
  410.     return(TRUE);
  411.  
  412.     else if (message == WM_COMMAND)
  413.     {
  414.         switch (wParam)
  415.         {
  416.             case IDOK:
  417.                 EndDialog(hDlg, TRUE);
  418.                 return(TRUE);
  419.  
  420.             default:
  421.                 return(TRUE);
  422.         }
  423.     }
  424.  
  425.     return(FALSE);
  426. }
  427.  
  428. //*******************************************************************
  429.  
  430. //*******************************************************************
  431. // MsgwndWndProc - every message for this instance will come here
  432. //
  433. // Handle the messages for this application.
  434. //
  435. // paramaters:
  436. //             hWnd          - The window handle for this message
  437. //             message       - The message number
  438. //             wParam        - The WPARAM parameter for this message
  439. //             lParam        - The LPARAM parameter for this message
  440. //
  441. // returns:
  442. //             Depends on message.
  443. //
  444. //*******************************************************************
  445. LRESULT CALLBACK MsgwndWndProc(HWND hWnd, UINT message,
  446.                  WPARAM wParam, LPARAM lParam)
  447. {
  448.     DLGPROC  lpproc;
  449.     int      i;
  450.     HWND     hClientWnd;
  451.  
  452.     switch (message)
  453.     {
  454.         case WM_DDE_INITIATE:
  455.             // If this message is recieved, it is being sent by another
  456.             // applicaton that is looking for a server on a particular
  457.             // application/topic combination.
  458.  
  459.             // Get the handle of this potential client.
  460.             hClientWnd = (HWND) wParam;
  461.  
  462.             // Go see if we support the application and topic he wants.
  463.             DDEServerInit(hWnd, hClientWnd, lParam, "msgwnd", "screen");
  464.             break;
  465.  
  466.         case WM_COMMAND:
  467.             switch (wParam)
  468.             {
  469.                 case IDM_QUIT:
  470.                     // User selected Quit on menu
  471.                     PostMessage(hWnd, WM_CLOSE, 0, 0L);
  472.                     break;
  473.  
  474.                 case IDM_HOME:
  475.                     // Used to implement home to topleft from keyboard.
  476.                     SendMessage(hWnd, WM_HSCROLL, SB_TOP, 0L); /* not set up */
  477.                     SendMessage(hWnd, WM_VSCROLL, SB_TOP, 0L);
  478.             break;
  479.  
  480.                 case IDM_ABOUT:
  481.                     // Display about box.
  482.             lpproc = (DLGPROC)MakeProcInstance((FARPROC)About, hInst);
  483.                     DialogBox(hInst,
  484.                               MAKEINTRESOURCE(ABOUT),
  485.                               hWnd,
  486.                               lpproc);
  487.                     FreeProcInstance((FARPROC)lpproc);
  488.                     break;
  489.  
  490.                 default:
  491.                     break;
  492.             }
  493.             break;
  494.  
  495.     case WM_SIZE:
  496.             // Save size of window client area.
  497.             yClient = HIWORD(lParam);
  498.             xClient = LOWORD(lParam);
  499.  
  500.             // Go setup scroll ranges and file display area based upon
  501.             // client area size.
  502.             SetupScroll(hWnd);
  503.             break;
  504.  
  505.         case WM_VSCROLL:
  506.             // React to the various vertical scroll related actions.
  507.             switch (wParam)
  508.             {
  509.                 case SB_TOP:
  510.                     nVscrollInc = -nVscrollPos;
  511.                     break;
  512.  
  513.                 case SB_BOTTOM:
  514.                     nVscrollInc = nVscrollMax - nVscrollPos;
  515.                     break;
  516.  
  517.                 case SB_LINEUP:
  518.                     nVscrollInc = -1;
  519.                     break;
  520.  
  521.                 case SB_LINEDOWN:
  522.                     nVscrollInc = 1;
  523.                     break;
  524.  
  525.                 case SB_PAGEUP:
  526.                     nVscrollInc = -max(1, yClient / yChar);
  527.                     break;
  528.  
  529.         case SB_PAGEDOWN:
  530.                     nVscrollInc = max(1, yClient / yChar);
  531.                     break;
  532.  
  533.                 case SB_THUMBPOSITION:
  534.                     nVscrollInc = LOWORD(lParam) - nVscrollPos;
  535.                     break;
  536.  
  537.                 case SB_THUMBTRACK:
  538.                     nVscrollInc = LOWORD(lParam) - nVscrollPos;
  539.                     break;
  540.  
  541.                 default:
  542.                     nVscrollInc = 0;
  543.             }
  544.  
  545.             nVscrollInc = max(-nVscrollPos,
  546.                   min(nVscrollInc, nVscrollMax - nVscrollPos));
  547.             if (nVscrollInc)
  548.             {
  549.                 nVscrollPos += nVscrollInc;
  550.                 ScrollWindow(hWnd, 0, -yChar * nVscrollInc, NULL, NULL);
  551.                 SetScrollPos(hWnd, SB_VERT, nVscrollPos, TRUE);
  552.                 UpdateWindow(hWnd);
  553.             }
  554.             break;
  555.  
  556.         case WM_HSCROLL:
  557.             // React to the various horizontal scroll related actions.
  558.             switch (wParam)
  559.             {
  560.                 case SB_LINEUP:
  561.                     nHscrollInc = -1;
  562.                     break;
  563.  
  564.                 case SB_LINEDOWN:
  565.                     nHscrollInc = 1;
  566.                     break;
  567.  
  568.                 case SB_PAGEUP:
  569.                     nHscrollInc = -8;
  570.                     break;
  571.  
  572.                 case SB_PAGEDOWN:
  573.                     nHscrollInc = 8;
  574.                     break;
  575.  
  576.                 case SB_THUMBPOSITION:
  577.                     nHscrollInc = LOWORD(lParam) - nHscrollPos;
  578.                     break;
  579.  
  580.         case SB_THUMBTRACK:
  581.                     nHscrollInc = LOWORD(lParam) - nHscrollPos;
  582.                     break;
  583.  
  584.                 default:
  585.                     nHscrollInc = 0;
  586.             }
  587.  
  588.             nHscrollInc = max(-nHscrollPos,
  589.                               min(nHscrollInc, nHscrollMax - nHscrollPos));
  590.             if (nHscrollInc)
  591.             {
  592.                 nHscrollPos += nHscrollInc;
  593.                 ScrollWindow(hWnd, -xChar * nHscrollInc, 0, NULL, NULL);
  594.                 SetScrollPos(hWnd, SB_HORZ, nHscrollPos, TRUE);
  595.                 UpdateWindow(hWnd);
  596.             }
  597.         break;
  598.  
  599.         case WM_KEYDOWN:
  600.             // Translate various keydown messages to appropriate horizontal
  601.             // and vertical scroll actions.
  602.             for (i = 0; i < NUMKEYS; i++)
  603.             {
  604.                 if (wParam == key2scroll[i].wVirtkey)
  605.                 {
  606.                     SendMessage(hWnd, key2scroll[i].iMessage,
  607.                                 key2scroll[i].wRequest, 0L);
  608.                     break;
  609.                 }
  610.             }
  611.             break;
  612.  
  613.         case WM_PAINT:
  614.         // Go paint the client area of the window with the appropriate
  615.             // part of the selected file.
  616.             MsgwndPaint(hWnd);
  617.             break;
  618.  
  619.         case WM_DESTROY:
  620.             // This is the end if we were closed by a DestroyWindow call.
  621.             CloseMsgwnd(hWnd);    // take any necessary wrapup action.
  622.             PostQuitMessage(0);   // this is the end...
  623.             break;
  624.  
  625.         case WM_QUERYENDSESSION:
  626.             // If we return TRUE we are saying it's ok with us to end the
  627.             // windows session.
  628.             CloseMsgwnd(hWnd);    // take any necessary wrapup action.
  629.             return((long) TRUE);  // we agree to end session.
  630.  
  631.     case WM_CLOSE:
  632.             // Tell windows to destroy our window.
  633.             DestroyWindow(hWnd);
  634.             break;
  635.  
  636.         default:
  637.             // Let windows handle all messages we choose to ignore.
  638.             return(DefWindowProc(hWnd, message, wParam, lParam));
  639.     }
  640.  
  641.     return(0L);
  642. }
  643.  
  644. //*******************************************************************
  645. // SetupScroll - setup scroll ranges
  646. //
  647. //   Setup the vertical and horizontal scroll ranges and positions
  648. //   of the applicatons main window based on:
  649. //
  650. //       numlines - The maximum number of lines to display.
  651. //       maxwidth - The maximum width of any line to display.
  652. //
  653. //   The resulting variables, nVscrollPos and nPageMaxLines, are used
  654. //   by the function MsgwndPaint to determine what part of the selected
  655. //   file to display in the window.
  656. //
  657. // paramaters:
  658. //             hWnd          - The callers window handle.
  659. //
  660. //*******************************************************************
  661. void SetupScroll(HWND hWnd)
  662. {
  663.     // numlines established during open
  664.     nVscrollMax = max(0, numlines - yClient / yChar);
  665.     nVscrollPos = min(nVscrollPos, nVscrollMax);
  666.  
  667.     nHscrollMax = max(0, maxwidth - xClient / xChar);
  668.     nHscrollPos = min(nHscrollPos, nHscrollMax);
  669.  
  670.     SetScrollRange (hWnd, SB_VERT, 0, nVscrollMax, FALSE);
  671.     SetScrollPos   (hWnd, SB_VERT, nVscrollPos, TRUE);
  672.  
  673.     SetScrollRange (hWnd, SB_HORZ, 0, nHscrollMax, FALSE);
  674.     SetScrollPos   (hWnd, SB_HORZ, nHscrollPos, TRUE);
  675.  
  676.     nPageMaxLines = min(numlines, yClient / yChar);
  677.  
  678.     rect.left = 0;
  679.     rect.top = 0;
  680.     rect.right = xClient;
  681.     rect.bottom = yClient;
  682.  
  683.     blanklen = rect.right / xChar + 1;
  684. }
  685.  
  686. //*******************************************************************
  687. // MsgwndPaint - paint the main window
  688. //
  689. // This function is responsible for redisplaying a portion of the saved
  690. // strings.  Which strings it displays depends on the current scroll
  691. // position.
  692. //
  693. // paramaters:
  694. //             hWnd          - The callers window handle
  695. //
  696. //*******************************************************************
  697. void MsgwndPaint(HWND hWnd)
  698. {
  699.     PAINTSTRUCT  ps;
  700.     HDC          hDC;
  701.     char         currec[256];
  702.     int          ypos;
  703.     LPSTR        lcp;
  704.     int          i;
  705.     int          ndone;
  706.  
  707.     // Get display context.
  708.     BeginPaint(hWnd, (LPPAINTSTRUCT) &ps);
  709.     hDC = ps.hdc;
  710.  
  711.     // Select fixed font.
  712.     SelectObject(hDC, hnewsfont);
  713.  
  714.     // Setup scroll ranges.
  715.     SetupScroll(hWnd);
  716.  
  717.     // See if we have any lines to show.
  718.     if (hwm_keep)
  719.       {
  720.         // Y position of bottom line in client area.
  721.         ypos = rect.bottom - yChar;
  722.  
  723.         // Index into keep list of first line (from bottom) to show.
  724.         i = nVscrollMax - nVscrollPos;
  725.  
  726.         ndone = 1;
  727.         while (ndone)
  728.           {
  729.             lcp = GlobalLock(hkeep[i]);
  730.             if (lcp)
  731.               {
  732.                 // We must fill line with blanks to width of window
  733.         // or else some previous longet text might show through.
  734.                 _fstrcpy(currec, blanks);
  735.  
  736.                 // Line to show.
  737.                 _fstrncpy(currec, lcp, _fstrlen(lcp));
  738.  
  739.                 // Send to window.
  740.                 TextOut(hDC,
  741.                         xChar * (-nHscrollPos + 0),
  742.                         ypos,
  743.                         currec,
  744.                         blanklen);
  745.  
  746.                 // New Y is one character height higher.
  747.                 ypos -= yChar;
  748.  
  749.                 GlobalUnlock(hkeep[i]);
  750.           }
  751.  
  752.             // Index of next keep string to show.
  753.             i++;
  754.  
  755.             // No use drawing lines beyond top of client area.
  756.             // They would not show, so don't wast the energy.
  757.             if (ypos < -yChar)
  758.               ndone = 0;
  759.  
  760.             // Have we done all of the lines?
  761.             if (i > (hwm_keep - 1))
  762.               ndone = 0;
  763.           }
  764.       }
  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.     int   i;
  796.     int   lstr;
  797.     LPSTR lcp;
  798.     RECT  trect;
  799.  
  800.     // If our keep stack is full free oldest member.
  801.     if (hwm_keep >= MAX_KEEP)
  802.       GlobalFree(hkeep[hwm_keep]);
  803.  
  804.     // Move all handles to make room for new one.
  805.     for (i = hwm_keep; i > 0; i--)
  806.       hkeep[i] = hkeep[i - 1];
  807.  
  808.     // If keep stack not yet full add one to high watter mark.
  809.     if (hwm_keep < MAX_KEEP)
  810.       hwm_keep++;
  811.  
  812.     // Make sure we know how many saved lines there are.
  813.     numlines = hwm_keep;
  814.  
  815.     // Length of new string.
  816.     lstr = strlen(str);
  817.  
  818.     // Is it longer than any previous string.
  819.     if (lstr > maxwidth)
  820.       maxwidth = lstr;
  821.  
  822.     // Get storage to save it.
  823.     hkeep[0] = GlobalAlloc(GMEM_MOVEABLE, (DWORD) (lstr + 1));
  824.     if (hkeep[0])
  825.       {
  826.         // Lock it down to get address.
  827.         lcp = GlobalLock(hkeep[0]);
  828.         if (lcp)
  829.       {
  830.             // Save string.
  831.             _fstrcpy(lcp, str);
  832.             GlobalUnlock(hkeep[0]);
  833.           }
  834.       }
  835.  
  836.     // See what we have to do to display it efficently.
  837.     if (!(nVscrollMax - nVscrollPos))
  838.       {
  839.         // We are scrolled to bottom of list.
  840.  
  841.         // Scroll contents of window up one character hehght.
  842.         ScrollWindow(hWnd, 0, -yChar, &rect, &rect);
  843.  
  844.         // Set scroll position to last line
  845.         nVscrollPos = numlines - yChar / yClient;
  846.  
  847.         // Tell windows to repaint only the bottom line of window.
  848.         GetClientRect(hWnd, &trect);
  849.         trect.top = trect.bottom - yChar;
  850.         InvalidateRect(hWnd, &trect, TRUE);
  851.       }
  852.     else
  853.       {
  854.         // We are not scrolled to bottom of list.
  855.  
  856.         // Set scroll position to last line.
  857.         nVscrollPos = numlines - yChar / yClient;
  858.  
  859.     // Tell windows to repaint the entire window.
  860.     InvalidateRect(hWnd, NULL, TRUE);
  861.       }
  862. }
  863.  
  864. //*******************************************************************
  865. // ClearKeep - free all saved strings
  866. //*******************************************************************
  867. void ClearKeep()
  868.   {
  869.     int i;
  870.  
  871.     for (i = 0; i < hwm_keep; i++)
  872.       {
  873.     GlobalFree(hkeep[i]);
  874.     hkeep[i] = 0;
  875.       }
  876.  
  877.     // Reset counters.
  878.     numlines = hwm_keep = 0;
  879.   }
  880.  
  881. //*******************************************************************
  882.  
  883. //*******************************************************************
  884. // DDEExecuteCommand - execute a command send by client
  885. //
  886. // paramaters:
  887. //             lpCommand  - command from client to be executed.
  888. //
  889. //             commands supported:
  890. //
  891. //               print   - print a line in window.
  892. //                         [print ("line to print")]
  893. //
  894. //               clear   - clear the window.
  895. //                         [clear]
  896. //
  897. // returns:
  898. //             1 - if command successful.
  899. //             0 - if not successful.
  900. //
  901. //*******************************************************************
  902. int DDEExecuteCommand(LPSTR lpCommand)
  903. {
  904.     int   nRc;
  905.     LPSTR lcp;
  906.     LPSTR lcp1;
  907.     LPSTR lcp2;
  908.     char  buf[256];
  909.  
  910.     // Init return code.
  911.     nRc = 0;
  912.  
  913.     // Find start of command.
  914.     lcp = _fstrchr(lpCommand, '[');
  915.     if (lcp)
  916.     {
  917.         // See what the command is.
  918.         lcp++;
  919.  
  920.         if (!_fstrncmp(lcp, "print", 5)) // Print a line to window.
  921.         {
  922.             // Find string between quotes (does not support embeded quotes)
  923.             lcp1 = _fstrchr(lcp, '\"');
  924.             if (lcp1)
  925.             {
  926.                 lcp1++;
  927.                 lcp2 = _fstrchr(lcp1, '\"');
  928.         if (lcp2)
  929.                 {
  930.                     *lcp2 = 0;
  931.                     _fstrcpy(buf, lcp1);
  932.  
  933.                     // Print the string to window.
  934.                     ScrollPrint(hWndMain, buf);
  935.  
  936.                     // Increment line count.
  937.                     plines++;
  938.  
  939.             nRc = 1;
  940.                 }
  941.             }
  942.         }
  943.  
  944.         else if (!_fstrncmp(lcp, "clear", 5))  // Clear window.
  945.     {
  946.             // Delete saved strings.
  947.             ClearKeep();
  948.  
  949.             // Clear the window.
  950.             InvalidateRect(hWndMain, NULL, TRUE);
  951.             UpdateWindow(hWndMain);
  952.  
  953.             // Reset line count.
  954.             plines = 0;
  955.  
  956.         nRc = 1;
  957.         }
  958.     }
  959.  
  960.     return(nRc);
  961. }
  962.  
  963. //*******************************************************************
  964. // DDEData - get data requested by client
  965. //
  966. // paramaters:
  967. //             szItem     - name of data item requested.
  968. //
  969. //             items supported:
  970. //
  971. //               lines   - the number lines printed to window.
  972. //
  973. // returns:
  974. //             Size of data item.
  975. //               or
  976. //             Zero if no data item.
  977. //
  978. //*******************************************************************
  979. int DDEData(char *szItem, HANDLE *hData)
  980. {
  981.     int   nRc;
  982.     int   len;
  983.     char  buf[30];
  984.     LPSTR lpData;
  985.  
  986.     // Init return code.
  987.     nRc = 0;
  988.  
  989.     // See what data item is being requested.
  990.     if (!stricmp(szItem, "lines"))
  991.     {
  992.         // Format response.
  993.         sprintf(buf, "Lines = %d", plines);
  994.  
  995.         // Get length of response.
  996.     len = strlen(buf);
  997.  
  998.         // Get memory for response.
  999.         *hData = GlobalAlloc(GMEM_MOVEABLE, (DWORD) (len + 1));
  1000.         if (*hData)
  1001.         {
  1002.             lpData = GlobalLock(*hData);
  1003.             if (lpData)
  1004.             {
  1005.                 // Copy response to memory.
  1006.                 _fstrcpy(lpData, buf);
  1007.         GlobalUnlock(*hData);
  1008.  
  1009.                 // Set return code to length of data returned.
  1010.                 nRc = len;
  1011.             }
  1012.             else
  1013.         {
  1014.                 GlobalFree(*hData);
  1015.                 *hData = 0;
  1016.             }
  1017.         }
  1018.     }
  1019.  
  1020.     return(nRc);
  1021. }
  1022.  
  1023. //*******************************************************************
  1024.