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

Тема 5. Механизм сообщений в операционных системах

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

План лекции

Учебные вопросы

  • Консольная модель vs событийный оконный GUI
  • Класс окна (WNDCLASSEXW) и дескриптор HWND
  • Анатомия структуры MSG, WPARAM и LPARAM
  • Поток RIT, очереди потока и главный цикл выборки
  • Синхронный SendMessage vs асинхронный PostMessage
  • Системный ввод мыши и клавиатуры (WM_CHAR)

Цели занятия

  • Освоить концепцию инверсии управления (IoC)
  • Изучить регистрацию и параметры оконного класса
  • Разобрать внутреннее устройство структуры сообщения MSG
  • Понять работу очередей потока и синтетических флагов
  • Освоить построение циклов с GetMessage и PeekMessage
  • Изучить механизмы хит-тестинга и трансляции символов
Механизм сообщений в операционных системах
Системное программирование

Консольная парадигма против событийного GUI

Консольная модель (Линейная)

  • Программа жестко управляет потоком выполнения
  • Блокирующий ввод: scanf усыпляет поток до нажатия Enter
  • Невозможно параллельно реагировать на действия пользователя
  • Монопольное исполнение без интерактивности

Событийная модель (GUI)

  • Инверсия управления (Inversion of Control):
    • ОС управляет главным потоком событий
    • Программа регистрирует функции обратного вызова
  • Цикл сообщений: непрерывный опрос очереди
  • Отзывчивый интерфейс и параллельная обработка окон
Механизм сообщений в операционных системах
Системное программирование

Парадигмы программирования: Консоль vs Событийный GUI

center

Механизм сообщений в операционных системах
Системное программирование

Архитектура оконного класса: WNDCLASSEXW

Понятие класса окна

  • Окно не может быть создано без предварительно зарегистрированного класса
  • Задает общие атрибуты окон данного типа
  • Регистрируется вызовом RegisterClassExW

Ключевые поля WNDCLASSEXW

  • lpfnWndProc: указатель на оконную процедуру (Callback)
  • style: стили перерисовки (CS_HREDRAW | CS_VREDRAW)
  • hInstance: дескриптор загруженного модуля
  • hCursor, hIcon: системный курсор и пиктограмма
  • lpszClassName: уникальное имя класса в системе
Механизм сообщений в операционных системах
Системное программирование

Архитектура оконного класса и создание окна (HWND)

center

Механизм сообщений в операционных системах
Системное программирование

Предопределенные оконные классы

Стандартные элементы управления

  • Все элементы управления Windows — это полноценные окна HWND
  • Создаются вызовом CreateWindowExW со стилями WS_CHILD | WS_VISIBLE
  • Имеют встроенную стандартную процедуру окна внутри USER32.DLL

Базовые предопределенные классы

  • L"BUTTON": командные кнопки, чекбоксы, радиокнопки
  • L"EDIT": однострочные и многострочные поля ввода текста
  • L"STATIC": текстовые надписи, рамки и изображения
  • L"LISTBOX": списки элементов с выбором
  • L"COMBOBOX": комбинированные выпадающие списки
Механизм сообщений в операционных системах
Системное программирование

Дополнительные данные окна: GetWindowLongPtrW

Проблема связывания с C++

  • WndProc в Си обязана быть статической функцией
  • Не может напрямую обращаться к нестатическим полям класса C++
  • Требуется безопасный механизм доступа к указателю this

Системное решение UserData

// Сохранение указателя this при WM_CREATE:
SetWindowLongPtrW(hwnd, GWLP_USERDATA, 
    (LONG_PTR)pThis);

// Извлечение объекта внутри WndProc:
MyWindow *pWnd = (MyWindow*)
    GetWindowLongPtrW(hwnd, GWLP_USERDATA);

if (pWnd) {
    return pWnd->HandleMessage(uMsg, wParam, lParam);
}
Механизм сообщений в операционных системах
Системное программирование

Анатомия оконного сообщения: структура MSG

Поля структуры MSG

