Модемы и факс-модемы. Программирование для MS-DOS и Windows.© Александр Фролов, Григорий ФроловТом 16, М.: Диалог-МИФИ, 1993. 7.3. Приложение EASYTTYНаше первое телекоммуникационное приложение EASYTTY демонстрирует использование функций Windows, предназначенных для работы с портами асинхронного последовательного адаптера и модемами. Приложение EASYTTY выполняет все основные функции, которые должна поддерживать любая телекоммуникационная программа. EASYTTY позволяет передавать модему AT-команды, принимать от него ответ и отображать его на экране. Перед тем как запускать приложение EASYTTY на вашем компьютере, следует создать в каталоге Windows файл EASYTTY.INI (см. листинг 7.6). Если вместе с книгой вы приобрели дискету, то скопируйте файл EASYTTY.INI из каталога WIN\EASYTTY в каталог Windows. Листинг 7.6. Файл EASYTTY.INI [Port] Mode=COM2:9600,N,8,1 Файл EASYTTY.INI должен состоять из одного раздела [Port], содержащего единственную строку Mode. В этой строке определяется номер COM-порта, к которому подключен модем, скорость обмена и формат передаваемых данных. Формат строки Mode совпадает с форматом команды MODE операционной системы MS-DOS. Запустите EASYTTY. Набирая на клавиатуре AT-команды модема, можно перевести его в любой режим. Например, можно сбросить текущую конфигурацию. Для этого введите команду ATZ и нажмите клавишу Чтобы приложение EASYTTY могло автоматически отвечать на вызов по телефонной линии, передайте модему команду ATS0=1 и нажмите клавишу
Рис. 7.2. Приложение EASYTTY Вы можете передать модему команду набора номера удаленного абонента. Чтобы набрать номер 777-77-77, достаточно ввести команду ATDP 777-77-77 и нажать клавишу После установления связи с удаленным модемом вы можете обменяться с ним текстовыми сообщениями. Набирайте передаваемый текст на клавиатуре и просматривайте ответ от удаленного компьютера в главном окне приложения. Когда вы закончите сеанс связи с удаленным компьютером, переведите модем в командный режим и передайте ему команду ATH0. Модем повесит трубку и отключится от телефонной линии. Чтобы перевести модем из режима передачи данных в командный режим, подождите 2-3 секунды, наберите на клавиатуре три знака '+' и дождитесь от модема ответа OK. Главный файл приложения EASYTTY приведен в листинге 7.7. Листинг 7.7. Файл EASYTTY.CPP #include Особенностью приложения EASYTTY является использование интерфейса EasyWin, предоставляемого средой разработки Borland C++ for Windows версии 3.1. Интерфейс EasyWin позволяет сократить до минимума код, требуемый для создания окна, вывода в него принимаемых данных и получения ввода с клавиатуры. После запуска приложения EASYTTY, функция WinMain выполняет инициализацию интерфейса EasyWin. Для этого вызывается функция _InitEasyWin, описанная во включаемом файле STDIO.H: _InitEasyWin(); После вызова этой функции появляется главное окно приложения. Теперь можно вызывать стандартные функции консольного ввода/вывода - puts, kbhit, getch, putch. Затем функция WinMain вызывает функцию InitCommPort, определенную в приложении. Эта функция считывает из раздела [Port] файла PHONE.INI строку Mode, которая определяет номер COM-порта, к которому подключен модем и его режим работы. Потом InitCommPort открывает соответствующий порт и устанавливает его режим. Затем функция завершает свою работу и возвращает идентификатор открытого COM-порта. Если COM-порт не открыт, то идентификатор открытого COM-порта равен нулю и приложение сразу завершает работу. После того как порт открыт, вызывается функция puts: puts( "Для завершения приложения нажмите клавишу Она выводит в окне приложения строку "Для завершения приложения нажмите клавишу while( TRUE ) { MSG msg; // Организуем цикл обработки сообщений if( PeekMessage( ( LPMSG )&msg, NULL, 0, 0, PM_REMOVE ) ) { // При получении сообщения WM_QUIT завершаем приложение if ( msg.message == WM_QUIT ) return( msg.wParam ); TranslateMessage( &msg ); DispatchMessage ( &msg ); } // Если в очереди приложения нет сообщений, начинаем обмен // данными через COM-порт else { if( !ProcessExchange( idCommPort )) { // Закрываем главное окно приложения DestroyWindow(GetFocus()); } } } Функция PeekMessage образует цикл обработки сообщений, благодаря которому одновременно могут работать и другие приложения Windows. Функция ProcessExchange является сердцем приложения EASYTTY. Она организует весь диалог пользователя с приложением. Для этого она считывает данные из входного буфера COM-порта, поступающие в него от модема, и отображает их в окне приложения. Если вы нажимаете на клавиши, функция ProcessExchange передает код клавиши в выходной буфер COM-порта. Если вы нажмете клавишу Теперь рассмотрим более подробно функции InitCommPort, ProcessExchange и CloseCommPort, определенные в приложении. Функция InitCommPort считывает из раздела [Port] файла EASYTTY.INI строку Mode, определяющую режим работы COM-порта и записывает ее в буфер szCommSettings. Если файл EASYTTY.INI не обнаружен в каталоге Windows или в нем не определена строка Mode, в буфер szCommSettings записывается строка "COM1:9600,n,8,1". Затем из строки в буфере szCommSettings выделяются первые четыре символа, задающие номер COM-порта для последующей передачи его функции OpenComm. Функция OpenComm открывает этот COM-порт. if((idCommPort = OpenComm(szPortName, QUEUE_SIZE, QUEUE_SIZE)) < 0 ) { ... } Если COM-порт не открыт, OpenComm возвращает отрицательное значение. Функция отображает предупреждающее сообщение "Ошибка открытия порта..." и завершает работу. Если COM-порт успешно открыт, удаляем все символы из входной и выходной очередей: // Удаляем все символы из выходной очереди FlushComm( idCommPort, 0 ); // Удаляем все символы из входной очереди FlushComm( idCommPort, 1 ); Затем заполняем структуру dcbCommPort типа DCB в соответствии с командной строкой Mode из раздела [Port] файла EASYTTY.INI. Для этого используем функцию BuildCommDCB, передав ей строку szCommSettings: if( BuildCommDCB( szCommSettings, &dcbCommPort ) != 0 ) { // В случае ошибки отображаем сообщение и // завершаем работу приложения MessageBox( NULL, "Ошибка при заполнении структуры DCB", "Ошибка", MB_OK | MB_ICONEXCLAMATION ); return( -1 ); } Если BuildCommDCB возвращает значение, не равное нулю, значит произошла ошибка. В этом случае выводим сообщение "Ошибка при заполнении структуры DCB" и завершаем функцию, возвращая число -1. В случае успешного выполнения функции BuildCommDCB устанавливаем новый режим COM-порта в соответствии с подготовленной структурой DCB: if( SetCommState( &dcbCommPort ) != 0 ) { // В случае ошибки отображаем сообщение и // завершаем работу приложения MessageBox( NULL, "Ошибка установки режима COM-порта", "Ошибка", MB_OK | MB_ICONEXCLAMATION ); return( -1 ); } Если SetCommState возвращает ненулевое значение, значит произошла ошибка. В этом случае выводим сообщение "Ошибка установки режима COM-порта" и завершаем функцию InitCommPort, возвращая число -1. Если функция SetCommState завершилась успешно, функция InitCommPort завершает работу и возвращает идентификатор открытого COM-порта. Позже полученный идентификатор COM-порта передается функциям ProcessExchange и CloseCommPort. Функция ProcessExchange вызывает GetCommError, заполняющую структуру ComStat типа COMSTAT: COMSTAT ComStat; // Определяем текущее состояние открытого COM-порта GetCommError( idCommPort, &ComStat ); Поле cbInQue структуры ComStat будет определять количество символов во входной очереди используемого нами COM-порта. Если во входной очереди есть данные, считываем их и выводим их в окно приложения: nCharWaiting = ReadComm( idCommPort, inBuff, ( nCharWaiting > QUEUE_SIZE ? QUEUE_SIZE : nCharWaiting )); // Отображаем полученные символы на экране if ( nCharWaiting > 0 ) for( int i = 0; i < nCharWaiting; i++ ) putch(inBuff[i]); else return( FALSE ); Если входная очередь COM-порта пуста, с помощью стандартной функции консольного ввода/вывода kbhit проверяем, нажата ли какая-нибудь клавиша на клавиатуре. В случае, если клавиша нажата, определяем ее код: // Если клавиша нажата, определяем ее код char keyHit = ( char )getch(); if ( !keyHit ) keyHit = ( char )getch(); Проверяем, нажата ли клавиша V// Закрываем COM-порт и возвращаем значение FALSE CloseCommPort( idCommPort ); return( FALSE ); Если пользователь нажал любую другую клавишу, записываем ее код в выходную очередь COM-порта: nCharWriting = WriteComm( idCommPort, ( LPSTR )&keyHit, 1 ); На этом работа функции завершена, и мы переходим к рассмотрению функции CloseCommPort. Функция CloseCommPort наиболее простая из функций приложения EASYTTY. Она удаляет все символы из входной и выходной очереди COM-порта, а затем закрывает COM-порт и возвращает управление: FlushComm( idCommPort, 0 ); FlushComm( idCommPort, 1 ); CloseComm( idCommPort ); return 0; Файл определения модуля для приложения EASYTTY приведен в листинге 7.8. Листинг 7.8. Файл EASYTTY.DEF ; ========================================================== ; Файл определения модуля ; ========================================================== NAME EASYTTY DESCRIPTION 'Приложение EASYTTY, (C) 1994, Frolov G.V.' EXETYPE windows STUB 'winstub.exe' STACKSIZE 16384 HEAPSIZE 16384 CODE preload moveable discardable DATA preload moveable multiple |