//*************************************************************** // From the book "Win32 System Services: The Heart of Windows 98 // and Windows 2000" // by Marshall Brain // Published by Prentice Hall // // Copyright 1995, by Prentice Hall. // // This code demonstrates the comm setup for a simple terminal // emulator program. //*************************************************************** // term.cpp #include #include #include #include void ErrorHandler(char *s, DWORD err) { cout << s << endl; cout << "Error number: " << err << endl; ExitProcess(err); } // Scrolls the console up one line void ScrollOneLine(HANDLE consoleStdout) { BOOL success; CONSOLE_SCREEN_BUFFER_INFO consoleInfo; SMALL_RECT scrollRect; CHAR_INFO consoleFill; COORD coord; // get current console size (may change) success = GetConsoleScreenBufferInfo( consoleStdout, &consoleInfo); if (!success) ErrorHandler("In GetConsoleScreenBufferInfo", GetLastError()); // Define the rectangle to scroll scrollRect.Top = 0; scrollRect.Left = 0; scrollRect.Bottom = consoleInfo.dwSize.Y - 1; scrollRect.Right = consoleInfo.dwSize.X - 1; // Define destination of scrolled rectangle coord.X = 0; coord.Y = -1; // Define how to fill blank line consoleFill.Attributes = consoleInfo.wAttributes; consoleFill.Char.AsciiChar = ' '; // Perform the scroll success = ScrollConsoleScreenBuffer(consoleStdout, &scrollRect, 0, coord, &consoleFill); if (!success) ErrorHandler("In ScrollConsoleScreenBuffer", GetLastError()); } // Handles the newline character VOID NewLine(HANDLE consoleStdout) { CONSOLE_SCREEN_BUFFER_INFO consoleInfo; BOOL success; // Find out where cursor is success = GetConsoleScreenBufferInfo(consoleStdout, &consoleInfo); if (!success) ErrorHandler("In GetConsoleScreenBufferInfo", GetLastError()); // Move cursor to far left consoleInfo.dwCursorPosition.X = 0; // If the cursor is on the last line // of the console, then scroll the console, // else increment position if (consoleInfo.dwSize.Y - 1 == consoleInfo.dwCursorPosition.Y) ScrollOneLine(consoleStdout); else consoleInfo.dwCursorPosition.Y += 1; // Update the console success = SetConsoleCursorPosition(consoleStdout, consoleInfo.dwCursorPosition); if (!success) ErrorHandler("In SetConsoleCursorPosition", GetLastError()); } // Initializes the port HANDLE SetupCommPort(char *port) { HANDLE comHandle; BOOL success; DCB dcb; COMMTIMEOUTS timeouts; // Open the file comHandle = CreateFile(port, GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); if (comHandle == INVALID_HANDLE_VALUE) ErrorHandler("In CreateFile", GetLastError()); // Set timeouts so ReadFile does not // return until data is available timeouts.ReadIntervalTimeout = 0 ; timeouts.ReadTotalTimeoutMultiplier = 0 ; timeouts.ReadTotalTimeoutConstant = 0 ; timeouts.WriteTotalTimeoutMultiplier = 0 ; timeouts.WriteTotalTimeoutConstant = 0 ; SetCommTimeouts( comHandle, &timeouts ) ; // Get current settings and change them success = GetCommState(comHandle, &dcb); if (!success) ErrorHandler("In GetCommState", GetLastError()); dcb.BaudRate = 2400; dcb.ByteSize = 8; dcb.Parity = NOPARITY; dcb.StopBits = ONESTOPBIT; success = SetCommState(comHandle, &dcb); if (!success) ErrorHandler("In SetCommState", GetLastError()); EscapeCommFunction(comHandle, SETDTR); return comHandle; } void ProcessIO(HANDLE consoleStdin, HANDLE consoleStdout) { char readBuffer, writeBuffer; DWORD numRead, numWrite; INPUT_RECORD inputEvent; DWORD s; HANDLE comHandle, readEvent, writeEvent; HANDLE handles[2]; OVERLAPPED overlappedRead, overlappedWrite; BOOL success; char *portString = "COM2"; // Set up the comm port. Can setup COM, LPT // or \\\\.\\TELNET. If you do TELNET, make sure // you have the TCP/IP package loaded and // the telnet service started comHandle = SetupCommPort(portString); // Set up for overlapped reading and // writing on the port overlappedRead.Offset = overlappedWrite.Offset = 0; overlappedRead.OffsetHigh = overlappedWrite.OffsetHigh = 0; readEvent = CreateEvent(0, TRUE, FALSE, 0); writeEvent = CreateEvent(0, FALSE, FALSE, 0); overlappedRead.hEvent = readEvent; overlappedWrite.hEvent = writeEvent; // Set up handles array // for WaitForMultipleObjects handles[0] = consoleStdin; handles[1] = readEvent; // Prime the pump by getting the read // process started success = ReadFile(comHandle, &readBuffer, 1, &numRead, &overlappedRead); do { // Wait for either a keystroke or a // modem character. Time out after // 1000 seconds s = WaitForMultipleObjects(2, handles, FALSE, 1000000); if (s==WAIT_TIMEOUT) break; // If it is a character from the // keyboard then... else if (s==WAIT_OBJECT_0) { // Get a copy of the character but // leave it in the queue PeekConsoleInput(handles[0], &inputEvent, 1, &numRead); if (numRead>0) { // If it is a mouse event, or a key up // event, or if it is not a valid // ASCII character (eg-a shift key), // then read and discard the keystroke. if (inputEvent.EventType != KEY_EVENT || inputEvent.Event.KeyEvent.bKeyDown == FALSE || inputEvent.Event.KeyEvent. uChar.AsciiChar==0) ReadConsoleInput(handles[0], &inputEvent, 1, &numRead); // Otherwise, read the keystroke // and send it to the comm port. else { ReadFile(handles[0], &writeBuffer, 1, &numWrite, 0); success = WriteFile(comHandle, &writeBuffer, 1, &numWrite, &overlappedWrite); GetOverlappedResult(comHandle, &overlappedWrite, &numWrite, TRUE); overlappedWrite.Offset += numWrite; } } } // If the character is coming in from // the comm port, then... else if (s==WAIT_OBJECT_0 + 1) { // Get the character and send it // to the console success = GetOverlappedResult(comHandle, &overlappedRead, &numRead, TRUE); overlappedRead.Offset += numRead; WriteFile(consoleStdout, &readBuffer, 1, &numWrite, 0); ResetEvent(readEvent); // Wait for the next character // from the comm port ReadFile(comHandle, &readBuffer, 1, &numRead, &overlappedRead); } // Terminate when the user types an 'X' } while (writeBuffer != 'X'); // Close all handles CloseHandle(readEvent); CloseHandle(writeEvent); CloseHandle(comHandle); } VOID main(void) { DWORD oldMode, newMode; BOOL success; HANDLE consoleStdout, consoleStdin; // Get handles for standard in and out consoleStdin = GetStdHandle(STD_INPUT_HANDLE); consoleStdout = GetStdHandle(STD_OUTPUT_HANDLE); if (consoleStdin == consoleStdout) ErrorHandler("In GetStdHandle", GetLastError()); // Get current console mode so can modify it success = GetConsoleMode(consoleStdin, &oldMode); if (!success) ErrorHandler("In GetConsoleMode", GetLastError()); newMode = oldMode & ~ENABLE_LINE_INPUT & ~ENABLE_ECHO_INPUT; success = SetConsoleMode(consoleStdin, newMode); if (!success) ErrorHandler("In SetConsoleMode", GetLastError()); // Process user I/O ProcessIO(consoleStdin, consoleStdout); // put the old mode back success = SetConsoleMode(consoleStdin, oldMode); if (!success) ErrorHandler("In SetConsoleMode", GetLastError()); }