typedef struct tagMSG {
    HWND   hwnd;    // Окно-получатель
    UINT   message; // Идентификатор (ID)
    WPARAM wParam;  // Параметр (Word)
    LPARAM lParam;  // Параметр (Long)
    DWORD  time;    // Системное время
    POINT  pt;      // Координаты мыши
} MSG;

Назначение WPARAM и LPARAM

  • WM_SIZE: wParam — тип изменения; lParam хранит width (LOWORD) и height (HIWORD)
  • WM_LBUTTONDOWN: wParam — флаги кнопок (MK_CONTROL); lParam хранит XX и YY
  • WM_COMMAND: LOWORD(wParam) — ID элемента, HIWORD(wParam) — код события
Механизм сообщений в операционных системах
Системное программирование

Классификация и анатомия оконных сообщений

center

Механизм сообщений в операционных системах
Системное программирование

Очереди сообщений потока и Raw Input Thread

Роль потока Raw Input Thread (RIT)

  • Системный поток реального времени в ядре win32k.sys
  • Считывает аппаратные прерывания клавиатуры и мыши
  • Выполняет хит-тестинг: определяет окно под курсором
  • Маршрутизирует ввод в аппаратную очередь целевого потока

Структура очереди потока

  1. Очередь отложенных сообщений (Posted Queue): FIFO буфер для сообщений PostMessage
  2. Очередь аппаратного ввода: события мыши и клавиатуры
  3. Синтетические флаги:
    • WM_PAINT — взводится при инвалидации области
    • WM_TIMER — взводится по таймеру
    • Обрабатываются только при пустых очередях 1 и 2!
Механизм сообщений в операционных системах
Системное программирование

Архитектура очередей и главный цикл сообщений

center

Механизм сообщений в операционных системах
Системное программирование

Синхронная и асинхронная отправка сообщений

Сравнение SendMessage и PostMessage

Свойство PostMessageW() SendMessageW()
Тип Асинхронный Синхронный
Очередь В хвост очереди В обход очереди
Блокировка Немедленно (0 мс) Блокирует поток
Результат BOOL (успех) LRESULT из WndProc
Потоки Безопасен Опасность дедлока

Практическое применение

  • PostMessage: безопасное уведомление GUI из фоновых рабочих потоков
  • SendMessage: мгновенный опрос дочерних элементов или получение статуса контролов
  • Опасность: вызов SendMessage между двумя GUI-потоками может вызвать взаимную блокировку!
Механизм сообщений в операционных системах
Системное программирование

Главный цикл выборки сообщений

Блокирующий цикл: GetMessage

MSG msg;
// Возвращает 0 только при WM_QUIT
while (GetMessageW(&msg, NULL, 0, 0) > 0) {
    // Генерация WM_CHAR из скан-кодов
    TranslateMessage(&msg);
    // Вызов оконной процедуры msg.hwnd
    DispatchMessageW(&msg);
}
return (int)msg.wParam;
  • Поток спит в ядре, если сообщений нет (0% нагрузки ЦПУ)

Неблокирующий цикл: PeekMessage

while (true) {
    if (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) {
        if (msg.message == WM_QUIT) break;
        TranslateMessage(&msg);
        DispatchMessageW(&msg);
    } else {
        RenderNextFrame(); // Рендеринг / логика
    }
}
Механизм сообщений в операционных системах
Системное программирование

Оконная процедура и функция DefWindowProc

Структура функции WndProc

LRESULT CALLBACK MainWindowProc(
    HWND hwnd, UINT uMsg, 
    WPARAM wParam, LPARAM lParam) 
{
    switch (uMsg) {
    case WM_PAINT: {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        // Рисование графики...
        EndPaint(hwnd, &ps);
        return 0;
    }
    case WM_DESTROY:
        PostQuitMessage(0); // Выход
        return 0;
    default:
        // Обязательная передача в ОС!
        return DefWindowProcW(hwnd, 
            uMsg, wParam, lParam);
    }
}

Важность DefWindowProcW

  • Выполняет базовую системную обработку сотен служебных сообщений Windows
  • Отвечает за анимацию рамки, системное меню, отрисовку неклиентской зоны
  • Пропуск DefWindowProcW приводит к зависанию окна!
Механизм сообщений в операционных системах
Системное программирование

