Автор работы: Пользователь скрыл имя, 25 Марта 2014 в 14:49, лекция
Конспект лекций содержит описание технологии системного программирования под Windows с использованием функций Win32 API. В первой части конспекта лекций рассмотрены особенности архитектуры ОС Windows, специфика интерфейса прикладного программирования Win32, структура приложений для Windows. Подробно рассмотрены API функции и основные структуры данных для работы с дисками, каталогами, файлами. Отдельная глава посвящена структурной обработке исключений SEH.
0, NULL, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if (hIn == INVALID_HANDLE_VALUE) { return 0; }
SetConsoleMode (hIn, ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT);
pRes = new char[80];
ReadConsole (hIn, pRes, MaxTchar, &TcharIn, NULL);
WriteConsole (hOut, pRes, MaxTchar, &Count, NULL);
delete [] pRes;
CloseHandle (hIn);
CloseHandle (hOut);
Sleep(1000);
return 0;
}
Примечание. Для того, чтобы выводить сообщения на русском языке, можно использовать для перекодировки символов функцию
BOOL CharToOem(
LPCTSTR lpszSrc, //указатель на исходную строку
LPSTR lpszDst // указатель на строку после перекодировки
);
Например, в примере 4 русский текст в строке pMsg: можно получить следующим образом:
LPCTSTR pMsg1="Привет всем!!!\n Введите текст: ";
LPSTR pMsg =new char[80];
CharToOem(pMsg1,pMsg); //
#include <windows.h>
#include <conio.h>
void MB(char *s)
// эта функция используется для удобства работы с MessageBox
{MessageBox(NULL,s,NULL,MB_OK|
// Эта функция выполняет основную работу по выводу на экран файла
void docat(char *fname)
{HANDLE f=CreateFile(fname, GENERIC_READ, 0, NULL,
OPEN_EXISTING, 0, NULL);
HANDLE out=GetStdHandle(STD_OUTPUT_
if (f==INVALID_HANDLE_VALUE)
{MB("Невозможно открыть файл!"); exit(1); }
char buf[4096];
unsigned long n;
do
{unsigned long wct;
if (!ReadFile(f,buf,sizeof(buf),&
if (n) WriteFile(out,buf,n,&wct,NULL)
}
while (n==sizeof(buf)); // при достижении конца файла (EOF) это
//условие не выполняется
CloseHandle(f);
}
void main(int argc,char *argv[])
{ if (argc==1)
{ MB("запуск программы: ntcat имя_файла1 [имя_файла2 ....]");
exit(9); }
// обрабатывать все файлы
while (--argc) { docat(*++argv); getche();}
exit(0);
}
Особым случаем работы с файлом является работа с коммуникационным портом. Для того чтобы можно было работать с портом, в основном используются те же самые функции CreateFile(), ReadFile() WriteFile(), которые используются и при работе с обычными файлами. Тем не менее, в связи с тем, что порт является не просто файлом, у него есть свои особенности.
Итак, что нужно сделать для того, чтобы получить доступ к последовательному порту? Прежде всего, при помощи функции CreateFile() необходимо этот порт открыть. Какое имя файла необходимо указывать при открытии порта? Для последовательных портов зарезервированы имена «СОМ1», «COM2», COM3» и так далее.
Далее следует определить режим разделения доступа к файлу dwShareMode. Последовательный порт - это неразделяемый ресурс, поэтому при его открытии нам необходимо указывать режим эксклюзивного доступа к файлу, то есть 0.
Следующий вопрос - а как быть с режимом открытия файла dwCreationDisposition? Естественно, что программным способом мы не сможем ни создать, ни удалить коммуникационный порт, мы можем использовать только существующие порты. Следовательно, при открытии порта в качестве режима открытия файла мы должны указать OPEN_EXISTING, и никакой другой.
Теперь определим, какие атрибуты файла (порта) должны быть указаны при его открытии? Если мы хотим, чтобы порт работал синхронно с нашей программой, мы должны параметр dwFlagsAndAttributes сделать равным нулю. Если же мы укажем в качестве этого параметра значение FILE_FLAG_OVERLAPPED, это будет означать, что порт будет работать асинхронно.
И, наконец, параметр hTemplateFile при работе с последовательным портом всегда должен быть равен нулю.
Как и обычно, в том случае, если порт открыт нормально, функция CreateFile() возвращает хэндл открытого файла. Это означает, что теперь мы можем осуществлять чтение и запись в порт (в соответствии с теми параметрами, которые мы указали при вызове функции). В случае возникновения какой-либо ошибки функция возвращает значение
INVALID_HANDLE_VALUE.
И, наконец, раз мы порт открываем, то, естественно, перед окончанием работы с портом он должен быть закрыт. Закрытие порта осуществляется обычным образом, при помощи функции CloseHandle().
Пример открытия и закрытия порта:
HANDLE hComPort;
hComPort = CreateFile ("COM1",
GENERIC_READ|GENERIC_WRITE, 0,
0NULL, OPEN_EXISTING, 0, NULL);
if(hComPort==INVALID_HANDLE_ VALUE) {
// Какие-то
действия, обычно оповещение
// о невозможности открыть порт. }
else { CloseHandle( hComPort);}
Однако, последовательный порт - это всё же не просто файл на диске. Поэтому, мало того, что мы его открыли, нужно ещё и настроить порт таким образом, чтобы параметры его работы соответствовали нашим требованиям. Настройка порта осуществляется несколькими функциями. Одна из этих функций, SetCommState().
BOOL SetCommState (HANDLE hFile, LPDCB IpDCB);
Первым аргументом этой функции является хэндл открытого порта. Второй аргумент - это указатель на структуру типа DCB. Эта структура содержит поля, определяющие скорость работы порта, порядок контроля четности, действия при ошибке, порядок использования сигналов RTS, DSR и многое другое. (Подробнее см. [6 Румянцев Файлы] ).
Заполнить структуру DCB можно при помощи функции:
BOOL GetCommState(HANDLE hFile, LPDCB IpDCB);
Эта функция считывает данные из внутренних регистров порта и управляющих структур драйвера. Первым аргументом этой функции является хэндл файла (в данном случае - порта), а вторым аргументом является указатель на структуру DCB, в которую будет записана необходимая информация о порте. В случае нормального завершения функция возвращает TRUE. Значение FALSE свидетельствует о том, что при считывании информации о параметрах порта произошла какая-то ошибка.
Вполне вероятно, что программе нужно будет изменить всего один или два параметра в этой структуре, например, скорость передачи. В этом случае вызов функции GetCommState() может намного сократить текст программы и заодно уменьшить количество возможных ошибок.
Итак, заполнив DCB и вызвав функцию SetCommState(), мы можем установить параметры работы порта.
После того как мы установили основные параметры работы порта, нам необходимо настроить значения временных задержек при приёме и передаче. Для этого используется функция:
BOOL SetCommTimeouts (HANDLE hFile,
LPCOMMTIMEOUTS lpCommTimeouts);
Нетрудно догадаться, что первым аргументом при обращении к функции является хэндл файла (порта - в нашем случае). Второй аргумент - это указатель на структуру типа COMMTIMEOUTS, которая в файле winbase.h описана следующим образом:
typedef struct ._COMMTIMEOUTS {
DWORD ReadIntervalTimeout;
DWORD ReadTotalTimeoutMultiplier;
DWORD ReadTotalTimeoutConstant;
DWORD WriteTotalTimeoutMultipiier;
DWORD WriteTotalTimeoutConstant;
} COMMTIMEOUTS,*LPCOMMTIMEOUTS;
Поле ReadIntervalTimeout определяет максимальный допустимый интервал (в миллисекундах) между появлением на коммуникационной линии двух последовательных символов.
Поле ReadTotalTimeoutMultiplier задаёт коэффициент, используемый для вычисления общей длительности операции чтения. Фактически представляет собой среднее время, необходимое для чтения одного символа, потому что для каждой операции чтения этот коэффициент умножается на число символов, подлежащих чтению.
Поле ReadTotalTimeoutConstant задаёт задержку (в миллисекундах), необходимую для завершения операции чтения. Для вычисления общей длительности операции чтения эта задержка прибавляется к результату умножения ReadTotalTimeoutMuitiplier на число считываемых символов.
Поле WriteTotalTimeoutMultiplier задаёт коэффициент, используемый для вычисления общей длительности операции записи. Фактически представляет собой среднее время, необходимое для записи одного символа, потому что для каждой операции записи этот коэффициент умножается на число символов, подлежащих записи.
Поле WriteTotalTimeoutConstant задаёт задержку (в миллисекундах), необходимую для завершения операции записи. Для вычисления общей длительности операции записи эта задержка прибавляется к результату умножения WriteTotalTimeoutMultiplier на число записываемых символов.
И в данном случае, как и в случае с функцией SetCommState(), мы можем получить установленные ранее значения задержек. Это делается при помощи функции:
BOOL GetCommTimeouts (HANDLE hFile,
LPCOMMTIMEOUTS lpCommTimeouts);
Первым аргументом этой функции является хэндл открытого порта, а вторым - указатель на структуру типа COMMTIMEOUTS, в которые будут записаны значения задержек, выставленные в указанном порте.
Для получения информации о настройках порта можно использовать также функцию:
BOOL GetCommProperties (HANDLE hFile,
LPCOMMPROP lpCommProp);
Первым аргументом этой функции является хэндл порта, информацию о котором требуется получить, вторым - указатель на структуру типа COMMPROP, в которые будут записаны значения свойств порта (номер версии структуры, различные битовые маски, максимальный размер выводного буфера, максимальная скорость, тип порта и др ).
Иногда может возникнуть ситуация, когда пользователь сам должен определить параметры работы порта. В таких случаях можно воспользоваться функцией, обеспечивающей вывод стандартного диалогового окна (которое содержится в коммуникационном драйвере):
BOOL CommConfigDialog(LPCSTR lpszName, HWND hWnd,
LPCOMMCONFIG lpCC);
Первый аргумент этой функции – указатель на строку, в которой содержится имя устройства, для которого вызывается диалоговое окно. Второй аргумент - хэндл родительского окна. Третий аргумент является указателем на структуру типа COMMCONFIG, в которой перед вызовом диалогового окна содержится начальная информация. После завершения работы окна в этой структуре будут находиться новые значения параметров.
Сама функция CommConfigDialog не производит никаких настроек порта, она только предоставляет удобный интерфейс для взаимодействия с пользователем. Поэтому после того как пользователь ввел все необходимые данные, обязательно нужно вызвать функцию
BOOL SetCommConfig(HANDLE hCommDev,
LPCOMMCONFIG lpCC, DWORD dwSize);
Первым аргументом этой функции является хэндл открытого порта, вторым - указатель на подготовленную структуру типа COMMCONFIG, третьим – размер в байтах блока памяти, занимаемого структурой COMMCONFIG.
С помощью функции
BOOL GetDefaultCommConfig((LPCWSTR lpszName,
LPCOMMCONFIG lpCC),
DWORD dwSize);
можно определить параметры порта, установленные системой по умолчанию.
Первый аргумент этой функции – указатель на строку, в которой содержится имя коммуникационного устройства, второй - указатель на структуру типа COMMCONFIG, третьим – размер в байтах блока памяти, занимаемого структурой COMMCONFIG.
Можно установить собственные значения по умолчанию с помощью функции:
BOOL SetDefaultCommConfig((LPCWSTR lpszName,
LPCOMMCONFIG lpCC),
DWORD dwSize);
Параметры этой функции аналогичны параметрам функции GetDefaultCommConfig.
Кроме перечисленных функций еще имеется ряд функций, позволяющих управлять портом в процессе работы (подробнее об этих функциях [6]).
Win32 содержит множество функций управления файлами, как правило, довольно простых. Приведенные ниже функции удаляют, копируют и переименовывают файлы. Также есть функция, создающая имена временных файлов.
Для удаления файла надо указать его имя. Все абсолютные полные имена начинаются с буквы диска или имени сервера.
BOOL DeleteFile (LPCTSTR lpszFileName)
LpszFileName – указатель на буфер, в котором хранится имя удаляемого файла.
Следует отметить одну особенность работы этой функции в Windows 9х: вызвав эту функцию, можно удалить и открытый файл, и файл, отображенный в память, что, в свою очередь, может привести к безвозвратной потере данных. Чтобы предотвратить потерю данных, файл перед удалением следует закрывать.В Windows 2000/NT нельзя удалить открытый файл, попытка сделать это в NT приведет к ошибке.
Скопировать файл можно с помощью всего одной функции.
BOOL CopyFile (LPCTSTR lpszExistingFile,
LPCTSTR lpszNewFile,
BOOL fFailExists)
CopyFile копирует
определенный по имени
Для перемещения файла служат функции MoveFile() и MoveFileEx(). Эти функции также могут работать с каталогами (действие функций DeleteFile и CopyFile ограничено файлами).
BOOL MoveFile (LPCTSTR lpszExisting, LPCTSTR lpszNew)
BOOL MoveFileEx (LPCTSTR lpszExisting, LPCTSTR lpszNew,
DWORD fdwFlags)
MoveFile завершается неудачно, если новый файл уже существует; для существующих файлов следует применять MoveFileEx. В Windows 9х функция MoveFileEx реализована ограниченно и бесполезна; она только возвращает FALSE, указывая на ошибку.
Параметры функций управления файлами:
lpszExisting определяет имя существующего файла или каталога.
lpszNew определяет имя нового файла или каталога, который в MoveFile не должен существовать. Новый файл может находиться в другой файловой системе или на другом диске, но новые каталоги должны быть на том же диске. Если этот параметр имеет значение NULL, существующий файл удаляется.
FdwFlags определяет следующие опции:
Перемещение (переименование) файлов связано с несколькими важными ограничениями.
Информация о работе Системное программирование в среде Win32