/***************************************************************************** Stdio.c Main Program file. This file contains all the code to provide basic text communication for another windows application. This programs operation is described in winpipe.wri. *****************************************************************************/ #include #include #include "winpipe.h" #include "Stdio.h" /* circular difference , First, Last, Count */ #define CIRDIF(F, L, C) (L >= F) ? (L - F): (C - (F - L)) #define MAX_ROWS 50 /* upto 50 rows of text on window */ #define MAX_COLS 100 /* up to 100 characters per row */ #define TAB_SIZE 8 /* Tab expansion size */ #define BUFFER_SIZE 2048 /* Buffer size, same as default pipe size */ FILE *logfile; /* "redirection" file */ char ScrBuf[MAX_ROWS][MAX_COLS];/* screen buffer */ char szFname[]="\\stdio.log"; /* default Log file name */ char *szAppName = "stdio"; /* Application name */ char *szPosition = "Pos"; /* Position entry in win.ini */ char *szError = "Error"; /* String for error */ static int FirstRow=0; /* first entry into circular buffer */ static int LastRow=0; /* last entry into circular buffer */ static int CurrentCol=0; /* Current row being worked on */ static int WinRow=0; /* reletive Windows row */ static int NumRows; /* Number of rows avaialable */ static int CharHeight; /* height of a character */ static int CharWidth; /* average Width of a character */ RECT rect; /* Window rectangle */ HANDLE hBrush; /* Generic brush to paint window with */ HANDLE hInstance; /* This programs instance */ HANDLE hMainWnd; /* This programs window */ static HDC ScrhDC; /* internal copy of device context */ /* Quick'n easy dialog routine */ BOOL PopupDLG( hParentWnd, lpszTemplate, lpfnDlgProc ) HWND hParentWnd; LPSTR lpszTemplate; FARPROC lpfnDlgProc; { BOOL bResult; FARPROC lpProc; HANDLE hParentInst; hParentInst = GetWindowWord(hParentWnd,GWW_HINSTANCE); lpProc = MakeProcInstance( lpfnDlgProc, hParentInst); bResult = DialogBox( hParentInst, lpszTemplate, hParentWnd, lpProc ); FreeProcInstance( lpProc ); return( bResult ); } /* Aboutbox proc */ BOOL FAR PASCAL About(hDlg, message, wParam, lParam) /* About box */ HWND hDlg; unsigned message; WORD wParam; LONG lParam; { switch (message) { case WM_INITDIALOG: return (TRUE); case WM_COMMAND: switch(wParam){ case IDOK: EndDialog(hDlg, TRUE); break; case IDCANCEL: EndDialog(hDlg, TRUE); break; default: break; } } return (FALSE); } /* Draw single line */ UpdateLine() { TextOut(ScrhDC, 0, CharHeight * WinRow, (LPSTR) ScrBuf[LastRow], CurrentCol); } /* Redraw whole window */ void RepaintScr() { int i, y, numrows; int len = CurrentCol; int row = LastRow; numrows = CIRDIF(FirstRow, LastRow, MAX_ROWS); /* number of displayable lines */ WinRow = (NumRows <= numrows) ? (NumRows-1) : numrows; /* starting row */ y = WinRow * CharHeight; /* Last line in window */ FillRect(ScrhDC, (LPRECT) &rect, hBrush); /* Clear window */ for(i=WinRow; i >= 0; i--){ /* count down to last displayable */ TextOut(ScrhDC, 0, y, (LPSTR)ScrBuf[row], lstrlen((LPSTR)ScrBuf[row])); y -= CharHeight; row = (--row < 0) ? (MAX_ROWS -1) : row; } } /* Point to next row */ void IncRow() { int difference; ScrBuf[LastRow][CurrentCol] = (char) 0; /* make a Z string */ if(logfile){ fputs(ScrBuf[LastRow], logfile); /* string */ fputc('\n', logfile); /* plus new line */ } UpdateLine(); CurrentCol=0; LastRow++; LastRow = (LastRow >= MAX_ROWS) ? 0 : LastRow; if(FirstRow == LastRow){ FirstRow ++; FirstRow = (FirstRow >= MAX_ROWS) ? 0 : FirstRow; } WinRow++; WinRow = (WinRow >= NumRows) ? (NumRows-1) : WinRow; ScrBuf[LastRow][CurrentCol] = 0; difference = CIRDIF(FirstRow, LastRow, MAX_ROWS); if(NumRows <= difference) RepaintScr(); } /* Interpret and optionally add character to window buffer */ void AddChar(int c) { int i; RECT rCell; DWORD dwStrSpec; switch(c){ case 9: /* Tab */ if((CurrentCol + TAB_SIZE) >= MAX_COLS) DrawChar('\n'); for(i=0; i < TAB_SIZE; i++) ScrBuf[LastRow][CurrentCol++] = ' '; break; case 10: /* Line feed */ IncRow(); break; case 11: /* Vertical tab */ IncRow(); break; case 12: /* Form feed (ignore) */ break; case 13: /* enter key */ CurrentCol=0; break; case 8: /* Back Space */ rCell.left = 0; /* left side of window */ rCell.top = CharHeight * WinRow; /* Top of text */ /* Width of all characters */ dwStrSpec=GetTextExtent(ScrhDC, (LPSTR)ScrBuf[LastRow], CurrentCol); rCell.right = LOWORD(dwStrSpec); rCell.bottom = rCell.top + HIWORD(dwStrSpec); /* Clear Cell */ FillRect(ScrhDC, (LPRECT) &rCell, hBrush); /* Clear cell position */ CurrentCol = (--CurrentCol <= 0) ? 0 : CurrentCol; /* repaint text minus character */ TextOut(ScrhDC, 0, CharHeight * WinRow, (LPSTR) ScrBuf[LastRow], CurrentCol); /* cap off ScrBuf to be an 'Z' string */ ScrBuf[LastRow][CurrentCol] = (char) 0; break; default: /* just draw characters */ ScrBuf[LastRow][CurrentCol++] = (char) c; ScrBuf[LastRow][CurrentCol] = (char) 0; break; } } /* Draw character on window */ DrawChar(int c) { AddChar(c); UpdateLine(); } /* Draw string on window */ void DrawBuffer(LPSTR szString, int num) { int i; for(i=0; i < num && szString[i] != 0; i++) AddChar(szString[i]); UpdateLine(); } /* Clear screen */ void ClearScr() { if(ScrhDC = GetDC(hMainWnd)){ FirstRow=LastRow=0; /* zero circular buffer */ CurrentCol=0; /* Set pos to zero */ ScrBuf[LastRow][CurrentCol]=0; /* Kill string */ RepaintScr(); ReleaseDC(hMainWnd, ScrhDC); } } /* Winproc for stdio */ long FAR PASCAL WndProc(hWnd, message, wParam, lParam) HWND hWnd; unsigned message; WORD wParam; LONG lParam; { PAINTSTRUCT ps; int i; HMENU hMenu; char Buffer[BUFFER_SIZE]; switch (message) { case WM_COMMAND: switch(wParam){ case IDM_ABOUT: /* Show about box */ PopupDLG(hWnd, "AboutBox", About); break; case IDM_SAVE: /* Save data */ logfile=fopen(szFname, "w"); if(logfile){ hMenu=GetMenu(hWnd); EnableMenuItem(hMenu, IDM_CLOSE, MF_ENABLED); EnableMenuItem(hMenu, IDM_SAVE, MF_GRAYED); } break; case IDM_CLEAR: /* Clear "screen" */ ClearScr(); break; case IDM_CLOSE: /* Close log file */ if(!fclose(logfile)){ hMenu=GetMenu(hWnd); EnableMenuItem(hMenu, IDM_CLOSE, MF_GRAYED); EnableMenuItem(hMenu, IDM_SAVE, MF_ENABLED); } break; case IDM_DEFAULT: /* Set default position in win.ini */ { RECT rect; char buffer[25]; GetWindowRect(hWnd, &rect); /* get size */ wsprintf((LPSTR)buffer, (LPSTR)"%d,%d,%d,%d", rect.left, rect.top, rect.right, rect.bottom); WriteProfileString((LPSTR)szAppName, (LPSTR)szPosition, (LPSTR)buffer); } break; default: return (DefWindowProc(hWnd, message, wParam, lParam)); } break; case WM_USER: if(wParam == 11){ ScrhDC = GetDC(hWnd); #ifdef BY_THE_BOOK i = Pgets((LPSTR) Buffer, LOWORD(lParam), Stdout); DrawBuffer(Buffer, i); #else while((i=QueryPipe(Stdout))){ i = Pgets((LPSTR) Buffer, LOWORD(lParam), Stdout); DrawBuffer(Buffer, i); } #endif /* * This is done to fix a phasing error. If testapp is started before * stdio, stdio will be a number of read messages behind. So - I have * Changed the code to empty the pipe after a read message. Your code * Should either do this also or assure correct phasing of read and * write messages. */ ReleaseDC(hWnd, ScrhDC); } break; case WM_CHAR: if(wParam == 13) Pputc(10, Stdin); else Pputc((char) wParam, Stdin); break; case WM_DESTROY: ReleasePipe(Stdin); ReleasePipe(Stdout); PostQuitMessage(0); break; case WM_CREATE: { TEXTMETRIC tm; if(OpenPipe(hWnd, (LPSTR) "Stdout", PIPE_READ, 11) < 0) PostQuitMessage(0); logfile=NULL; hBrush = GetStockObject(WHITE_BRUSH); LastRow=0; CurrentCol=0; ScrhDC = GetDC(hWnd); GetTextMetrics(ScrhDC, (LPTEXTMETRIC) &tm); CharHeight = tm.tmHeight; CharWidth = tm.tmWeight; ReleaseDC(hWnd, ScrhDC); GetClientRect(hWnd, &rect); NumRows = (rect.bottom - rect.top) / CharHeight; } break; case WM_PAINT: ScrhDC = BeginPaint(hWnd, &ps); GetClientRect(hWnd, &rect); NumRows = (rect.bottom - rect.top) /CharHeight; RepaintScr(); EndPaint(hWnd, &ps); break; default: return (DefWindowProc(hWnd, message, wParam, lParam)); } return (NULL); } /* routine to create window sized by parameters in win.ini */ HWND SetWindow() { char Buffer[25]; char *szString; int i; int startx, starty, sizex, sizey; szString=Buffer; GetProfileString((LPSTR)szAppName, (LPSTR)szPosition, (LPSTR)szError, (LPSTR)szString, 25); if(lstrcmpi((LPSTR)szError, (LPSTR)szString)){ /* if default set */ while(*szString && !isdigit(*szString)) szString++; startx=atoi(szString); while(*szString && isdigit(*szString)) szString++; /* skip start x number */ while(*szString && !isdigit(*szString)) szString++; /* Skip non numbers */ starty=atoi(szString); while(*szString && isdigit(*szString)) szString++; /* skip start y number */ while(*szString && !isdigit(*szString)) szString++; /* skip non numbers */ sizex=atoi(szString); while(*szString && isdigit(*szString)) szString++; /* skip start y number */ while(*szString && !isdigit(*szString)) szString++; /* skip non numbers */ sizey=atoi(szString); sizex = sizex - startx; /* Get size, not coords. */ sizey = sizey - starty; } else{ startx = 0; sizex = GetSystemMetrics(SM_CXSCREEN); /* All across the bottom */ i=GetSystemMetrics(SM_CYSCREEN); /* Get Height of screen */ starty = i - (i * .3); /* 1/4 of the screen */ sizey = i - starty; } return(CreateWindow (szAppName,"Stdio Window", WS_OVERLAPPEDWINDOW, startx, starty, sizex, sizey, NULL, NULL, hInstance, NULL)); } /* Winmain routine for stdio */ int PASCAL WinMain(hInst, hPrevInstance, lpszCmdLine, nCmdShow) HANDLE hInst; HANDLE hPrevInstance; LPSTR lpszCmdLine; int nCmdShow; { MSG msg; BOOL bStat; hInstance = hInst; if(!hPrevInstance){ WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst; wc.hIcon = LoadIcon(hInst,"StdioIcon"); wc.hCursor = LoadCursor (NULL, IDC_ARROW); wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.lpszMenuName = szAppName; wc.lpszClassName = szAppName; if(!RegisterClass(&wc)) return(FALSE); } hMainWnd = SetWindow(); ShowWindow(hMainWnd, nCmdShow); UpdateWindow(hMainWnd); while(GetMessage(&msg, NULL, 0, 0)){ TranslateMessage(&msg); DispatchMessage(&msg); } return(msg.wParam); }