Обработка сообщений мыши в системном API

Клиентские сообщения мыши

  • Генерируются при нахождении курсора над рабочей областью окна
  • WM_MOUSEMOVE: перемещение мыши
  • WM_LBUTTONDOWN / WM_LBUTTONUP: нажатие и отпускание ЛКМ
  • WM_RBUTTONDOWN: контекстные действия (ПКМ)
  • WM_MOUSEWHEEL: дельта вращения колеса мыши

Извлечение координат курсора

case WM_LBUTTONDOWN: {
    int x = GET_X_LPARAM(lParam);
    int y = GET_Y_LPARAM(lParam);
    UINT flags = (UINT)wParam; // MK_CONTROL
    // Обработка клика в точке (x, y)...
    return 0;
}
Механизм сообщений в операционных системах
Системное программирование

Захват мыши и неклиентские события

Механизм захвата мыши (SetCapture)

  • По умолчанию сообщения мыши привязаны к окну под курсором
  • При перетаскивании (Drag-and-Drop) курсор может покинуть границы окна
  • SetCapture(hwnd): направляет все сообщения мыши окну, даже вне экрана
  • ReleaseCapture(): обязательно вызывается при отпускании кнопки

Хит-тестинг: WM_NCHITTEST

  • Опрашивает окно: «В какой зоне находится курсор?»
  • HTCLIENT: рабочая область
  • HTCAPTION: заголовок (перетаскивание)
  • HTCLOSE: кнопка закрытия [X]
  • Возврат HTCAPTION в теле клиентской зоны позволяет перетаскивать окно за любое место!
Механизм сообщений в операционных системах
Системное программирование

Обработка клавиатурного ввода

Уровни обработки ввода

  1. Аппаратные скан-коды (Scan Codes):
    • Номера контактов микроконтроллера клавиатуры
    • Зависят от физической модели устройства
  2. Виртуальные коды (Virtual-Key Codes, VK_*):
    • Аппаратно-независимые системные константы
    • VK_LEFT, VK_RIGHT, VK_F1, VK_RETURN, VK_SPACE

Системные сообщения клавиш

  • WM_KEYDOWN: физическое нажатие клавиши; код клавиши передается в wParam
  • WM_KEYUP: отпускание клавиши
  • WM_SYSKEYDOWN: нажатия системных комбинаций (с клавишей Alt)
Механизм сообщений в операционных системах
Системное программирование

Фокус ввода и текстовый ввод: WM_CHAR

Генерация символов: TranslateMessage

  • WM_KEYDOWN не содержит символа с учетом раскладки и регистра
  • Функция TranslateMessage(&msg) сопоставляет скан-код, раскладку и Shift/Caps
  • Синтезирует сообщение WM_CHAR и ставит его в очередь потока
  • В wParam передается готовый код UTF-16 (wchar_t)

Фокус клавиатурного ввода

  • Сообщения клавиатуры направляются только окну с фокусом
  • WM_SETFOCUS: окно получило фокус ввода
  • WM_KILLFOCUS: окно потеряло фокус (переключение на другой элемент)
  • Программная установка: SetFocus(hwnd)
Механизм сообщений в операционных системах
Системное программирование

Резюме лекции

Классы и очереди

  • Архитектура GUI построена на инверсии управления (IoC)
  • WNDCLASSEXW связывает класс окна с оконной процедурой (lpfnWndProc)
  • Поток RIT транслирует аппаратные прерывания в очереди потоков
  • WM_PAINT и WM_TIMER — синтетические флаги низкого приоритета

Сообщения и ввод

  • PostMessage ставит сообщение в очередь; SendMessage вызывает WndProc напрямую
  • GetMessage обеспечивает энергоэффективный сон; PeekMessage — неблокирующий опрос
  • Пропуск DefWindowProcW приводит к фатальному зависанию окна
  • TranslateMessage преобразует скан-коды в символы Юникода WM_CHAR
Механизм сообщений в операционных системах
Системное программирование

Вопросы для самопроверки

