home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / win_lrn / tty / tty.c next >
Encoding:
C/C++ Source or Header  |  1989-03-15  |  15.9 KB  |  598 lines

  1. /*  TTY.c
  2.     a very simple sample terminal application. It demonstrates
  3.     the basics in the use of the Windows Comm functions. It also
  4.     shows the basic structure for a terminal program.
  5.     Currently, there are a number of things that are hard coded,
  6.     which could be made settable in a dialog box. These can be
  7.     found in the Terminal data section below. They are things like
  8.     the background and text colors, the background brush, and the
  9.     font to be used. Also, the baud rate and other communication
  10.     settings are hard coded. You can experiment with different
  11.     settings, or change them just to match your available serial
  12.     connection.
  13.  
  14.     Microsoft makes no claims to the correctness or operation of
  15.     this code. It is provided for example and learning purposes
  16.     only.
  17.  
  18.     Copyright (c) Microsoft 1985,1986,1987,1988,1989 */
  19.  
  20. #include "windows.h"
  21. #include "TTY.h"
  22.  
  23. char szAppName[10];
  24. char szAbout[10];
  25. char szMessage[15];
  26. int MessageLength;
  27.  
  28. /* Terminal data */
  29. typedef char cpt[2];        // point array of char sized values
  30.  
  31. #define cpX 0
  32. #define cpY 1
  33.  
  34. #define PortSetting  "com1"
  35. #define CommSettings "com1:96,n,8,1"
  36. #define BufMax 160
  37. HWND hTTYWnd;
  38. char MsgBuff[BufMax + 1];   // Buffer to hold incoming characters
  39. char sScrBuff[25][81];        // Array of characters on TTY
  40. char cLastLine;         // Index of last line on TTY in the array
  41. char cCurrPos;            // Current TTY output position
  42. BOOL bConnected;        // Flag to indicate if connected
  43. int TTYCharWidth, TTYCharHeight;    // width and height of TTY font chars
  44. DCB CommDCB;            // DCB for comm port
  45. COMSTAT CommStat;        // COMSTAT info buffer for comm port
  46.  
  47. DWORD TTYbkRGB = RGB(0,0,0);        // background color
  48. DWORD TTYtextRGB = RGB(255,255,255);    // text color
  49. #define TTY_BRUSH BLACK_BRUSH        // background brush
  50. #define TTY_FONT DEVICEDEFAULT_FONT    // font used for display
  51.  
  52. char sTemp[256];
  53. HFONT hOldFont;
  54.  
  55. static HANDLE hInst;
  56. FARPROC lpprocAbout;
  57.  
  58. long FAR PASCAL TTYWndProc(HWND, unsigned, WORD, LONG);
  59.  
  60. BOOL FAR PASCAL About( hDlg, message, wParam, lParam )
  61. HWND hDlg;
  62. unsigned message;
  63. WORD wParam;
  64. LONG lParam;
  65. {
  66.     if (message == WM_COMMAND
  67.     || message == WM_LBUTTONDOWN) {
  68.         EndDialog( hDlg, TRUE );
  69.         return TRUE;
  70.         }
  71.     else if (message == WM_INITDIALOG)
  72.         return TRUE;
  73.     else return FALSE;
  74. }
  75.  
  76. SetupTTYDC(HWND hWnd, HDC hDC)
  77. {
  78.     RECT rClRect;
  79.  
  80.     hOldFont = SelectObject(hDC,GetStockObject(TTY_FONT));
  81.     GetClientRect(hWnd,&rClRect);
  82.     SetViewportOrg(hDC,0,rClRect.bottom-TTYCharHeight*25);
  83.     SetTextColor(hDC,TTYtextRGB);
  84.     SetBkColor(hDC,TTYbkRGB);
  85.     SetBkMode(hDC,OPAQUE);
  86.  
  87. }
  88.  
  89. ResetTTYDC(HWND hWnd, HDC hDC)
  90. {
  91.     SelectObject(hDC,hOldFont);
  92. }
  93.  
  94. char *GetTTYLine(char ndx)        // get ptr to text for give line
  95. {
  96.     char pos;
  97.  
  98.     pos = cLastLine + ndx + 1;
  99.     pos = pos > 24 ? (pos % 24)-1 : pos;
  100.     return(sScrBuff[pos]);
  101. }
  102.  
  103. POINT TTYScrPos(char X, char Y)     // get window pos from TTY pos
  104. {
  105.     POINT ScrPos;
  106.  
  107.     ScrPos.x = X * TTYCharWidth;
  108.     ScrPos.y = Y * TTYCharHeight;
  109.     return(ScrPos);
  110. }
  111.  
  112. // process incoming text to tty window - simulate tty actions
  113. void putTTY(HWND hWnd, HDC hDC, WORD wParam, LPSTR lParam)
  114. {
  115.     short i,j;
  116.     POINT ptTTYPos;
  117.     char *sBuffer;
  118.     char len = 0;
  119.     RECT rClRect;
  120.     char *psLine;
  121.     short iLinesOut = 0;
  122.  
  123.     sBuffer = &sScrBuff[cLastLine][cCurrPos];
  124.  
  125.     for(i=0;i<wParam;i++){
  126.     switch(lParam[i]) {
  127.  
  128.     case '\r': // return
  129.         // move to the start of the line
  130.         cCurrPos = 0;
  131.         len = 0;
  132.  
  133.         break;
  134.  
  135.     case '\b': // backspace
  136.  
  137.         // (ok, so most of this should be a function since it is
  138.         //      repeated later)
  139.         // Note: it is easier to go ahead and display the text
  140.         //    up to this point for things such as backspace. This
  141.         //    will apply to other things, like arrow keys, tabs, etc.
  142.  
  143.         // scroll screen by number of lines received
  144.         if(iLinesOut > 0) {
  145.         // scroll iLinesOut lines
  146.         ScrollWindow(hWnd,0,-(TTYCharHeight * iLinesOut),NULL,NULL);
  147.         rClRect.top = TTYCharHeight * (24 - iLinesOut);
  148.         rClRect.bottom = TTYCharHeight*25;
  149.         rClRect.left = 0;
  150.         rClRect.right = TTYCharWidth * 80;
  151.         FillRect(hDC,&rClRect,GetStockObject(TTY_BRUSH));
  152.  
  153.         }
  154.  
  155.         // display lines in scrolled area previous to current line
  156.         for(j = 1;j<=iLinesOut;j++) {
  157.         // TextOut line cLastLine - j;
  158.         psLine = GetTTYLine(24 - j);
  159.         ptTTYPos = TTYScrPos(0,24 - j);
  160.         TextOut(hDC,
  161.             ptTTYPos.x,
  162.             ptTTYPos.y,
  163.             psLine,
  164.             strlen(psLine));
  165.  
  166.         }
  167.         iLinesOut = 0;
  168.  
  169.         if(len > 0){
  170.         // display current line
  171.         ptTTYPos = TTYScrPos(cCurrPos,24);
  172.         TextOut(hDC,
  173.             ptTTYPos.x,
  174.             ptTTYPos.y,
  175.             sBuffer,
  176.             len);
  177.         cCurrPos += len;
  178.         }
  179.         len = 0;
  180.  
  181.         // move back one space
  182.         if(cCurrPos > 0) {
  183.         --cCurrPos;
  184.         ptTTYPos = TTYScrPos(cCurrPos,24);
  185.         TextOut(hDC,
  186.             ptTTYPos.x,
  187.             ptTTYPos.y,
  188.             " ",
  189.             1);
  190.         }
  191.         break;
  192.  
  193.     case '\n': // new line
  194.  
  195.         // "scroll" the window
  196.         ++iLinesOut; // increment lines to scroll
  197.         ++cLastLine;
  198.         if(cLastLine > 24) cLastLine = 0;
  199.  
  200.         // clear the new line
  201.         sBuffer = &sScrBuff[cLastLine][0];
  202.         for(j=0;j<80;j++) sBuffer[j] = '\0';
  203.         len = 0;
  204.  
  205.         break;
  206.  
  207.     default:
  208.         //add char to buffer
  209.         if(cCurrPos < 80){
  210.         sBuffer[len] = lParam[i];
  211.         ++len;
  212.         }
  213.         break;
  214.     }
  215.     }
  216.  
  217.     // scroll screen by number of lines received
  218.     if(iLinesOut > 0) {
  219.     // scroll iLinesOut lines
  220.     ScrollWindow(hWnd,0,-(TTYCharHeight * iLinesOut),NULL,NULL);
  221.     rClRect.top = TTYCharHeight * (24 - iLinesOut);
  222.     rClRect.bottom = TTYCharHeight*25;
  223.     rClRect.left = 0;
  224.     rClRect.right = TTYCharWidth * 80;
  225.     FillRect(hDC,&rClRect,GetStockObject(TTY_BRUSH));
  226.  
  227.     }
  228.  
  229.     // display lines in scrolled area previous to current line
  230.     for(j = 1;j<=iLinesOut;j++) {
  231.     // TextOut line cLastLine - j;
  232.     psLine = GetTTYLine(24 - j);
  233.     ptTTYPos = TTYScrPos(0,24 - j);
  234.     TextOut(hDC,
  235.         ptTTYPos.x,
  236.         ptTTYPos.y,
  237.         psLine,
  238.         strlen(psLine));
  239.  
  240.     }
  241.  
  242.     if(len > 0){
  243.     // display current line
  244.     ptTTYPos = TTYScrPos(cCurrPos,24);
  245.     TextOut(hDC,
  246.         ptTTYPos.x,
  247.         ptTTYPos.y,
  248.         sBuffer,
  249.         len);
  250.     cCurrPos += len;
  251.     }
  252. }
  253.  
  254.  
  255. void TTYPaint(HDC hDC )    // repaint the text in the tty
  256. {
  257.     char *psLine;
  258.     POINT ptTTYPos;
  259.     register int i;
  260.  
  261.     for(i=0;i<25;i++){
  262.     psLine = GetTTYLine(i);
  263.     ptTTYPos = TTYScrPos(0,i);
  264.     TextOut(hDC,
  265.         ptTTYPos.x,
  266.         ptTTYPos.y,
  267.         psLine,
  268.         strlen(psLine));
  269.     }
  270. }
  271.  
  272.  
  273. /* Procedure called when the application is loaded for the first time */
  274. BOOL TTYInit( hInstance )
  275. HANDLE hInstance;
  276. {
  277.     PWNDCLASS    pTTYClass;
  278.  
  279.     /* Load strings from resource */
  280.     LoadString( hInstance, IDSNAME, (LPSTR)szAppName, 10 );
  281.     LoadString( hInstance, IDSABOUT, (LPSTR)szAbout, 10 );
  282.     MessageLength = LoadString( hInstance, IDSTITLE, (LPSTR)szMessage, 15 );
  283.  
  284.     pTTYClass = (PWNDCLASS)LocalAlloc( LPTR, sizeof(WNDCLASS) );
  285.  
  286.     pTTYClass->hCursor          = LoadCursor( NULL, IDC_ARROW );
  287.     pTTYClass->hIcon          = LoadIcon( hInstance, MAKEINTRESOURCE(TTYICON) );
  288.     pTTYClass->lpszMenuName   = (LPSTR)"TTYMENU";
  289.     pTTYClass->lpszClassName  = (LPSTR)szAppName;
  290.     pTTYClass->hbrBackground  = (HBRUSH)GetStockObject( TTY_BRUSH );
  291.     pTTYClass->hInstance      = hInstance;
  292.     pTTYClass->style          = CS_HREDRAW | CS_VREDRAW | CS_OWNDC
  293.                 | CS_BYTEALIGNCLIENT;
  294.     pTTYClass->lpfnWndProc    = TTYWndProc;
  295.  
  296.     if (!RegisterClass( (LPWNDCLASS)pTTYClass ) )
  297.         /* Initialization failed.
  298.          * Windows will automatically deallocate all allocated memory.
  299.          */
  300.         return FALSE;
  301.  
  302.     LocalFree( (HANDLE)pTTYClass );
  303.     return TRUE;        /* Initialization succeeded */
  304. }
  305.  
  306.  
  307. int PASCAL WinMain( hInstance, hPrevInstance, lpszCmdLine, cmdShow )
  308. HANDLE hInstance, hPrevInstance;
  309. LPSTR lpszCmdLine;
  310. int cmdShow;
  311. {
  312.     MSG   msg;
  313.     HWND  hWnd;
  314.     HMENU hMenu;
  315.     RECT rClRect, rWndRect;
  316.     short iXExtra,iYExtra;
  317.     short iNumRead,iError;
  318.  
  319.     if (!hPrevInstance) {
  320.         /* Call initialization procedure if this is the first instance */
  321.     if (!TTYInit( hInstance ))
  322.             return FALSE;
  323.         }
  324.     else {
  325.         /* Copy data from previous instance */
  326.         GetInstanceData( hPrevInstance, (PSTR)szAppName, 10 );
  327.         GetInstanceData( hPrevInstance, (PSTR)szAbout, 10 );
  328.         GetInstanceData( hPrevInstance, (PSTR)szMessage, 15 );
  329.         GetInstanceData( hPrevInstance, (PSTR)&MessageLength, sizeof(int) );
  330.         }
  331.  
  332.     hWnd = CreateWindow((LPSTR)szAppName,
  333.                         (LPSTR)szMessage,
  334.                         WS_TILEDWINDOW,
  335.             CW_USEDEFAULT,      /*  x - ignored for tiled windows */
  336.             CW_USEDEFAULT,      /*  y - ignored for tiled windows */
  337.             CW_USEDEFAULT,      /* cx - ignored for tiled windows */
  338.             CW_USEDEFAULT,      /* cy - ignored for tiled windows */
  339.                         (HWND)NULL,        /* no parent */
  340.                         (HMENU)NULL,       /* use class menu */
  341.                         (HANDLE)hInstance, /* handle to window instance */
  342.                         (LPSTR)NULL        /* no params to pass on */
  343.                         );
  344.  
  345.     /* Save instance handle for DialogBox */
  346.     hInst = hInstance;
  347.  
  348.     /* Bind callback function with module instance */
  349.     lpprocAbout = MakeProcInstance( (FARPROC)About, hInstance );
  350.  
  351.     /* Insert "About..." into system menu */
  352.     hMenu = GetSystemMenu(hWnd, FALSE);
  353.     ChangeMenu(hMenu, 0, NULL, 999, MF_APPEND | MF_SEPARATOR);
  354.     ChangeMenu(hMenu, 0, (LPSTR)szAbout, IDSABOUT, MF_APPEND | MF_STRING);
  355.  
  356.     /* Make window visible according to the way the app is activated */
  357.     GetWindowRect(hWnd,&rWndRect);
  358.     GetClientRect(hWnd,&rClRect);
  359.     iXExtra = (rWndRect.right-rWndRect.left)-(rClRect.right-rClRect.left);
  360.     iYExtra = (rWndRect.bottom-rWndRect.top)-(rClRect.bottom-rClRect.top);
  361.     SetWindowPos(hWnd,NULL,0,0,
  362.         TTYCharWidth*80 + iXExtra,
  363.         TTYCharHeight*25 + iYExtra,
  364.         SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER);
  365.     ShowWindow( hWnd, cmdShow );
  366.     UpdateWindow( hWnd );
  367.  
  368.     /* Polling messages from event queue */
  369.     while(TRUE){
  370.     // if messages pending, process them
  371.     if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)){
  372.         if(msg.message == WM_QUIT) break;
  373.         TranslateMessage((LPMSG)&msg);
  374.         DispatchMessage((LPMSG)&msg);
  375.     } else {
  376.         // otherwise check the comm port and process any available
  377.         // characters. you could also use a timer instead, and have
  378.         // the timer case of the wndproc check the port.
  379.         if(bConnected){
  380.         // get the CommStat record and clear any error condition
  381.         GetCommError(CommDCB.Id,&CommStat);
  382.         // get the number of characters available
  383.         iNumRead = CommStat.cbInQue;
  384.         if(iNumRead > 0) {
  385.             // get the number of characters rounded to the buffer size
  386.             if(iNumRead > BufMax) iNumRead = BufMax;
  387.             iNumRead = ReadComm(CommDCB.Id,MsgBuff,
  388.                     iNumRead);
  389.             // check for errors
  390.             if(iNumRead < 0) {
  391.             iNumRead = abs(iNumRead);
  392.             iError = GetCommError(CommDCB.Id,&CommStat);
  393.             // clear the event mask
  394.             GetCommEventMask(CommDCB.Id,0xFFFF);
  395.             itoa(iError,sTemp,10);
  396.             // display what the error was
  397.             switch(iError){
  398.             case CE_BREAK:
  399.                 MessageBox(GetFocus(), sTemp, "CE_BREAK!",MB_OK);
  400.                 break;
  401.             case CE_CTSTO:
  402.                 MessageBox(GetFocus(), sTemp, "CE_CTSTO!",MB_OK);
  403.                 break;
  404.             case CE_DNS:
  405.                 MessageBox(GetFocus(), sTemp, "CE_DNS!",MB_OK);
  406.                 break;
  407.             case CE_DSRTO:
  408.                 MessageBox(GetFocus(), sTemp, "CE_DSTRO!",MB_OK);
  409.                 break;
  410.             case CE_FRAME:
  411.                 MessageBox(GetFocus(), sTemp, "CE_FRAME!",MB_OK);
  412.                 break;
  413.             case CE_IOE:
  414.                 MessageBox(GetFocus(), sTemp, "CE_IOE!",MB_OK);
  415.                 break;
  416.             case CE_MODE:
  417.                 MessageBox(GetFocus(), sTemp, "CE_MODE!",MB_OK);
  418.                 break;
  419.             case CE_OOP:
  420.                 MessageBox(GetFocus(), sTemp, "CE_OOP!",MB_OK);
  421.                 break;
  422.             case CE_OVERRUN:
  423.                 MessageBox(GetFocus(), sTemp, "CE_OVERRUN!",MB_OK);
  424.                 break;
  425.             case CE_PTO:
  426.                 MessageBox(GetFocus(), sTemp, "CE_PTO!",MB_OK);
  427.                 break;
  428.             case CE_RLSDTO:
  429.                 MessageBox(GetFocus(), sTemp, "CE_RLSDTO!",MB_OK);
  430.                 break;
  431.             case CE_RXOVER:
  432.                 MessageBox(GetFocus(), sTemp, "CE_RXOVER!",MB_OK);
  433.                 break;
  434.             case CE_RXPARITY:
  435.                 MessageBox(GetFocus(), sTemp, "CE_RXPARITY!",MB_OK);
  436.                 break;
  437.             case CE_TXFULL:
  438.                 MessageBox(GetFocus(), sTemp, "CE_TXFULL!",MB_OK);
  439.                 break;
  440.             }
  441.             }
  442.             // send the characters to the tty window for processing
  443.             SendMessage(hTTYWnd,COMM_CHARS,
  444.                 iNumRead,(LONG)(LPSTR)MsgBuff);
  445.         }
  446.  
  447.  
  448.         }
  449.     }
  450.     }
  451.  
  452.     return (int)msg.wParam;
  453. }
  454.  
  455.  
  456. /* Procedures which make up the window class. */
  457. long FAR PASCAL TTYWndProc( hWnd, message, wParam, lParam )
  458. HWND hWnd;
  459. unsigned message;
  460. WORD wParam;
  461. LONG lParam;
  462. {
  463.     PAINTSTRUCT ps;
  464.     register int i,j;
  465.     TEXTMETRIC Metrics;
  466.     HDC hDC;
  467.  
  468.     switch (message)
  469.     {
  470.     case WM_SYSCOMMAND:
  471.         switch (wParam)
  472.         {
  473.         case IDSABOUT:
  474.             DialogBox( hInst, MAKEINTRESOURCE(ABOUTBOX), hWnd, lpprocAbout );
  475.             break;
  476.         default:
  477.             return DefWindowProc( hWnd, message, wParam, lParam );
  478.         }
  479.         break;
  480.  
  481.     case WM_DESTROY:
  482.         PostQuitMessage( 0 );
  483.         break;
  484.  
  485.     case WM_PAINT:  // repaint the tty window
  486.     BeginPaint( hWnd, (LPPAINTSTRUCT)&ps );
  487.     hDC = ps.hdc;
  488.     SetupTTYDC(hWnd,hDC);
  489.  
  490.     TTYPaint( hDC );
  491.  
  492.     ResetTTYDC(hWnd,hDC);
  493.         EndPaint( hWnd, (LPPAINTSTRUCT)&ps );
  494.         break;
  495.  
  496.     case WM_CREATE:  // initialize the comm and tty parameters
  497.     /* initialize screen buffer to nulls */
  498.     for(i=0;i<25;i++)
  499.         for(j=0;j<81;j++)
  500.         sScrBuff[i][j] = '\0';
  501.     /* initialize line and position to zero */
  502.     cLastLine = 0;
  503.     hDC = GetDC(hWnd);
  504.     SetupTTYDC(hWnd,hDC);
  505.     GetTextMetrics(hDC,&Metrics);
  506.     ResetTTYDC(hWnd,hDC);
  507.     ReleaseDC(hWnd,hDC);
  508.     cCurrPos = 0;
  509.     TTYCharWidth = Metrics.tmMaxCharWidth;
  510.     TTYCharHeight = Metrics.tmHeight + Metrics.tmExternalLeading;
  511.     bConnected = FALSE;
  512.     hTTYWnd = hWnd;
  513.  
  514.     break;
  515.  
  516.     case WM_CLOSE:
  517.     // disconnect if still connected
  518.     if(bConnected)SendMessage(hWnd,WM_COMMAND,TTYCONNECT,0L);
  519.     // go ahead and close down
  520.     DefWindowProc( hWnd, message, wParam, lParam );
  521.     break;
  522.  
  523.     case WM_COMMAND:
  524.     switch(wParam){
  525.  
  526.         case IDSABOUT:
  527.             DialogBox( hInst, MAKEINTRESOURCE(ABOUTBOX), hWnd, lpprocAbout );
  528.             break;
  529.  
  530.     case TTYEXIT:
  531.         PostMessage(hWnd,WM_CLOSE,0,0L);
  532.         break;
  533.  
  534.     case TTYCONNECT:
  535.         // connect to port if not already connected
  536.         if(!bConnected){
  537.         if(OpenComm(PortSetting,1024,128)) break;
  538.         if(BuildCommDCB(CommSettings,&CommDCB)) break;
  539.  
  540.         FlushComm(CommDCB.Id,0);
  541.         FlushComm(CommDCB.Id,1);
  542.  
  543.         CommDCB.fInX = TRUE;
  544.         CommDCB.fOutX = FALSE;
  545.         CommDCB.XonChar = 0x11;
  546.         CommDCB.XoffChar = 0x13;
  547.         CommDCB.XonLim = 50;
  548.         CommDCB.XoffLim = 500;
  549.  
  550.         if(SetCommState(&CommDCB))break;
  551.         bConnected = TRUE;
  552.         MessageBox(hWnd,"Connection was successful.","",MB_OK);
  553.         }else{
  554.         // otherwise disconnect
  555.         FlushComm(CommDCB.Id,0);
  556.         FlushComm(CommDCB.Id,1);
  557.         CloseComm(CommDCB.Id);
  558.         MessageBox(hWnd,"Connection closed.","",MB_OK);
  559.         bConnected = FALSE;
  560.         }
  561.         break;
  562.     case TTYSETTINGS:
  563.         // settings dialog
  564.         i=1;    // this does nothing right now
  565.         break;
  566.     }
  567.     break;
  568.  
  569.     case WM_CHAR:
  570.     if(!bConnected) break;
  571.     i = GetCommError(CommDCB.Id,&CommStat);
  572.             if(i != 0) {
  573.             itoa(i,sTemp,10);
  574.             MessageBox(GetFocus(), sTemp, "Comm Read Error!",MB_OK);
  575.             }
  576.  
  577.     WriteComm(CommDCB.Id,&wParam,1);
  578.     break;
  579.  
  580.     case COMM_CHARS:
  581.     if(wParam > 0) {
  582.         hDC = GetDC(hWnd);
  583.         SetupTTYDC(hWnd,hDC);
  584.  
  585.         putTTY(hWnd,hDC,wParam,(LPSTR)lParam);
  586.  
  587.         ResetTTYDC(hWnd,hDC);
  588.         ReleaseDC(hWnd,hDC);
  589.     }
  590.     break;
  591.  
  592.     default:
  593.         return DefWindowProc( hWnd, message, wParam, lParam );
  594.         break;
  595.     }
  596.     return(0L);
  597. }
  598.