- •История Windows
- •Windows 1.0
- •Windows 1.3
- •Windows 2.0
- •Windows 3.0
- •Windows 3.1
- •Windows for Workgroups версии 3.11
- •Windows NT
- •Windows 95
- •Windows NT Workstation 4.0 и Windows NT Server 4.0
- •Windows NT 4.0 Server Enterprise Edition
- •Windows 98
- •Windows 98 Second Edition (SE)
- •Windows 2000
- •Windows 98 Millenium Edition (ME)
- •Windows XP
- •Общая архитектура WINDOWS приложения.
- •Каркас приложения
- •Регистрация класса окна
- •Создание окна.
- •Отображение окна.
- •Цикл обработки очереди сообщений.
- •WndProc
- •Обработка сообщений типового приложения.
- •Контрольные вопросы
- •Сообщения
- •Типы сообщений
- •Обработка клавиатурных сообщений
- •Обработка сообщений от мыши
- •Сообщения таймера
- •Контрольные вопросы
- •Организация ввода
- •Разупорядоченный ввод
- •Разделение потоками виртуальных очередей ввода
- •Локальное состояние ввода
- •Ввод с клавиатуры и фокус
- •Управление курсором мыши
- •Контрольные вопросы
- •Окна
- •Окна Windows
- •Иерархия окон
- •Оконная процедура, стандартные оконные процедуры
- •Стиль класса окна
- •Стили окон, окна основных стилей
- •Перекрывающиеся окна
- •Временные окна
- •Дочерние окна
- •Сообщения управления окнами
- •Окна с полосами прокрутки
- •Системные метрики
- •Определение размера окна
- •Определение расположения окна
- •Контрольные вопросы
- •Графический интерфейс устройств(GDI).
- •Создание (получение) контекста устройств.
- •Сохранение контекста устройства.
- •Прямые (отрезки) и кривые
- •Закрашенные области
- •Битовые шаблоны (растровые шаблоны, растровые образы)
- •Текст и шрифты
- •Режимы масштабирования и преобразования
- •Метафайл
- •Регионы
- •Путь
- •Палитры
- •Контрольные вопросы
- •Объекты ядра
- •Что такое объект ядра
- •Учет пользователей объектов ядра
- •Защита
- •Таблица описателей объектов ядра
- •Создание объекта ядра
- •Закрытие объекта ядра
- •Синхронизация объектов
- •Именованные объекты
- •Дублирование описателей объектов
- •Изменение флагов описателя
- •Синхронизация потоков
- •Критическая секция
- •Мьютексы
- •Семафоры
- •События
- •Ожидаемые таймеры
- •Контрольные вопросы
- •Ресурсы Windows приложения
- •Файлы ресурсов приложения
- •Значки (пиктограммы)
- •Курсоры
- •Битовые образы
- •Символьные строки
- •Ресурсы, определяемые пользователем
- •Таблица акселераторов
- •Меню
- •Диалоговые окна
- •Контрольные вопросы
- •Элементы управления
- •Дочерние окна управления
- •Создание дочерних окон
- •Сообщения дочерних окон родительскому окну
- •Сообщения родительского окна дочерним окнам
- •Дочерние окна и фокус ввода
- •Дочерние окна управления и цвет
- •Кнопки различных стилей (класс BUTTON)
- •Нажимаемые кнопки
- •Флажки-переключатели
- •Переключатели
- •Окна групп
- •Кнопки, определяемые пользователем
- •Статические поля (класс static)
- •Текстовые редакторы (класс edit)
- •Списки разных стилей (класс listbox)
- •Комбинированные списки (класс combobox)
- •Полосы прокрутки (класс scrollbar)
- •Контрольные вопросы
- •Расширенные элементы управления
- •Основы общих элементов управления
- •Инициализация библиотеки элементов общего пользования
- •Создание элементов управления общего пользования
- •Посылка сообщений общим элементам управления
- •Уведомляющие сообщения от общих элементов управления
- •Контрольные вопросы
- •Стандартные диалоговые окна.
- •Окна сообщений
- •Диалоговые окна общего пользования
- •Контрольные вопросы
- •Динамически подключаемые библиотеки
- •Создание DLL
- •Проецирование DLL на адресное пространство процесса
- •Функция входа/выхода
- •Функция DllMain и стандартная библиотека С
- •Функция LibEntry
- •Функция LibMain
- •Функция WEP
- •Экспорт функций и переменных из DLL
- •Импорт функций и переменных из DLL
- •Заголовочный файл DLL
- •Разделы в ЕХЕ- и DLL-файлах
- •Контрольные вопросы
- •Файлы, проецируемые в память
- •Контрольные вопросы
- •Классы, определяющие архитектуру приложения
- •Классы приложения и поддержки потоков
- •Классы приложения и потоков
- •Классы фреймов окон
- •Получение информации о приложении
- •Соглашения об именах MFC
- •Включаемые файлы
- •Функция WinMain
- •Класс CWinApp
- •Класс CWnd
- •Класс CFrameWnd
- •Создание главного окна SDI-приложения
- •Примечание
- •Создание главного окна SDI-приложения
- •Создание дочерних окон
- •Ограничение размеров окна
- •Ограничение доступа к окну
- •Создание многодокументных приложений
- •Класс CMDIChildWnd
- •MDI — пример приложения
- •Категории сообщений
- •Карта сообщений
- •Компоненты карты сообщений
- •Класс CCmdTarget
- •Стандартный маршрут команды
- •Команды обновления и класс CCmdlll
- •Функции для работы с сообщениями
- •Основные положения
- •Класс CDocTemplate
- •Класс CSingleDocTemplate
- •Роль фреймов в архитектуре "документ/представление"
- •Документ и его представления
- •Документы
- •Класс CDocument
- •Класс CArchive
- •Представления
- •Класс CView
- •Панели элементов управления
- •Класс CStatusBar
- •Класс CStatusBarCtrl
- •Класс CDialogBar
- •ControlBars — пример приложения
- •НЕКОТОРЫЕ КЛАССЫ MFC
- •Класс CObject - основной класс MFC
- •Конструкторы класса
- •Оператор присваивания
- •Диагностика
- •Проверка целостности объектов класса
- •Получение дампа объекта класса
- •Сохранение и восстановление состояния объекта
- •Метод IsSerializable
- •Виртуальный метод Serialize
- •Информация о классе
- •Виртуальный метод GetRuntimeClass
- •Метод IsKindOf
- •Класс CPoint - точка на плоскости
- •Класс CSize - относительные координаты
- •Класс CString - текстовые строки
- •Конструктор класса
- •Коллекции
- •Массивы - шаблон CArray
- •Списки - шаблон CList
- •Словари - шаблон CMap
- •Класс CTime - дата и время
- •Файловая система - класс CFile
- •Открытие и создание файлов
- •Идентификатор открытого файла
- •Закрытие файлов
- •Чтение и запись файлов
- •Метод Flush
- •Операции с файлами
- •Блокировка
- •Позиционирование
- •Характеристики открытого файла
- •Файловая система - классы CMemFile и CStdioFile
- •Модификация класса CMemFile
- •Файловая система - класс CStdioFile
- •Запись и восстановление объектов
- •Запись в архивный файл
- •Чтение из архивного файла
- •Исключения - класс CException
- •Класс CException
- •Класс CMemoryException
- •Класс CFileException
- •Приложение Except
- •Класс CArchiveException
- •Класс CNotSupportedException
- •Класс CResourceException
- •Класс CUserException
HANDLE hFileMapRO;
DuplicateHandle(GetCurrentProcess(),
hFileMapRW, GetCurrentProcess(), &hFileMdpRO, FILE_MAP_READ, FALSE, 0);
// вызываем функцию, которая не должна ничего записывать в проекцию файла
ReadFromTheFileMapping(hFileMapRO);
// закрываем объект "проекция файла" , доступный только для чтения
CloseHandle(hFileMapRO);
// проекция файла нам по-прежнему полностью доступна через hFileMapRW
.
.
.
// если проекция файла больше не нужна основному коду, закрываем ее
CloseHandle(hFileMapRW);
}
Изменение флагов описателя
Иногда встречаются ситуации, в которых родительский процесс создает объект ядра с наследуемым описателем, а затем порождает два дочерних процесса. Но наследуемый описатель нужен только одному из них. Иначе говоря, время от времени
возникает необходимость контролировать, какой из дочерних процессов наследует описатели объектов ядра. Для этого модифицируйте флаг наследования, связанный с
описателем, вызовом SetHandleInformation:
BOOL |
SetHandleInformation( |
HANDLE |
hObject, |
DWORD |
dwMask, |
DWORD dwFlags); |
|
Как видите, эта функция принимает три параметра. Первый (bObject) идентифицирует допустимый описатель. Второй (dwMask) сообщает функции, какой флаг (или флаги)
Вы хотите изменить. На сегодняшний день с каждым описателем связано два флага:
#define |
HANDLE_FLAG_INHERIT |
0x00000001 |
#define HANDLE_FLAG_PROTECT_FROM_CLOSE 0x00000002 |
|
|
И, наконец, третий параметр функции SetHandleInformation — dwFlags — указывает, в
какое именно состояние следует перевести флаги. Например, чтобы установить флаг наследования для описателя объекта ядра:
SetHandleInformation(hobj, HANDLE_FLAG_INHERIT,
HANDLE_FLAG_INHERIT);
а чтобы сбросить этот флаг:
SetHandleInformation(hobj, HANDLE_FLAG_INHERIT, 0);
Флаг HANDLE_FLAG_PROTECT_FROM_CLOSE сообщает системе, что
данный описатель закрывать нельзя:
SetHandleInformation(hobj, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE);
CloseHandle(hobj); // генерируется исключение
Если какой-нибудь поток попытается закрыть защищенный описатель,
CloseHandle приведет к исключению. Необходимость в такой защите возникает очень редко. Однако этот флаг весьма полезен, когда процесс порождает дочерний, а тот в свою очередь — еще один процесс. При этом родительский процесс может ожидать, что его "внук" унаследует определенный описатель объекта, переданный дочернему. Но тут вполне возможно, что дочерний процесс, прежде чем породить новый процесс, закрывает нужный описатель. Тогда родительский процесс теряет связь с "внуком", поскольку тот не унаследовал требуемый объект ядра. Защитив описатель от закрытия, Вы исправите ситуацию, и "внук" унаследует предназначенный ему объект.
У этого подхода, впрочем, есть один недостаток. Дочерний процесс, вызвав:
SetHandleInformation(hobj, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0);
CloseHandle(hobj);
может сбросить флаг HANDLE_FLAG_PROTECT_FROM_CLOSE и закрыть затем соответствующий описатель. Родительский процесс ставит на то, что дочерний не исполнит этот код. Но одновременно он ставит и на то, что дочерний процесс породит ему "внука", поэтому в целом ставки не слишком рискованны.
Для полноты картины стоит, пожалуй, упомянуть и функцию
GetHandleInformation: |
|
BOOL |
GetHandleInformation( |
HANDLE |
hObj, |
PDWORD pdwFlags); |
|
Эта функция возвращает текущие флаги для заданного описателя в переменной типа
DWORD, на которую укапывает pdwFlags. Чтобы проверить, является ли описатель наследуемым, сделайте так:
DWORD |
dwFlags; |
GetHandleInformation(hObj, |
&dwFlags); |
BOOL fHandleIsInheritable = (0 != (dwFlags & HANDLE_FLAG_INHERIT)); |
|