Вопросы 1–5

  1. В чем заключается фундаментальная разница между консольной и событийно-ориентированной парадигмой?
  2. Какую роль играет структура WNDCLASSEXW и почему окно нельзя создать без класса?
  3. Каким образом SetWindowLongPtrW связывает дескриптор HWND с объектом класса C++?
  4. Какие поля входят в структуру MSG и какую информацию несут WPARAM и LPARAM?
  5. В чем разница между диапазонами WM_USER, WM_APP и строковыми сообщениями?

Вопросы 6–10

  1. За какие задачи отвечает системный поток Raw Input Thread (RIT) в ядре Windows?
  2. Почему сообщение WM_PAINT называется синтетическим и когда оно извлекается?
  3. В чем заключается принципиальная разница в поведении SendMessage и PostMessage?
  4. Что произойдет с окном, если в WndProc не передавать сообщения в DefWindowProc?
  5. Каким образом функция TranslateMessage формирует символьные сообщения WM_CHAR?
Механизм сообщений в операционных системах
Системное программирование

Литература и рекомендуемые ресурсы

Учебная литература

  • Устройство и функционирование OC Windows — Коньков К. А. М.: Бином, 2008. 208 с.
  • Современные операционные системы (4-е изд.) — Таненбаум Э., Бос Х. СПб.: Питер, 2021. 1119 с.
  • Операционные системы (2-е изд.) — Гордеев А. В. СПб.: Питер, 2009. 415 с.
  • Программирование для Windows 95 (в 2-х томах) — Петцольд Ч. СПб.: BHV, 1997.

Документация и справочники

Механизм сообщений в операционных системах

Лекция №5. Цель: сформировать детальное понимание событийно-ориентированной модели операционных систем, архитектуры оконных классов, механизмов очередей сообщений потока, работы системного потока RIT, синхронной и асинхронной диспетчеризации, а также обработки событий мыши и клавиатуры на уровне системного API. Связь с предыдущими темами: опирается на Тему 2 (процессы и потоки) и Тему 3 (объекты ядра и примитивы взаимодействия). Связь с практической работой: теоретическая база для лабораторной работы №4 "Обработка сообщений. Очереди сообщений".

План ориентирован на освоение низкоуровневой механики оконной подсистемы USER32 и WIN32K.

Подчеркнуть: переход от активного опроса к функциям обратного вызова (Голливудский принцип).

Слева — линейная блокирующая модель консоли, справа — цикл выборки и оконная процедура GUI.

Оконный класс связывает строковое имя типа окна с функцией-обработчиком lpfnWndProc.

Схема регистрации класса, фабрики окон CreateWindowExW и связывания дескриптора HWND.

Предопределенные классы предоставляют готовые оконные процедуры стандартных элементов Windows.

SetWindowLongPtrW сохраняет указатель на C++ объект прямо в структуре WND в памяти ядра.

Параметры wParam и lParam полиморфны и интерпретируются в зависимости от кода сообщения message.

Иерархия: системные сообщения, пользовательские диапазоны WM_USER, WM_APP и строковые IPC.

Синтетические сообщения WM_PAINT имеют низший приоритет и не перегружают очередь потока.

Схема: аппаратный ввод через RIT, очереди потока, цикл выборки и прямой обходной вызов SendMessage.

SendMessage выполняет синхронный RPC-вызов оконной процедуры; опасен взаимными блокировками.

GetMessage оптимален для стандартного GUI, PeekMessage — для игр и рендеринга реального времени.

DefWindowProcW — системная реализация по умолчанию, обеспечивающая штатное поведение окна.

Координаты мыши упакованы в 32 бита LPARAM и извлекаются макросами GET_X_LPARAM / GET_Y_LPARAM.

SetCapture гарантирует получение WM_LBUTTONUP при отпускании за пределами окна.

WM_KEYDOWN фиксирует факт нажатия аппаратной кнопки, но еще не знает печатного символа.

TranslateMessage превращает аппаратно-зависимый скан-код в готовый символ Юникода WM_CHAR.

Подвести итог: механизм сообщений — кровеносная система графического интерфейса Windows.

Опросить слушателей по различиям Send/PostMessage, роли RIT и структуре MSG.

Завершить лекцию, объявить тему следующего занятия (Тема 6. Графический интерфейс пользователя).