Автор работы: Пользователь скрыл имя, 25 Марта 2014 в 14:49, лекция
Конспект лекций содержит описание технологии системного программирования под Windows с использованием функций Win32 API. В первой части конспекта лекций рассмотрены особенности архитектуры ОС Windows, специфика интерфейса прикладного программирования Win32, структура приложений для Windows. Подробно рассмотрены API функции и основные структуры данных для работы с дисками, каталогами, файлами. Отдельная глава посвящена структурной обработке исключений SEH.
BOOL AbnormalTermination (VOID)
Функция возвращает TRUE при аварийном завершении и FALSE при нормальном завершении.
#include <tchar.h>
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
__try {
int n=MessageBox(NULL,"Обратиться к несуществующей памяти?","Обработка завершения", MB_YESNO);
if (n==IDYES) { *(PBYTE) NULL=5;} }
__finally {
LPCTSTR psz= AbnormalTermination() ? TEXT("Аварийное завершение "): TEXT ("Нормальное завершение");
MessageBox(NULL,psz,"В блоке finally", MB_OK); }
MessageBox(NULL," Норамальное завершение процесса","Обработка завершения", MB_OK);
return 0; }
Обработчик завершения , или блок finally, выполняется в контексте блока или функции, которую он контролирует. Управление может передаваться с конца обработчика завершения на следующий оператор. Также в обработчике завершения может выполняться оператор перехода (return, break, continue, goto, longjmp или _leave). Еще один вариант – выход из обработчика по исключению.
Отдельный блок try должен иметь один блок finally или except; оба блока сразу не допускаются. Но можно вложить один блок в другой. Следующий код обеспечивает удаление временного файла при выходе из цикла как по логике программы, так и по исключению. Можно также применить внутренний блок try-except для оперций с плавающей запятой.
_try { /* Внешний блок try-except */
while (. . .) _try { /* Внутренний блок try-finally */
hFile = CreateFile (TempFi:le, ...);
if (…) _try {/* Внутренний блок try-except */
/* Разрешение исключений ПЗ и выполнение вычислений */
…
}
_except (EXCEPTION_EXECUTE_HANDLER) {
… /* Обработка исключения ПЗ */ _clearf ();
}
… /* Обработка, не связанная с ПЗ */
}
_finally { /* Конец цикла while loop */
/* Выполняется на каждой итерации цикла */
CloseHandle (hFile); DeleteFile (TempFile);
}
}
_except (выражение фильтра) {
/* Обработчик исключения */
}
Эта программа преобразует один или несколько файлов. Имена преобразуемых файлов передаются в программу в качестве параметров запуска. Преобразование заключается в том, что все латинские строчные буквы в файле заменяются заглавными. Выходной файл имеет то же имя, что и входной, но с дополнительным префиксом «UC».
#include "stdafx.h"
#include <windows.h>
#include <string.h>
#include <stdio.h>
int main(int argc, LPTSTR argv[])
{
HANDLE hIn, hOut;
DWORD FileSize, nXfer, iFile, j;
CHAR OutFileName[256] = "", *pBuffer = NULL;
OVERLAPPED ov = { 0, 0, 0, 0, NULL}; //структура перекрытия
//используется для блокировки файлов
char ss[256];
if (argc <= 1) MessageBox (NULL, "Не заданы параметры",
"Ошибка запуска", MB_OK);
/* Обработка всех файлов в командной строке */
for (iFile = 1; iFile < argc; iFile++) __try
{ /* Блок исключения*/
/*Все дескрипторы файлов закрыты, pBuffer == NULL, и
OutFileName пуст. Это гарантируют обработчики */
strcpy(OutFileName, "UC");
strcat(OutFileName,argv[iFile] );
strcpy(ss,"Начало обработки файла ");
strcat(ss,argv[iFile] );
MessageBox (NULL, ss, "Цикл обработки ", MB_OK);
__try { /*Внутренний блок try-finally */
/* Ошибка на любом шаге вызовет исключение, и после очистки начнется обработка следующего файла. Объем очистки зависит от того, где произошла ошибка*/
// Открытие исходного файла
hIn = CreateFile (argv[iFile], GENERIC_READ, 0, NULL,
OPEN_EXISTING, 0, NULL);
if (hIn == INVALID_HANDLE_VALUE)
MessageBox(NULL, "Ошибка открытия входного файла",
"Ошибка при работе с файлами", MB_OK);
FileSize = GetFileSize (hIn, NULL);
hOut = CreateFile (OutFileName, GENERIC_READ|GENERIC_WRITE,
0, NULL, CREATE_ALWAYS, 0, NULL);
if (hOut == INVALID_HANDLE_VALUE)
MessageBox(NULL, "Ошибка создания выходного файла",
"Ошибка при работе с файлами", MB_OK);
/*Резервирование памяти под содержимое файла */
pBuffer = (char *) malloc (FileSize);
if (pBuffer == NULL)
MessageBox(NULL, "Ошибка выделения памяти",
"Ошибка при работе с памятью ", MB_OK);
/*Блокировка обеих файлов, чтобы обеспечить целостность копии */
if (!LockFileEx (hIn, LOCKFILE_FAIL_IMMEDIATELY, 0, FileSize, 0, &ov))
MessageBox(NULL, "Ошибка блокировки входного файла",
" Ошибка при работе с файлами ", MB_OK);
if (!LockFileEx (hOut, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, 0, FileSize, 0, &ov))
MessageBox(NULL, "Ошибка блокировки выходного файла",
" Ошибка при работе с файлами ", MB_OK);
if (!ReadFile (hIn, pBuffer, FileSize, &nXfer, NULL))
MessageBox(NULL, "Ошибка чтения из файла",
"Ошибка при работе с файлами", MB_OK);
for (j = 0; j < FileSize; j++) /*Преобразование данных */
if (isalpha(pBuffer[j])) pBuffer[j] = toupper(pBuffer[j]);
if (!WriteFile (hOut, pBuffer, FileSize, &nXfer, NULL))
MessageBox(NULL, "Ошибка записи в файл",
"Ошибка при работе с файлами", MB_OK);
} __finally
{ /* Блокировка снимается,
дескрипторы файлов
if (pBuffer != NULL) free (pBuffer); pBuffer = NULL;
if (hIn != INVALID_HANDLE_VALUE)
{UnlockFileEx (hIn, 0, FileSize, 0, &ov);
CloseHandle (hIn);
hIn = INVALID_HANDLE_VALUE;}
if (hOut != INVALID_HANDLE_VALUE)
{UnlockFileEx (hOut, 0, FileSize, 0, &ov);
CloseHandle (hOut);
hOut = INVALID_HANDLE_VALUE;}
strcpy(OutFileName, "");
}
} /*Конец главного цикла обработки файла и блока try */
/* Этот обработчик исключения применяется к телу цикла*/
__except (EXCEPTION_EXECUTE_HANDLER) {
strcpy(ss,"Ошибка обработки ");
strcat(ss,argv[iFile]);
printf(" Error occured processing file %s\n",argv[iFile]);
MessageBox(NULL, ss, "Ошибка!", MB_OK);
DeleteFile (OutFileName);
}
MessageBox(NULL, "Преобразованы все файлы, кроме указанных выше", "Результат", MB_OK);
return 0;
}
Хотя обработчик завершения справляется с большинством ситуаций, в которых выход из блока try был бы преждевременным, он не может вызвать выполнение блока finally при завершении потока или процесса. Вызов ExitTbread или ExitProcess сразу завершит поток или процесс - без выполнения какого-либо кода в блоке finaly. Обработчики завершения не выполняются при завершении процесса или потока, независимо от того, завершает ли процесс или поток себя сам с помощью функции ExitProcess или ExitThread либо они завершаются извне вызовом TerminateProcess или TerminateThread. Поэтому процесс или поток не должны выполнять эти функции в блоке try-except или try-finally.
Также обратите внимание, что функция exit библиотеки С или возвращение из функции main завершают процесс.
Обработка исключений в C++ использует ключевые слова catch и throw и реализована на основе SEH. Несмотря на это, обработка исключений C++ и SEH — разные вещи. При их совместном применении нужна осторожность, так как заданные пользователем и генерируемые в C++ обработчики исключений могут входить в конфликт. Например, обработчик _except может находиться в стеке и перехватывать исключения C++, и тогда обработчик C++ вообще не получит исключения. Возможно и обратное: захват обработчиком C++ исключения SEH, сгенерированного RaiseException. В документации Microsoft рекомендуется, чтобы обработчики исключений Win32 вообще не использовались в программах на C++; вместо этого должна применяться только обработка исключений в C++.
Кроме того, обработчик исключения или завершения Win32 не вызывает деструкторов для уничтожения экземпляров объектов C++.
Обработчики исключений могут отвечать на самые разнообразные события, однако они не выявляют таких ситуаций, как завершение сеанса пользователя или ввод Ctrl-C с клавиатуры для остановки программы. Для обнаружения таких событий нужны обработчики управления консоли; они доступны на всех платформах Windows, кроме Windows СЕ.
Функция SetConsoleCtrlHandler запускает выполнение одной или нескольких указанных функций по получении <Ctrl+C>, <Ctrl+Break> или одного из трех других сигналов консоли. Функция GenerateConsoleCtrlEvent также генерирует эти сигналы, которые могут быть направлены другим процессам, совместно использующим данную консоль. Обработчики — это заданные пользователем функции типа BOOL, которые принимают параметр dword, обозначающий принятый сигнал.
С каждым сигналом может быть связано несколько обработчиков; обработчики можно удалять и добавлять. Для этого применяется следующая функция:
BOOL SetConsoleCtrlHandler (PHANDLER_ROUTINE HandlerRoutine, BOOL Add)
Процедура обработчика добавляется, если флаг Add имеет значение true; в противном случае она удаляется из списка процедур управления консоли. Заметьте, что сигнал здесь не указывается. Обработчик должен сделать проверку, чтобы узнать, какой именно сигнал принят.
Текущая процедура обработчика возвращает значение bool и принимает один параметр dword, который идентифицирует фактический сигнал. Вместо имени обработчика в определении стоит метка-заполнитель; имя указывается программистом.
Использование обработчиков управления консоли имеет несколько других особенностей.
• Если параметр HandlerRoutine равен null, a Add равно true, сигналы <Ctrl+C> будут игнорироваться.
• Флаг enable_processed_input в SetConsoleMode вызывает обработку <Ctrl+C> как ввода с клавиатуры, а не как сигнала,
• Процедура обработчика фактически выполняется как независимый поток в процессе. Основная программа продолжает работу.
• Вызов исключения в обработчике не приводит к возникновению исключения в потоке, который была прерван, так как исключения применяются к потокам, а не ко всему процессу. Для связи с прерванным потоком следует использовать переменную или метод синхронизации.
Есть еще одно важное различие между исключениями и сигналами. Сигнал обращается ко всему процессу, тогда как исключение – только к потоку, где выполняется код, в котором произошло исключение.
BOOL HandlerRoutine (DWORD dwCtrlType)
DwCtrlType идентифицирует текущий сигнал (или событие) и может принимать одно из пяти значений.
1. ctrl_c_event указывает, что с клавиатуры была введена последовательность <Ctrl+C>.
2. ctrl_close_event указывает, что окно консоли закрывается.
3. ctrl_break_event обозначает сигнал <Ctrl+Break>.
4. ctrl_loqofp_event указывает, что пользователь завершает сеанс.
5. ctrl_shutdown_event указывает, что система завершает работу.
Обработчик сигнала, как и обработчик исключения или завершения, может выполнять операции очистки. Он должен возвратить true, чтобы указать, что функция обработала сигнал. Если обработчик сигнала возвращает false, то вызывается следующий обработчик в списке. Обработчики сигнала выполняются в порядке, противоположном тому, в котором они были установлены, так что первым выполняется последний установленный обработчик, а последним — системный обработчик.
Таблица П.1
Константа |
Описание |
SW_HIDE |
Скрывает окно и активизирует другое |
SW_MAXIMIZE |
Максимизирует окно |
SW_MINIMIZE |
Сворачивает окно и активизирует расположенное под ним окно |
SW_RESTORE |
Восстанавливает свернутое окно |
SW_SHOW |
Активизирует окно в текущих размерах и позиции |
SW_SHOWMAXIMIZED |
Активизирует окно в максимально распахнутом виде |
SW_SHOWMINIMIZED |
Активизирует окно в свернутом виде |
SW_SHOWMINNOACTIVE |
Сворачивает окно |
SW_SHOWNA |
Показывает состояние окна |
SW_SHOWNOACTIVATE |
Показывает окно в текущих координатах |
SW_SHOWNORMAL |
Активизирует и отображает окно в первоначальных размерах и позиции |
Таблица П.2
Значение стиля |
Пояснение |
Код |
CS_BYTEALIGNCLIENT |
Рабочую область окна выравнивать по границе байта видеопамяти. Это ускоряет перерисовку окна, влияет на размеры окна по оси х. |
0х1000 |
CS_BYTEALIGNWINDOW |
Все окно выравнивать по границе байта видеопамяти. Это влияет на размеры окна по оси х. |
0х1000 |
CS_CLASSDC |
Создать единый контекст отображения для всех окон |
0х0040 |
CS_DBLCLKS |
Функция окна будет получать сообщения при двойном щелчке клавишей мыши над рабочей областью |
0х0008 |
CS_GLOBALCLASS |
Доступный всем приложениям класс. При создании окон можно игнорировать дескриптор приложения. |
0х4000 |
CS_HREDRAW |
Рабочую область перерисовывать при изменении ширины окна |
0х0002 |
CS_NOCLOSE |
Отключить команду Close в системном меню |
|
CS_OWNDC |
Создать свой контекст устройства для каждого окна |
0х0020 |
CS_PARENDC |
Окна будут пользоваться контекстом устройства, создавшего их окна (родителя) |
0х0080 |
CS_SAVEBITS |
Часть окна, затененного другим окном, сохранять в виде битового образа и использовать этот образ для воссоздания этой части при перемещении затеняющего окна. |
0х0200 |
CS_VREDRAW |
Рабочую область перерисовывать при изменении высоты окна |
0х0001 |
Информация о работе Системное программирование в среде Win32