Синхронизация потоков
В среде, позволяющей исполнять несколько потоков одновременно, очень важно синхронизировать их деятельность. Для этого в операционных системах, базирующихся на Win32, предусмотрен целый ряд синхронизирующих объектов. В данном разделе мы рассмотрим пять таких объектов: критические секции, объекты-мьютексы, семафоры,
события и ожидаемые таймеры.
В общем случае поток синхронизирует себя с другим так: он засыпает, и
операционная система, не выделяя ему процессорного времени, приостанавливает его выполнение. Но прежде чем заснуть, поток сообщает системе, какое особое событие должно произойти, чтобы его исполнение возобновилось. Как только указанное событие произойдет, поток вновь получит право на выделение ему процессорного времени, и все пойдет своим чередом. Таким образом, отныне
выполнение потока синхронизировано с определенным событием.
Критическая секция
Критическая секция (critical section) — это небольшой участок кода, требующий монопольного доступа к каким-то общим данным. Она представляет собой структуру, содержащую несколько флагов и какой-то объект ядра. Среди синхронизирующих объектов критические секции наиболее просты, но применимы для синхронизации потоков лишь в пределах одного процесса. Они позволяют сделать так, чтобы единовременно только один поток получал доступ к определенному региону. При входе в критическую секцию сначала проверяются флаги, и если выясняется, что она занята уже другим потоком, то выполняется обычная wait-
функция. Для проверки, занята критическая секция или нет, программа не переходит в режим ядра, а лишь проверяются флаги. Из-за этого считается, что синхронизация с помощью критической секции наиболее быстрая.
Создание. Для этого сначала сформируем в своем процессе структуру данных CRITICAL_SECTION. Она должна быть глобальной, чтобы к ней могли обращаться разные потоки. Обычно критические секции представляют собой набор глобальных переменных. Хотя структура CRITICAL_SECTION и ее элементы определены в файле WINNT.H, считайте ее содержимое «черным ящиком». Win32-функции, управляющие критическими секциями, сами инициализируют и модифицируют элементы данной структуры.
Применение. Прежде чем синхронизировать потоки с помощью критической секции, нужно инициализировать ее вызовом InitializeCriticalSection, передав адрес
структуры CRITICAL_SECTION в параметре IpCriticalSection:
VOID InitializeCnticalSection(LPCRITICAL_SECTION IpCnticalSection)
Эта функция обязательно вызывается перед обращением к EnterCriticalSection..
Предположим, SecondThread исполняется первой. Она вызывает
EnterCriticalSection, передавая ей адрес переменной-структуры g_CriticalSection:
VOID EnterCriticalSection(LPCRITICAL_SECTION IpCriticalSection)
Обнаружив, что для переменной g_CriticalSection она вызвана впервые, эта функция изменяет некоторые элементы в структуре данных .Допустим, после этого второй поток вытесняется первым, и начинается исполнение функции FirstThread. Она вызывает EnterCriticalSection, передавая ей адрес того же объекта, что и SecondThread. На этот раз
EnterCriticalSection видит, что переменная-структура g_CriticalSection уже используется, и приостанавливает исполнение первого потока. Остаток процессорного времени передается другому потоку, и операционная система больше не выделяет квантов времени первому потоку, пока он спит.
Когда второй поток получит следующий квант времени, функция SecondThread исполнит оператор:
