![](/user_photo/1549_7W_y5.jpg)
- •История 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
![](/html/1549/349/html_zF3yk3EBC5.yf3l/htmlconvd-KH3qLD80x1.jpg)
выполняется и новый его экземпляр можно закрыть. Вот фрагмент кода, иллюстрирующий этот прием:
|
int WINAPI WinMain(HINSTANCE hinstExe, HINSTANCE, PSTR pszCmdLine, |
||||||
int |
|
|
|
nCmdShow} |
|
{ |
|
HANDLE |
h |
= |
CreateMutex(NULL, |
FALSE, |
"{FA531CC1-0497-11d3-A180- |
||
00105A276C3E}"); |
|
|
|
|
|
||
if |
|
(GetLastError() |
== |
|
ERROR_ALREADY_EXISTS){ |
||
// |
экземпляр |
этого |
приложения |
уже |
выполняется |
||
return(0), |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// |
запущен |
первый |
экземпляр |
данного |
приложения |
||
// |
|
перед |
|
выходом |
|
закрываем |
объект |
CloseHandle(h),
return(0);
}
Дублирование описателей объектов
Последний механизм совместного использования объектов ядра несколькими процессами требует функции DuplicateHandle:
BOOL |
DuplicateHandle( |
HANDLE |
hSourceProcessHandle, |
HANDLE |
hSourceHandle, |
HANDLE |
hTargetProcessHandle, |
PHANDLE |
phTargetHandle, |
DWORD |
dwDesiredAccess, |
BOOL |
bInheritHandle, |
DWORD dwOptions); |
|
Эта функция берет запись в таблице описателей одного процесса и создает ее копию в таблице другого. DuplicateHandle принимает несколько параметров, но на самом деле весьма незамысловата. Обычно ее применение требует наличия в системе трех разных процессов.
![](/html/1549/349/html_zF3yk3EBC5.yf3l/htmlconvd-KH3qLD81x1.jpg)
•Первый и третий параметры функции DuplicateHandle представляют собой описатели объектов ядра, специфичные для вызывающего процесса. Кроме того, эти параметры должны идентифицировать именно процессы — функция
завершится с ошибкой, если Вы передадите описатели на объекты ядра любого другого типа.
•Второй параметр, hSourceHandle, — описатель объекта ядра любого типа. Однако его значение специфично не для процесса, вызывающего DuplicateHandle, а для того, на который указывает описатель hSourceProcessHandle. Параметр phTargetHandle — это адрес переменной типа
HANDLE, в которой возвращается индекс записи с копией описателя из процессаисточника. Значение возвращаемого описателя специфично для процесса, определяемого параметром hTargetProcessHandle.
•Предпоследние два параметра DuplicateHandle позволяют задать маску доступа и флаг наследования, устанавливаемые для данного описателя в процессеприемнике.
•И, наконец, параметр dwOptions может быть 0 или любой комбинацией двух
флагов. DUPLICATE_SAME_ACCESS и DUPLICATE_CLOSE_SOURCE.
Первый флаг подсказывает DuplicateHandle: у описателя, получаемого процессомприемником, должна быть та же маска доступа, что и у описателя в процессеисточнике. Этот флаг заставляет DuplicateHandle игнорировать параметр dwDesiredAccess. Второй флаг приводит к закрытию описателя в процессеисточнике. Он позволяет процессам обмениваться объектом ядра как эстафетной палочкой. При этом счетчик объекта не меняется.
Проиллюстрируем работу функции DuplicateHandle на примере. Здесь S — это процесс-источник, имеющий доступ к какому-то объекту ядра, Т — это процессприемник, который получит доступ к тому же объекту ядра, а С — процесс катализатор, вызывающий функцию DuplicateHandle.
Таблица описателей в процессе С (см таблицу 4) содержит два индекса - 1 и 2. Описатель с первым значением идентифицирует объект ядра "процесс S", описатель со вторым значением — объект ядра "процесс Т"
|
Индекс |
Указатель |
на блокМаска |
доступа |
Флаги |
(DWORD с |
|
|
|
памяти объекта ядра (DWORD |
|
битовых |
флагов) |
||
|
|
|
|
с набором |
битовых |
набором |
|
|
|
|
|
флагов) |
|
|
|
|
1 |
0xF0000000 |
|
0x???????? |
|
0x00000000 |
|
|
|
(объект |
ядра |
|
|
|
|
|
|
процесса S) |
|
|
|
|
|
|
2 |
0xF0000010 |
(обьект |
0x???????? |
|
0x00000000 |
|
|
|
ядра процесса Т) |
|
|
|
|
|
Таблица 4. Таблица описателей в процессе С |
|
|
|
![](/html/1549/349/html_zF3yk3EBC5.yf3l/htmlconvd-KH3qLD82x1.jpg)
Таблица 5 иллюстрирует таблицу описателей в процессе S, содержащую единственную запись со значением описателя, равным 2. Этот описатель может идентифицировать объект ядра любого типа, а не только "процесс".
ИндексУказатель на блокМаска |
доступа |
Флаги (DWORD с |
|||
|
памяти объекта(DWORD |
|
набором |
||
|
ядра |
|
с набором битовых |
битовых флагов) |
|
|
|
|
флагов) |
|
|
1 |
0x00000000 |
|
(неприменим) |
|
(неприменим) |
2 |
0xF0000020 |
|
0x???????? |
|
0x00000000 |
|
(объект |
ядра |
|
|
|
|
любого типа) |
|
|
|
|
Таблица 5. Таблица описателей в процессе S
В таблице 6 показано, что именно содержит таблица описателей в процессе Т перед вызовом процессом С функции DuplicateHandle. Как видно, в ней всего одна запись со значением описателя, равным 2, а запись с индексом 1 пока пуста.
Индекс |
Указатель на блок |
Маска доступа (DWORD |
Флаги (DWORD с |
|||
|
памяти объекта ядра |
с |
набором |
битовых |
набором |
|
|
|
флагов) |
|
битовых флагов |
||
1 |
0x00000000 |
(неприменим) |
|
(неприменим) |
||
|
|
|
|
|
||
2 |
0xF0000030 |
0x???????? |
|
0x00000000 |
||
|
(объект ядра любого |
|
|
|
|
|
|
типа) |
|
|
|
|
Таблица 6. Таблица описателей в процессе Т перед вызовом DuplicateHandle
Если процесс С теперь вызовет DuplicateHandle так:
DuplicateHandle(1, 2, 2, &hObj, 0, TRUE, DUPLICATE_SAME_ACCESS);
то после вызова изменится только таблица описателей в процессе Т (см. таблицу 7).
Индекс |
Указатель на |
блок |
Маска |
доступа |
Флаги |
(DWORD |
с |
|
памяти объекта ядра |
(DWORD |
с набором |
набором |
битовых |
||
|
|
|
битовых флагов) |
флагов) |
|
|
|
1 |
0xF0000020 |
|
0х???????? |
|
0x00000001 |
|
|
|
|
|
|
|
|
|
|
2 |
0xF0000030 |
|
0х???????? |
|
0x00000000 |
|
|
|
(объект ядра |
любого |
|
|
|
|
|
|
типа) |
|
|
|
|
|
|
Таблица 7. Таблица описателей в процессе Т после вызова DuplicateHandle
![](/html/1549/349/html_zF3yk3EBC5.yf3l/htmlconvd-KH3qLD83x1.jpg)
Вторая строка таблицы описателей в процессе S скопирована в первую строку таблицы описателей в процессе Т. Функция DuplicateHandle присвоила также переменной bObj процесса С значение 1 — индекс той строки таблицы в процессе Т, в которую занесен новый описатель.
Поскольку функции DuplicateHandle передан флаг DUPLICATE_SAME_ACCESS, маска доступа для этого описателя в процессе Т идентична маске доступа в процессе S. Кроме того, данный флаг заставляет DuplicateHandle проигнорировать параметр dwDesiredAccess. Заметьте также, что система установила битовый флаг наследования, так как в параметре bInheritHandle функции DuplicateHandle мы передали TRUE.
Очевидно, Вы никогда не станете передавать в DuplicateHandle жестко зашитые значения, как это сделано в примере, просто демонстрируя работу функции. В
реальных программах значения описателей хранятся в переменных и, конечно же,
именно эти переменные передаются функциям.
Как и механизм наследования, функция DuplicateHandle тоже обладает одной
странностью: процесс-приемник никак не уведомляется о том, что он получил доступ к новому объекту ядра. Поэтому процесс С должен каким-то образом сообщить процессу Т, что тот имеет теперь доступ к новому объекту; для этого нужно воспользоваться одной из форм межпроцессной связи и передать в процесс Т значение описателя в переменной bObj. Ясное дело, в данном случае не годится ни командная строка, ни изменение переменных окружения процесса Т, поскольку этот процесс уже выполняется. Здесь придется послать сообщение окну или задействовать какой-нибудь другой механизм межпроцессной связи.
Представьте, что один процесс имеет доступ к объекту, к которому хочет обратиться другой процесс, или что один процесс хочет предоставить другому доступ к "своему" объекту ядра. Например, если процесс S имеет доступ к объекту ядра и Вам нужно, чтобы к этому объекту мог обращаться процесс Т, используйте DuplicateHandle так:
// |
весь |
приведенный |
ниже |
код |
исполняется |
процессом |
S |
|
// |
создаем |
объект-мьютекс, |
доступный |
процессу |
S |
|||
HANDLE hObjProcessS = CreateMutex(NULL, FALSE, NULL); |
|
|
||||||
// |
открываем |
описатель |
объекта |
ядра |
"процесс |
Т" |
HANDLE |
hProcessT = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessIdT); |
|||
HANDLE |
hObjProcessT; |
// |
неинициализированный |
описатель, |
//связанный с процессом Т
//предоставляем процессу Т доступ к объекту-мьютексу
DuplicateHandle(GetCurrentProcess(), |
hObjProcessS, |
hProcessT, |
&hObjProcessT, 0, FALSE, DUPLICATE_SAME_ACCESS); |
|
![](/html/1549/349/html_zF3yk3EBC5.yf3l/htmlconvd-KH3qLD84x1.jpg)
// |
используем |
какую-нибудь форму |
межпроцессной связи, |
чтобы |
передать |
||
// значение описателя из hObjProcessS в процесс Т |
|
|
|
||||
// |
связь |
с |
процессом |
Т |
больше |
не |
нужна |
CloseHandle(hProcessT); |
|
|
|
|
|
// если процессу S не нужен объект-мьютекс, он должен закрыть его
CloseHandle(hObjProcessS);
Вызов GetCurrentProcess возвращает псевдоописатель, который всегда идентифицирует вызывающий процесс, в данном случае — процесс S. Как только функция DuplicateHandle возвращает управление, bObjProcessT становится описателем, связанным с процессом Т и идентифицирующим тот же объект, что и описатель bObjProcessS (когда на него ссылается код процесса S). При этом процесс S ни в коем случае не должен исполнять следующий код:
// |
процесс |
S |
никогда |
не |
должен |
пытаться |
исполнять |
код, |
// |
|
закрывающий |
|
продублированный |
описатель |
|||
CloseHandle(hObjProcessT); |
|
|
|
|
|
Если процесс S выполнит этот код, вызов может дать (а может и не дать) ошибку. Он будет успешен, если у процесса S случайно окажется описатель с тем же значением, что и в hObjProcessT. При этом процесс S закроет неизвестно какой объект, и что будет потом
— остается только гадать.
Теперь о другом способе применения DuplicateHandle. Допустим, некий процесс имеет полный доступ (для чтения и записи) к объекту "проекция файла" и из этого процесса вызывается функция, которая должна обратиться к проекции файла и считать из нее какие-то данные. Так вот, если мы хотим повысить отказоустойчивость
приложения, то могли бы с помощью DuplicateHandle создать новый описатель существующего объекта и разрешить доступ только для чтения. Потом мы передали бы этот описатель функции, и та уже не смогла бы случайно что-то записать в проекцию файла. Взгляните на код, который иллюстрирует этот пример:
int WINAPI WinMain(HINSTANCE hinstExe, HINSTANCE, PSTR pszCmdLine, int nCmdShow) {
//создаем объект "проекция файла",
//его описатель разрешает доступ как для чтения, так и для записи
HANDLE hFileMapRW = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
PAGE_READWRITE, 0, 10240, NULL);
//создаем другой описатель на тот же обьект;
//этот описатель разрешает дocтyп только для чтения