Сведения о классах окон
Каждый класс окна имеет связанную процедуру окна, которая совместно используется всеми окнами одного класса. Процедура window обрабатывает сообщения для всех окон этого класса и, следовательно, управляет их поведением и внешним видом. Дополнительные сведения см. в разделе Процедуры окна.
Процесс должен зарегистрировать класс окна, прежде чем он сможет создать окно этого класса. Регистрация класса окна связывает процедуру окна, стили классов и другие атрибуты класса с именем класса. Когда процесс задает имя класса в функции CreateWindow или CreateWindowEx , система создает окно с процедурой окна, стилями и другими атрибутами, связанными с этим именем класса.
В этом разделе рассматриваются следующие темы.
- Типы оконных классов
- Как система находит класс Window
- Регистрация класса Window
- Элементы класса Window
Типы оконных классов
Существует три типа классов окон:
Эти типы отличаются область, а также в том, когда и как они регистрируются и уничтожаются.
Системные классы
Системный класс — это класс окна, зарегистрированный системой. Многие системные классы доступны для использования всеми процессами, в то время как другие используются системой только внутри системы. Так как система регистрирует эти классы, процесс не может уничтожить их.
Система регистрирует системные классы для процесса, когда один из ее потоков впервые вызывает функцию User или Windows Graphics Device Interface (GDI).
Каждое приложение получает собственную копию системных классов. Все 16-разрядные приложения windows в одном VDM совместно используют системные классы, как и в 16-разрядной версии Windows.
В следующей таблице описаны системные классы, доступные для использования всеми процессами.
Класс | Описание |
---|---|
Кнопка | Класс для кнопки. |
ComboBox | Класс для поля со списком. |
Изменить | Класс для элемента управления "Редактирование". |
ListBox | Класс для списка. |
MDIClient | Класс для окна клиента MDI. |
ScrollBar | Класс для полосы прокрутки. |
Статические | Класс для статического элемента управления. |
В следующей таблице описаны системные классы, доступные только для использования системой. Они перечислены здесь для полноты.
Класс | Описание |
---|---|
ComboLBox | Класс для списка, содержащегося в поле со списком. |
DDEMLEvent | Класс для событий библиотеки DDEML. |
Сообщение | Класс для окна только для сообщений. |
#32768 | Класс для меню. |
#32769 | Класс для окна рабочего стола. |
#32770 | Класс для диалогового окна. |
#32771 | Класс для окна переключения задач. |
#32772 | Класс для заголовков значков. |
Глобальные классы приложения
Глобальный класс приложения — это класс окна, зарегистрированный исполняемым файлом или библиотекой DLL, который доступен для всех остальных модулей в процессе. Например, .dll может вызвать функцию RegisterClassEx для регистрации класса окна, который определяет пользовательский элемент управления в качестве глобального класса приложения, чтобы процесс, загружающий .dll, может создавать экземпляры пользовательского элемента управления.
Чтобы создать класс, который можно использовать в каждом процессе, создайте класс окна в .dll и загрузите .dll в каждом процессе. Чтобы загрузить .dll в каждом процессе, добавьте его имя в значение AppInit_DLLs в следующем разделе реестра:
HKEY_LOCAL_MACHINE\Программного обеспечения\Microsoft\\Windows Windows NTCurrentVersion\
При каждом запуске процесса система загружает указанный .dll в контексте только что запущенного процесса перед вызовом его функции точки входа. .dll должен зарегистрировать класс во время процедуры инициализации и указать стиль CS_GLOBALCLASS . Дополнительные сведения см. в разделе Стили классов.
Чтобы удалить глобальный класс приложения и освободить связанное с ним хранилище, используйте функцию UnregisterClass .
Локальные классы приложения
Локальный класс приложения — это любой класс окна, который исполняемый файл или .dll регистрирует для монопольного использования. Хотя можно зарегистрировать любое количество локальных классов, обычно регистрируется только один. Этот класс окна поддерживает процедуру окна main приложения.
Система уничтожает локальный класс при закрытии зарегистрированного модуля. Приложение также может использовать функцию UnregisterClass для удаления локального класса и освобождения связанного с ним хранилища.
Как система находит класс Window
Система поддерживает список структур для каждого из трех типов оконных классов. Когда приложение вызывает функцию CreateWindow или CreateWindowEx для создания окна с указанным классом, система использует следующую процедуру для поиска класса.
- Выполните поиск в списке локальных классов приложения для класса с указанным именем, дескриптор экземпляра которого соответствует дескриптору экземпляра модуля. (Несколько модулей могут использовать одно и то же имя для регистрации локальных классов в одном процессе.)
- Если имя отсутствует в списке локальных классов приложения, выполните поиск в списке глобальных классов приложения.
- Если имя отсутствует в списке глобальных классов приложения, выполните поиск в списке системных классов.
Все окна, созданные приложением, используют эту процедуру, включая окна, созданные системой от имени приложения, например диалоговые окна. Системные классы можно переопределить, не затрагивая другие приложения. То есть приложение может зарегистрировать локальный класс приложения с тем же именем, что и системный класс. Это заменяет системный класс в контексте приложения, но не запрещает другим приложениям использовать системный класс.
Регистрация класса Window
Класс window определяет атрибуты окна, такие как его стиль, значок, курсор, меню и процедура окна. Первым шагом при регистрации класса окна является заполнение структуры WNDCLASSEX сведениями о классе окна. Дополнительные сведения см. в разделе Элементы класса Window. Затем передайте структуру в функцию RegisterClassEx . Дополнительные сведения см. в разделе Использование оконных классов.
Чтобы зарегистрировать глобальный класс приложения, укажите стиль CS_GLOBALCLASS в элементе стиля структуры WNDCLASSEX . При регистрации локального класса приложения не указывайте стиль CS_GLOBALCLASS .
Если вы регистрируете оконный класс с помощью версии ANSI RegisterClassEx, RegisterClassExA, приложение запрашивает, чтобы система передала текстовые параметры сообщений в окна созданного класса с помощью кодировки ANSI; Если вы регистрируете класс с помощью версии Юникода RegisterClassEx, RegisterClassExW, приложение запрашивает, чтобы система передала текстовые параметры сообщений в окна созданного класса, используя кодировку Юникода. Функция IsWindowUnicode позволяет приложениям запрашивать характер каждого окна. Дополнительные сведения о функциях ANSI и Юникода см. в разделе Соглашения о прототипах функций.
Исполняемый файл или библиотека DLL, зарегистрировав класс, является владельцем класса . Система определяет владение классом из элемента hInstance структуры WNDCLASSEX, передаваемой функции RegisterClassEx при регистрации класса. Для библиотек DLL элемент hInstance должен быть дескриптором экземпляра .dll.
Класс не уничтожается при выгрузке .dll, которому он принадлежит. Таким образом, если система вызывает процедуру окна для окна этого класса, это приведет к нарушению доступа, так как .dll, содержащий процедуру окна, больше не находится в памяти. Процесс должен уничтожить все окна с помощью класса , прежде чем .dll будет выгружен и вызвать функцию UnregisterClass .
Элементы класса Window
Элементы класса window определяют поведение окон по умолчанию, принадлежащих классу . Приложение, которое регистрирует класс окна, назначает элементы классу, задавая соответствующие члены в структуре WNDCLASSEX и передавая структуру в функцию RegisterClassEx . Функции GetClassInfoEx и GetClassLong извлекают сведения о заданном классе окна. Функция SetClassLong изменяет элементы локального или глобального класса, уже зарегистрированного приложением.
Хотя полный класс window состоит из множества элементов, системе требуется только, чтобы приложение предоставлял имя класса, адрес процедуры окна и дескриптор экземпляра. Другие элементы используются для определения атрибутов по умолчанию для окон класса , таких как форма курсора и содержимое меню окна. Необходимо инициализировать все неиспользуемые члены структуры WNDCLASSEX равными нулю или NULL. Элементы класса window приведены в следующей таблице.
Элемент | Назначение |
---|---|
Имя класса | Отличает класс от других зарегистрированных классов. |
Адрес процедуры окна | Указатель на функцию, которая обрабатывает все сообщения, отправленные в окна в классе , и определяет поведение окна. |
Маркер экземпляра | Идентифицирует приложение или .dll, зарегистрировав класс . |
Курсор класса | Определяет курсор мыши, отображаемый системой для окна класса . |
Значки классов | Определяет большой и маленький значок. |
Кисть фона класса | Определяет цвет и узор, которые заполняют клиентную область при открытии или окрашении окна. |
Меню "Класс" | Задает меню по умолчанию для окон, которые явно не определяют меню. |
Стили класса | Определяет, как обновить окно после перемещения или изменения его размера, как обрабатывать двойные щелчки мыши, как выделить место для контекста устройства и другие аспекты окна. |
Дополнительная память класса | Указывает объем дополнительной памяти (в байтах), которую система должна зарезервировать для класса . Все окна в классе используют дополнительную память и могут использовать ее для любых целей, определенных приложением. Система инициализирует эту память до нуля. |
Дополнительная память окна | Указывает объем дополнительной памяти (в байтах), который система должна резервировать для каждого окна, относящегося к классу . Дополнительную память можно использовать для любых целей, определенных приложением. Система инициализирует эту память до нуля. |
Имя класса
Каждому классу окна требуется имя класса , чтобы отличать один класс от другого. Назначьте имя класса, задав члену lpszClassName структуры WNDCLASSEX адрес строки, заканчивающейся null, которая указывает имя. Так как классы окон зависят от процесса, имена классов окон должны быть уникальными только в рамках одного процесса. Кроме того, поскольку имена классов занимают место в частной таблице atom системы, строки имен классов должны быть максимально короткими.
Функция GetClassName извлекает имя класса, которому принадлежит заданное окно.
Адрес процедуры окна
Каждому классу требуется адрес window-procedure, чтобы определить точку входа в процедуру окна, используемую для обработки всех сообщений для окон в классе . Система передает сообщения в процедуру, когда требуется, чтобы окно выполняло задачи, такие как рисование клиентской области или реагирование на входные данные от пользователя. Процесс назначает процедуру окна классу, копируя ее адрес в член lpfnWndProc структуры WNDCLASSEX . Дополнительные сведения см. в разделе Процедуры окна.
Маркер экземпляра
Для каждого класса window требуется дескриптор экземпляра для идентификации приложения или .dll, которые зарегистрировали класс . Системе требуются дескрипторы экземпляров для отслеживания всех модулей. Система назначает дескриптор каждой копии выполняемого исполняемого файла или .dll.
Система передает дескриптор экземпляра функции точки входа каждого исполняемого файла (см . раздел WinMain) и .dll (см. DllMain). Исполняемый файл или .dll назначает этот дескриптор экземпляра классу, копируя его в элемент hInstance структуры WNDCLASSEX .
Курсор класса
Курсор класса определяет форму курсора, когда он находится в клиентской области окна класса . Система автоматически присваивает курсору заданную фигуру, когда курсор входит в клиентскую область окна, и гарантирует, что он сохраняет эту фигуру, оставаясь в клиентской области. Чтобы назначить фигуру курсора классу окна, загрузите предопределенную фигуру курсора с помощью функции LoadCursor , а затем назначьте возвращенный дескриптор курсора члену hCursor структуры WNDCLASSEX . Кроме того, укажите пользовательский ресурс курсора и используйте функцию LoadCursor , чтобы загрузить его из ресурсов приложения.
Системе не требуется курсор класса. Если приложение задает элементу hCursor структуры WNDCLASSEXзначение NULL, курсор класса не определяется. Система предполагает, что окно задает фигуру курсора каждый раз, когда курсор перемещается в окно. Окно может задать фигуру курсора, вызывая функцию SetCursor всякий раз, когда окно получает сообщение WM_MOUSEMOVE . Дополнительные сведения о курсорах см. в разделе Курсоры.
Значки классов
Значок класса — это изображение, которое система использует для представления окна определенного класса. Приложение может иметь два значка класса — один большой и один маленький. Система отображает большой значок класса окна в окне переключения задач, которое появляется при нажатии клавиш ALT+TAB, а также в представлениях больших значков панели задач и обозревателя. Маленький значок класса отображается в строке заголовка окна, а также в небольших представлениях значков панели задач и обозревателя.
Чтобы назначить большой и маленький значок классу окна, укажите дескрипторы значков в членах hIcon и hIconSm структуры WNDCLASSEX . Размеры значков должны соответствовать требуемым измерениям для значков больших и малых классов. Для большого значка класса можно определить необходимые измерения, указав значения SM_CXICON и SM_CYICON в вызове функции GetSystemMetrics . Для значка небольшого класса укажите значения SM_CXSMICON и SM_CYSMICON . Дополнительные сведения см. в разделе Значки.
Если приложение присваивает членам hIcon и hIconSm структуры WNDCLASSEXзначение NULL, система использует значок приложения по умолчанию в качестве значков большого и малого классов для класса окна. Если указать большой значок класса, но не маленький, система создаст маленький значок класса на основе большого. Однако если указать небольшой значок класса, но не большой, система использует значок приложения по умолчанию в качестве значка большого класса и указанный значок в качестве значка малого класса.
Вы можете переопределить большой или маленький значок класса для определенного окна с помощью сообщения WM_SETICON . Текущий значок большого или малого класса можно получить с помощью сообщения WM_GETICON .
Кисть фона класса
Фоновая кисть класса подготавливает клиентную область окна для последующего рисования приложением. Система использует кисть для заполнения клиентской области сплошным цветом или узором, тем самым удаляя все предыдущие изображения из этого места независимо от того, принадлежат ли они окну или нет. Система уведомляет окно о том, что его фон должен быть закрашен, отправляя WM_ERASEBKGND сообщение в окно. Дополнительные сведения см. в разделе Brushes.
Чтобы назначить классу фоновую кисть, создайте кисть с помощью соответствующих функций GDI и назначьте возвращенный дескриптор кисти члену hbrBackground структуры WNDCLASSEX .
Вместо создания кисти приложение может задать элементу hbrBackground одно из стандартных системных значений цвета. Список стандартных системных значений цветов см. в разделе SetSysColors.
Чтобы использовать стандартный системный цвет, приложение должно увеличить значение цвета фона на один. Например, COLOR_BACKGROUND + 1 — это цвет фона системы. Кроме того, можно использовать функцию GetSysColorBrush , чтобы получить дескриптор к кисти, соответствующий стандартному системному цвету, а затем указать дескриптор в элементе hbrBackground структуры WNDCLASSEX .
Системе не требуется, чтобы класс окна был фоновой кистью класса. Если для этого параметра задано значение NULL, окно должно закрашивать собственный фон всякий раз, когда получает сообщение WM_ERASEBKGND .
Меню "Класс"
Меню класса определяет меню по умолчанию, которое будет использоваться окнами в классе, если при создании окон явное меню не задано. Меню — это список команд, из которых пользователь может выбрать действия для выполнения приложением.
Вы можете назначить меню классу, задав для элемента lpszMenuName структуры WNDCLASSEX адрес строки, завершившей значение NULL, которая указывает имя ресурса меню. Предполагается, что меню является ресурсом в данном приложении. При необходимости система автоматически загружает меню. Если ресурс меню идентифицируется по целочислению, а не по имени, приложение может задать для элемента lpszMenuName это целое число, применив макрос MAKEINTRESOURCE перед присвоением значения.
Системе не требуется меню классов. Если приложение задает элементу lpszMenuName структуры WNDCLASSEXзначение NULL, окна в классе не имеют строк меню. Даже если меню класса не задано, приложение по-прежнему может определить строку меню для окна при создании окна.
Если для класса задано меню и создается дочернее окно этого класса, меню игнорируется. Дополнительные сведения см. в разделе Меню.
Стили класса
Стили классов определяют дополнительные элементы класса window. Два или более стилей можно объединить с помощью побитового оператора OR (|). Чтобы назначить стиль классу окна, назначьте стиль члену стиля структуры WNDCLASSEX . Список стилей классов см. в разделе Стили классов окна.
Классы и контексты устройств
Контекст устройства — это специальный набор значений, используемый приложениями для рисования в клиентской области окон. Системе требуется контекст устройства для каждого окна на дисплее, но она обеспечивает некоторую гибкость в том, как система хранит и обрабатывает этот контекст устройства.
Если стиль контекста устройства явно не задан, система предполагает, что каждое окно использует контекст устройства, полученный из пула контекстов, поддерживаемых системой. В таких случаях каждое окно должно извлекать и инициализировать контекст устройства перед рисованием и освобождать его после рисования.
Чтобы избежать получения контекста устройства каждый раз, когда необходимо закрасить внутри окна, приложение может указать стиль CS_OWNDC для класса окна. Этот стиль класса предписывает системе создать контекст частного устройства, то есть выделить уникальный контекст устройства для каждого окна в классе. Приложению нужно получить контекст только один раз, а затем использовать его для всего последующего рисования.
Дополнительная память класса
Система внутренне поддерживает структуру WNDCLASSEX для каждого класса окна в системе. Когда приложение регистрирует класс окна, оно может направить систему на выделение и добавление нескольких дополнительных байтов памяти в конец структуры WNDCLASSEX . Эта память называется дополнительной памятью класса и совместно используется всеми окнами, принадлежащими к классу . Используйте дополнительную память класса для хранения любой информации, относящейся к классу.
Так как из локальной кучи системы выделяется дополнительная память, приложение должно использовать память дополнительного класса экономно. Функция RegisterClassEx завершается сбоем, если запрошенный объем дополнительной памяти класса превышает 40 байт. Если приложению требуется более 40 байт, оно должно выделить собственную память и сохранить указатель на память в дополнительном классе памяти.
Функции SetClassWord и SetClassLong копируют значение в дополнительную память класса. Чтобы получить значение из дополнительной памяти класса, используйте функции GetClassWord и GetClassLong . Член cbClsExtra структуры WNDCLASSEX указывает объем выделяемой памяти дополнительного класса. Приложение, которое не использует дополнительную память класса, должно инициализировать член cbClsExtra равным нулю.
Дополнительная память окна
Система поддерживает внутреннюю структуру данных для каждого окна. При регистрации класса окна приложение может указать количество дополнительных байтов памяти, называемое дополнительной памятью окна. При создании окна класса система выделяет и добавляет указанный объем дополнительной памяти окна в конец структуры окна. Приложение может использовать эту память для хранения данных, относящихся к окну.
Так как из локальной кучи системы выделяется дополнительная память, приложение должно использовать дополнительную память окна. Функция RegisterClassEx завершается ошибкой, если запрошенный объем дополнительной памяти окна превышает 40 байт. Если приложению требуется более 40 байт, оно должно выделить собственную память и сохранить указатель на память в дополнительном окне.
Функция SetWindowLong копирует значение в дополнительную память. Функция GetWindowLong извлекает значение из дополнительной памяти. Элемент cbWndExtra структуры WNDCLASSEX указывает объем выделяемой дополнительной памяти окна. Приложение, которое не использует память, должно инициализировать cbWndExtra до нуля.