Системное программирование в среде Win32

Автор работы: Пользователь скрыл имя, 25 Марта 2014 в 14:49, лекция

Краткое описание

Конспект лекций содержит описание технологии системного программирования под Windows с использованием функций Win32 API. В первой части конспекта лекций рассмотрены особенности архитектуры ОС Windows, специфика интерфейса прикладного программирования Win32, структура приложений для Windows. Подробно рассмотрены API функции и основные структуры данных для работы с дисками, каталогами, файлами. Отдельная глава посвящена структурной обработке исключений SEH.

Прикрепленные файлы: 1 файл

Win32_лек_часть1.doc

— 811.00 Кб (Скачать документ)

BOOL AbnormalTermination (VOID)

 Функция возвращает TRUE при аварийном завершении и FALSE при нормальном завершении.

Пример 6.5. Аварийное завершение

#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). Еще один вариант – выход из обработчика по исключению.

 

6.5. Сочетание блоков Finally  и  Except

Отдельный блок 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 (выражение фильтра) {

/* Обработчик исключения  */

}

Пример 6.6. Обработка файлов с восстановлением при ошибках

Эта программа преобразует один или несколько файлов. Имена преобразуемых файлов передаются в программу в качестве параметров запуска. Преобразование заключается в том, что все латинские строчные буквы в файле заменяются заглавными. Выходной файл имеет то же имя, что и входной, но с дополнительным префиксом «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 завершают процесс.

 

SЕН  и обработка исключений C++

Обработка исключений в C++ использует ключевые слова catch и throw и реализована на основе SEH. Несмотря на это, обработка исключений C++ и SEH — разные вещи. При их совместном применении нужна осторожность, так как заданные пользователем и генерируемые в C++ обработчики исключений могут входить в конфликт. Например, обработчик _except может находиться в стеке и перехватывать исключения C++, и тогда обработчик C++ вообще не получит исключения. Возможно и обратное: захват обработчиком C++ исключения SEH, сгенерированного RaiseException. В документации Microsoft рекомендуется, чтобы обработчики исключений Win32 вообще не использовались в программах на C++; вместо этого должна применяться только обработка исключений в C++.

Кроме того, обработчик исключения или завершения Win32 не вызывает деструкторов для уничтожения экземпляров объектов C++.

6.6. Обработчики управления консоли

Обработчики исключений могут отвечать на самые разнообразные события, однако они не выявляют таких ситуаций, как завершение сеанса пользователя или ввод 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. Вильямс А. Системное программирование в Windows 2000 для профессионалов. СПБ: Питер, 2001. 624 с.
  2. Харт Джонсон М.Системное программирование в среде Win32. 2-е изд. : Пер. с англ. М. : Издательский дом «Вильямс», 2001. 464 с.
  3. Мешков А., Тихомиров Ю. Visual C++ и MFC. Программирование для Windows NT и Windows 95: В 3 т. Т.1. СПб.: BHV – Санкт-Петербург, 1997. 464 с.
  4. Мешков А., Тихомиров Ю. Visual C++ и MFC. СПб.: БХВ – Петербург, 2002. 1040 с.
  5. Румянцев П.В.  Азбука программирования в Win32 API. М.: Горячая линия – Телеком, 2001.  312 с.
  6. Румянцев П.В.  Работа с файлами в Win32 API. М.: Горячая линия – Телеком, 2002.  216 с.
  7. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с учетом специфики 64-разрядной версии Windows : Пер. с англ. 4-е изд. СПб.: Питер; М.: Издательско-торговый дом «Русская редакция», 2003. 752 с.
  8. Гордеев А.В., Молчанов А.Ю. Системное программное обеспечение. СПб.: Питер, 2002. 736 с.
  9. Ганеев Р.М. Проектирование интерфейса пользователя средствами Win32  API. М.: Горячая линия – Телеком, 2001. – 336 с.
  10. Сорокина С.И., Тихонов А.Ю., Щербаков А.Ю. Программирование драйверов и систем безопасности: Учебное пособие. СПб.: БХВ-Петербург, М.: Издатель Молгачева С.В. 2002. 256 с.
  11. Зверева О.М. Операционные системы. Конспект лекций. Ч.1-ч.5. Екатеринбург: Изд-во УМЦ-УПИ, 2002. 

 

 

 

Приложение

Таблица П.1

Значения параметра функции WinMain, определяющего вид окна на экране (nCmdShow)

Константа

Описание

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