- •Содержание
- •Часть 1. Общие сведения о технологии программирования 5
- •Часть 2. Windows программирование 24
- •Введение
- •Часть 1. Общие сведения о технологии программирования
- •1. Задачи технологии программирования
- •1.1. Базовые определения
- •1.2. Невозможность доказательства отсутствия программных ошибок
- •1.3. Надежность программного средства
- •1.4. Технология программирования как способ создания надежных программных средств
- •1.5. Этапы развития технологии программирования
- •1.6. Технология программирования и информатизация общества
- •2. Общие принципы разработки программных средств
- •2.1. Специфика разработки программных средств
- •2.2. Основные подходы при создании пс
- •2.3. Жизненный цикл программного средства
- •2.4. Понятие качества программного средства
- •2.5. Обеспечение надежности – основной критерий разработки программных средств
- •2.5.1. Методы борьбы со сложностью
- •2.5.2. Обеспечение точности перевода
- •2.5.3. Преодоление барьера между пользователем и разработчиком
- •2.5.4. Контроль принимаемых решений
- •3. Архитектура программного средства
- •3.1. Понятие архитектуры программного средства
- •3.2. Основные классы архитектур программных средств
- •3.3. Архитектурные функции
- •4. Тестирование и отладка программного средства
- •4.1. Основные понятия
- •4.2. Принципы и виды отладки программного средства
- •4.3. Заповеди отладки программного средства
- •4.4. Автономная отладка программного средства
- •4.5. Комплексная отладка программного средства.
- •Часть 2. Windows программирование
- •5. Основные характеристики Windows платформ
- •5.1. Краткая история Windows
- •5.2. Отличия и общие свойства Windows платформ
- •5.2.1. Общие свойства Windows платформ
- •5.2.2. Отличия Win32 платформ
- •5.2.3. Окна и сообщения
- •5.2.4. Приложения, потоки и окна
- •5.2.5. Классы окон
- •5.2.6. Венгерская нотация
- •5.2.7. Типы сообщений
- •5.2.8. Сообщения и многозадачность
- •5.2.9. Очереди сообщений
- •5.2.10. Процессы и потоки
- •5.2.11. Потоки и сообщения
- •5.2.12. Оконная функция – функция обратного вызова
- •5.2.13. Синхронные и асинхронные сообщения
- •5.2.14. Функции Windows
- •5.2.15. Другие api
- •6. Структура Windows приложений
- •6.1. Файлы заголовков
- •6.2. Глабальные переменные
- •6.3. Точка входа в приложение
- •6.4. Необходимые переменные
- •6.5. Регистрация класса окна
- •6.6. Создание главного окна
- •6.7. Отображение главного окна
- •6.8. Цикл обработки сообщений
- •6.9. Функция окна
- •7. Обработка сообщений в оконной функции
- •7.1. Создание окна wm_create
- •7.2. Определение размера окна wm_size
- •7.3. Отображение содержимого окна wm_paint
- •7.3.1. Случаи генерации сообщения wm_paint
- •7.3.2. Особенность сообщения wm_paint
- •7.3.3. Правила обработки wm_paint
- •7.3.4. Отрисовка вне wm_paint
- •7.3.5. Определение возможностей контекста устройства
- •7.3.6. Системные метрики
- •7.4. Определение расположения окна wm_move
- •7.5. Использование оконных полос прокрутки
- •7.5.1. Диапазон и положение полос прокрутки
- •7.5.2. Сообщения полос прокрутки
- •7.6. Клавиатурный ввод
- •7.6.1. Фокус ввода и активное окно
- •7.6.2. Генерация клавиатурных сообщений
- •7.6.3. Аппаратные сообщения
- •7.6.3.1. Системные аппаратные сообщения
- •7.6.3.2. Несистемные аппаратные сообщения
- •7.6.3.3. Битовые поля параметра lParam
- •7.6.3.4. Виртуальные коды клавиш
- •7.6.4. Символьные сообщения
- •7.6.5. Обработка сообщения wm_char
- •7.6.6. Определение состояния управляющих клавиш
- •7.6.7. Наборы символов
- •7.7. Системный таймер
- •7.7.1. Использование таймера. Первый способ
- •7.7.2. Использование таймера. Второй способ
- •7.8. Удаление окна, сообщение wm_destroy
- •8. Ресурсы приложения и их использование
- •8.1. Меню приложения
- •8.1.1. Виды меню
- •8.1.2. Возможные состояния пунктов меню
- •8.1.3. Сообщения от пунктов меню
- •8.1.4. Создание главного меню приложения
- •8.1.5. Функции для работы с меню
- •8.2. Стандартные элементы управления
- •8.2.1. Создание стандартных элементов управления
- •8.2.2. Разрушение элементов управления
- •8.2.3. Функции для работы с элементами управления
- •8.2.4. Сообщения дочерних окон
- •8.2.5. Сообщения родительского окна дочерним окнам
- •8.2.6. Расширенное управление дочерними окнами
- •8.2.7. Оконные процедуры элементов управления
- •8.2.8. Элемент управления кнопка
- •8.2.8.1. Стили кнопок
- •8.2.8.2. Сообщения от кнопок, получаемые родительским окном
- •8.2.8.3. Сообщения от родительского окна к кнопке
- •8.2.8.4. Кнопки-переключатели
- •8.2.8.5. Сообщение от переключателей
- •8.2.8.6. Сообщение от родительского окна к переключателям
- •8.2.9. Структура drawitemstruct
- •8.2.10. Стандартный элемент управления окно ввода
- •8.2.10.1. Стили окна редактирования
- •8.2.10.2. Сообщения от редактора к родительскому окну
- •8.2.10.3. Сообщения от родительского окна к редактору
- •8.2.11. Стандартный элемент управления статический текст
- •8.2.11.1. Стили элемент управления static
- •8.2.11.2. Сообщения от статического элемента управления
- •8.2.11.3. Сообщения от родительского окна к static
- •8.2.12. Стандартный элемент управления список
- •8.2.12.1. Стили элемента управления список
- •8.2.12.2. Сообщения от списка к родительскому окну
- •8.2.12.3. Сообщения от родительского окна к списку
- •8.2.13. Стандартный элемент управления список с вводом
- •8.2.13.1. Стили элемента управления combobox
- •8.2.13.2. Сообщения от combobox к родительскому окну
- •8.2.13.3. Сообщения от родительского окна к combobox
- •9. Создание и использование диалоговых окон
- •9.1. Этапы создания диалога
- •9.1.1. Создание шаблона диалога
- •9.1.2. Функция диалога
- •9.1.2.1. Сходства между диалоговой функцией и оконной процедурой
- •9.1.2.2. Различия между диалоговой функцией и оконной процедурой
- •9.2. Типы диалоговых панелей
- •9.3. Создание модального диалога
- •9.4. Закрытие модального диалога
- •9.5. Окна сообщений.
- •9.6. Немодальные диалоги
- •9.7. Диалоговые окна общего пользования
- •10. Управление файлами
- •10.1. Доступ к файловой системе
- •10.2. Потоковый ввод/вывод
- •10.3. Функции ядра Windows для работы с файлами
- •10.4. Специализированные функции для работы с файлами
- •11. Печать документов
- •11.1. Последовательность печати документа
- •11.2. Контекст устройства принтера
- •11.3. Диалог отмены печати
- •11.4. Запуск процесса печати
- •11.5. Печать страницы документа
- •11.6. Завершение печати документа
- •12. Процессы и потоки
- •12.1. Диспетчеризация потоков
- •12.2. Проблемы многопоточной технологии
- •12.3. Создание рабочего потока
- •12.4. Организация взаимодействия потоков
- •12.4.1. Рабочий поток – процесс
- •12.4.2. Процесс – рабочий поток
- •12.5. Общая схема взаимодействия потоков
- •13. Приложение "Тестер файлов"
- •13.1. Функция WinMain()
- •13.2. Функция главного окна
- •13.3. Вспомогательные функции
- •13.4. Функция рабочего потока
- •Литература к первой части
- •Литература ко второй части
12.4.1. Рабочий поток – процесс
С первым направлением взаимодействия особых трудностей не возникает, поскольку здесь работает посылка сообщений. Напомним, что главный поток имеет функцию окна и, следовательно, может принимать сообщения от рабочего потока. Но какие сообщения? В заголовочном файле windows.h определена константа WM_USER, которая является верхней границей сообщений, используемых Windows для служебных целей. Это означает, что все истинные Windows сообщения имеют номера, меньшие чем WM_USER. Следовательно, для своих внутренних целей приложение безопасно может использовать сообщения со значением WM_USER+n, где n>0. При этом операционной системой гарантируется, что это не приведет к нежелательному эффекту коллизии сообщений, т.е. наложению одного на другое.
Как отправлять сообщения – синхронно или асинхронно? Ответ едиственный. Следует использовать только асинхронную передачу через функцию PostMessage(), подразумевая, что в любой момент работа потока может быть прервана.
12.4.2. Процесс – рабочий поток
Рассмотрим типичные ситуации.
Рабочий поток должен начать обработку некоторых данных только после того, как эти данные будут подготовлены другим потоком. Как уведомить рабочий поток о том, что информация уже готова к обработке?
В силу каких-либо причин, рабочий поток должен немедленно завершить свою работу. Как сообщить ему об этом? Конечно, можно использовать принудительное снятие потока, но это, как правило, приводит к нежелательным побочным эффектам.
Подобные примеры можно продолжать, но уже ясно, что рабочий поток не может принимать сообщения, т.к. он не имеет функции окна.
1. Для координации действий потоков в такого рода ситуациях в Win32 предусмотрены специальные формы синхронизации. Одной из таких форм являются события (events). Объект событие может находиться только в двух состояниях: установлено и сброшено. Сам по себе объект событие не представляет интереса, он используется только в комбинации со специальными Win32 функциями ожидания.
Дескриптор на объект событие возвращает функция CreateEvent():
HANDLE CreateEvent( SECURITY_ATTRIBUTES* pEventAttr, BOOL bManualReset, BOOL bInitialState, LPCTSTR lpName); //только для разных процессов
Здесь: указатель pEventAttr, как правило, равен NULL; переменная bManualReset определяет режим управления событием – вручную (TRUE) или автоматически (FALSE); переменная bInitialState задает стартовое состояние объекта – установлено (TRUE) или сброшено (FALSE).
Событие может быть именованным, тогда параметр lpName должен указывать на константную строку. Это имя используется в случае, когда требуется синхронизировать два или более процессов. Для взаимодействия процесс – рабочий поток данное имя не требуется, поэтому можно использовать NULL указатель.
Напомним, что все созданные или открытые Windows объекты требуют закрытия функцией:
CloseHandle((HANDLE)hObject);
когда отпадает необходимость в их использовании.
2. Второй трудностью межпотокового взаимодействия является доступ к разделяемым данным. Допустим, один поток модифицирует какие-то данные, а в это же время второй поток их читает. Если первый поток не завершил свои изменения, то второй получит неверные значения. Наилучший способ предотвратить такую ситуацию – это использование критических секций (critical sections), которые представляют собой разделы кода, во время выполнения которого текущий поток не может быть прерван, а все остальные переводятся в состояние ожидания.
Критическая секция должна быть проинициализирова, после чего функция
EnterCriticalSection(&cs);
начинает критическую секцию cs, а функция
LeaveCriticalSection(&cs);
завершает ее. При этом Windows гарантирует, что код программы, заключенный между этими двумя вызовами будет выполняться как бы в монопольном режиме, т.е. тогда, когда остальные потоки данного приложения будут «заморожены».
3. Следует упомянуть о третьей трудности, которая связана с динамическим захватом памяти в рабочем потоке. Эта проблема проявляется тогда, когда, возникает необходимость иметь постоянную область памяти, уникальную для каждого потока. Win32 API предоставляет ряд функций, поддерживающих такую специфическую память, которая называется локальной памятью потока (thread local storage или TLS). Однако лучшим решением следует признать пересмотр алгоритма решения задачи, и полный отказ от такого захвата в потоке.