Программа 2.2. Функция Report Error, предназначенная для вывода сообщений об ошибках при выполнении системных вызовов
#include "EvryThng.h"
VOID ReportError(LPCTSTR UserMessage, DWORD ExitCode, BOOL PrintErrorMsg)
/* Универсальная функция для вывода сообщений о системных ошибках. */
{
DWORD eMsgLen, LastErr = GetLastError();
LPTSTR lpvSysMsg;
HANDLE hStdErr = GetStdHandle(STD_ERROR_HANDLE);
PrintMsg(hStdErr, UserMessage);
if (PrintErrorMsg) {
eMsgLen = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, LastErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpvSysMsg, 0, NULL);
PrintStrings (hStdErr, _T("\n"), lpvSysMsg, _T("\n"), NULL);
/* Освободить блок памяти, содержащий сообщение об ошибке. */
HeapFree(GetProcessHeap(), 0, lpvSysMsg); /* См. гл. 5. */
}
if (ExitCode > 0) ExitProcess (ExitCode);
else return;
}
Пример: копирование нескольких файлов на стандартное устройство вывода
В программе 2.3 иллюстрируется использование стандартных устройств ввода/вывода, а также демонстрируется, как улучшить контроль ошибок и усовершенствовать взаимодействие с пользователем. Эта программа представляет собой вариант ограниченной реализации команды UNIX cat, которая копирует один или несколько заданных файлов (или содержимое буфера стандартного устройства ввода, если файлы не указаны) на стандартное устройства вывода.
Программа 2.3 включает полную обработку ошибок. В большинстве других примеров проверка ошибок опущена или сведена к минимуму, но полностью включена в завершенные документированные варианты программ, находящиеся на Web-сайте. Обратите внимание на функцию Options (ее листинг приведен в приложении А), вызываемую в начале программы. Эта функция, которая включена в состав программ, находящихся на Web-сайте, и используется на протяжении всей книги, просматривает параметры в командной строке и возвращает индекс массива argv, соответствующий имени первого файла. Функция Options аналогична функции getopt, которая используется во многих программах в UNIX.
Программа 2.3. cat: вывод нескольких файлов на стандартное устройство вывода
/* Глава 2. cat. */
/* cat [параметры] [файлы] Допускается только параметр –s, предназначенный для подавления вывода сообщений об ошибках в случае, если один из указанных файлов не существует. */
#include "EvryThng.h"
#define BUF_SIZE 0x200
static VOID CatFile(HANDLE, HANDLE);
int _tmain(int argc, LPTSTR argv[]) {
HANDLE hInFile, hStdIn = GetStdHandle(STD_INPUT_HANDLE);
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
BOOL DashS;
int iArg, iFirstFile;
/* Переменная DashS будет установлена только в случае задания параметра "-s" в командной строке. */
/* iFirstFile — индекс первого входного файла в списке argv[]. */
iFirstFile = Options(argc, argv, _T("s"), &DashS, NULL);
if (iFirstFile == argc) { /*Отсутствие входных файлов в списке аргументов.*/
/* Использовать стандартное устройство ввода. */
CatFile(hStdIn, hStdOut);
return 0;
}
/* Обработать каждый входной файл. */
for (iArg = iFirstFile; iArg < argc; iArg++) {
hInFile = CreateFile(argv [iArg], GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hInFile == INVALID_HANDLE_VALUE && !DashS) ReportError (_T("Cat: ошибка при открытии файла"), 1, TRUE);
CatFile (hInFile, hStdOut);
CloseHandle (hInFile);
}
return 0;
}
/* Функция, выполняющая всю работу:
/* читает входные данные и копирует их на стандартное устройства вывода. */
static VOID CatFile(HANDLE hInFile, HANDLE hOutFile) {
DWORD nIn, nOut;
BYTE Buffer [BUF_SIZE];
while (ReadFile(hInFile, Buffer, BUF_SIZE, &nIn, NULL) && (nIn != 0) && WriteFile(hOutFile, Buffer, nIn, &nOut, NULL));
return;
}
Пример: преобразование символов из ASCII в Unicode
Программа 2.4 достраивает программу 1.3, в которой использовалась вспомогательная функция CopyFile. С копированием файлов вы уже знакомы, поэтому в данном примере эта операция дополняется преобразованием файла к кодировке Unicode в предположении, что первоначальной кодировкой символов является ASCII, хотя проверка этого предположения не производится. В программе предусмотрены некоторые возможности вывода сообщений об ошибках и параметр, позволяющий подавить замену существующего файла; завершающий вызов функции CopyFile заменен в программе вызовом новой функции, которая Выполняет преобразование символьных строк файла из кодировки ASCII в кодировку Unicode.
В данной программе основное внимание уделяется обеспечению возможности успешного завершения преобразования. Фактическое выполнение преобразования сосредоточено в единственной функции, вызываемой в самом конце программы. Этот фрагмент, как и аналогичный ему фрагмент предыдущей программы, послужит нам шаблоном и будет вновь использоваться в последующих программах без повторения его исходного кода.
Обратите внимание на вызов функции _taccess, проверяющей существование файла. Эта функция является обобщенной версией функции access, которая имеется в библиотеке UNIX, но не входит в состав стандартной библиотеки С. Ее определение содержится в файле <io.h>. Если говорить точнее, функция _taccess осуществляет проверку прав доступа к файлу в соответствии с режимом, установленным значением второго параметра. Значение 0 задает проверку существования файла, 2 — проверку наличия разрешения на запись в файл, 4 — проверку наличия разрешения на чтение из файла, 6 — проверку наличия разрешения как на чтение из файла, так и на запись в файл (эти значения не связаны напрямую с такими параметрами доступа, используемыми в Windows, как GENERIC_READ). Альтернативой проверке существования файла могло бы быть открытие дескриптора при помощи функции CreateFile и его последующее закрытие после проверки действительности дескриптора.
Программа 2.4. atou: преобразование файла с выводом сообщений об ошибках
/* Глава 2. atou – копирование файлов с преобразованием из ASCII в Unicode. */
#include "EvryThng.h"
BOOL Asc2Un(LPCTSTR, LPCTSTR, BOOL);
int _tmain(int argc, LPTSTR argv[]) {
DWORD LocFileIn, LocFileOut;
BOOL DashI = FALSE;
TCHAR YNResp[3] = _T("y");
/* Получить параметры командной строки и индекс входного файла. */
LocFileIn = Options(argc, argv, _T("i"), &DashI, NULL);
LocFileOut = LocFileIn + 1;
if (DashI) { /* Существует ли выходной файл? */
/* Обобщенная версия функции access, осуществляющая проверку существования файла. */
if (_taccess(argv[LocFileOut], 0) == 0) {
_tprintf(_T("Перезаписать существующий файл? [y/n]"));
_tscanf(_T ("%s"), &YNResp);
if (lstrcmp(CharLower(YNResp), YES) != 0) ReportError(_T("Отказ от перезаписи"), 4, FALSE);
}
}
/* Эта функция построена на основе функции CopyFile. */
Asc2Un(argv[LocFileIn], argv [LocFileOut], FALSE);
return 0;
}
Программа 2.5 — это вызываемая в программе 2.4 функция Asc2Un, осуществляющая преобразование кодировки символов.