- •Содержание
- •Часть 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.3. Создание рабочего потока
В первую очередь нужно написать так называемую “функцию рабочего потока”, тело которой и содержит операции, выполняемые рабочим потоком. Прототип функции одинаков для всех потоков
DWORD WINAPI ThreadFunc (LPVOID pData);
Имя функции рабочего потока не имеет значения, поскольку, как и для оконной процедуры, Windows использует ее адрес, а не имя. Все функции рабочего потока имеют только один параметр типа LPVOID. Следовательно, чтобы передать в функцию несколько параметров из вызывающего процесса, нужно определить собственную структуру, заполнить поля и передать ее адрес через pData.
Особенность функции рабочего потока состоит в том, что при выходе из нее поток автоматически завершается.
Используйте именно этот путь для окончания рабочего потока, а не принудительное завершение через специальные функции Win32 API. Это может быть источником трудноуловимых ошибок межпотокового взаимодействия.
Непосредственное создание рабочего потока происходит в момент вызова Win32 API функции CreateThread(), которая имеет прототип:
HANDLE CreateThread( SECURITY_ATTRIBUTES* pThreadAttr, DWORD dwStackSize, THREAD_START_ROUTINE* pThreadFunc, LPVOID pData, DWORD dwFlags, LPDWORD pIdThread);
Первый параметр обычно не используется и равен NULL, второй – определяет размер стека для рабочего потока. Если он равен 0, Windows сама определяет необходимый размер. Третий параметр – это указатель на функцию рабочего потока, а четвертый – указатель блока памяти, который будет передан в ThreadFunc(). Флаг активизации рабочего потока обычно равен 0, что означает немедленный запуск потока. Через последний указатель буден возвращен идентификатор созданного потока. Однако больший интерес представляет дескриптор потока, возвращаемый функцией CreateThread(). Он позволяет вызывающему процессу проводить некоторые манипуляции с запущенными потоками.
Ниже представлен фрагмент кода, выполняющий запуск рабочего потока:
HANDLE hThread; DWORD idThread; THREAD_PARAM params; // .... hThread = ::CreateThread(NULL, 0, ThreadFunc, ¶ms, 0, &idThread); if (!hThread) { // ошибки создания потока }
Здесь THREAD_PARAM – некоторая структура, которая определяется в приложении. Она служит для передачи набора параметров в функцию потока.
Этот фрагмент содержит потенциальную ошибку, суть которой объяснена ниже.
При выходе из блока, запустившего поток, происходит разрушение локальных переменных params и hThread. Но уже запущенный поток не может “знать” об этом, он продолжает пользоваться данными из блока памяти, которого уже нет! Последствия этого – непредсказуемы.
Дескриптор hThread необходим для корректного освобождения ресурсов потока после его завершения следующим образом:
CloseHandle(hThread);
Выходом из сложившейся ситуации является объявление параметров params и hThread как глобальные или статические переменные.
12.4. Организация взаимодействия потоков
Как уже отмечалось, главная трудность технологии многопотокового программирования – это организация взаимодействия потоков. Приложение должно иметь возможность дуплексного обмена информацией. Это означает, что данные должны передаваться как от рабочего потока к процессу или, другими словами, в главный поток, так и в обратном направлении – от процесса в рабочий поток.