Поделиться через


Сведения о процедурах окна

Каждое окно является членом определенного класса окна. Класс окна определяет процедуру окна по умолчанию, которую использует отдельное окно для обработки сообщений. Все окна, принадлежащие одному классу, используют одну и ту же процедуру окна по умолчанию. Например, система определяет процедуру окна для класса поля со списком (COMBOBOX); затем все поля со списком используют эту процедуру окна.

Обычно приложение регистрирует по крайней мере один новый класс окна и связанную с ней процедуру окна. После регистрации класса приложение может создать множество окон этого класса, все из которых используют одну и ту же процедуру окна. Так как это означает, что несколько источников могут одновременно вызывать один и тот же фрагмент кода, необходимо быть осторожным при изменении общих ресурсов из процедуры окна. Дополнительные сведения см. в классах окон .

Процедуры окна для диалоговых окон (называемые процедурами диалогового окна) имеют аналогичную структуру и функцию как обычные процедуры окна. Все точки, ссылающиеся на процедуры окна в этом разделе, также применяются к процедурам диалогового окна. Дополнительные сведения см. в диалоговых окнах.

В этом разделе рассматриваются следующие разделы.

Структура оконной процедуры

Процедура окна — это функция, которая имеет четыре параметра и возвращает подписанное значение. Параметры состоят из дескриптора окна, идентификатора сообщения UINT и двух параметров сообщения, объявленных WPA RAM и типах данных LPARAM. Дополнительные сведения см. в разделе WindowProc.

Параметры сообщения часто содержат сведения как в их словах с низким порядком, так и в высоком порядке. Существует несколько макросов, которые приложение может использовать для извлечения информации из параметров сообщения. Макрос LOWORD, например, извлекает младшее слово (биты от 0 до 15) из параметра сообщения. Другие макросы включают HIWORD, LOBYTEи макросов HIBYTE.

Интерпретация возвращаемого значения зависит от конкретного сообщения. Ознакомьтесь с описанием каждого сообщения, чтобы определить соответствующее возвращаемое значение.

Так как можно вызывать процедуру окна рекурсивно, важно свести к минимуму количество локальных переменных, которые он использует. При обработке отдельных сообщений приложение должно вызывать функции за пределами оконной процедуры, чтобы избежать чрезмерного использования локальных переменных, что может привести к переполнению стека при глубокой рекурсии.

Процедура окна по умолчанию

Функция процедуры окна по умолчанию DefWindowProc определяет определенное базовое поведение, общее для всех окон. Процедура окна по умолчанию предоставляет минимальные функциональные возможности для окна. Процедура окна, определяемая приложением, должна передавать любые сообщения, которые она не обрабатывает, в функцию DefWindowProc для обработки по умолчанию.

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

При создании окна система выделяет блок памяти для хранения сведений, относящихся к окну, включая адрес процедуры окна, обрабатывающей сообщения для окна. Когда системе нужно передать сообщение в окно, он выполняет поиск сведений о окне для адреса процедуры окна и передает сообщение этой процедуре.

Подклассификация — это метод, позволяющий приложению перехватывать и обрабатывать сообщения, отправленные в определённое окно, прежде чем оно сможет их обработать. Подклассив окно, приложение может расширить, изменить или отслеживать поведение окна. Приложение может подклассить окно, принадлежащее системным глобальным классам, например элементу управления редактирования или списку. Например, приложение может подклассить элемент управления редактирования, чтобы запретить элементу управления принимать определенные символы. Однако вы не можете подклассить окно или класс, принадлежащий другому приложению. Все подклассы должны выполняться в рамках одного процесса.

Приложение подклассирует окно, заменив адрес исходной процедуры окна адресом новой процедуры окна, называемой процедурой подкласса . После этого процедура подкласса получает все сообщения, отправленные в окно.

Процедура подкласса может выполнить три действия при получении сообщения: оно может передать сообщение исходной процедуре окна, изменить сообщение и передать его в исходную процедуру окна или обработать сообщение и не передать его исходной процедуре окна. Если процедура подкласса обрабатывает сообщение, оно может сделать это до, после или до и после передачи сообщения в исходную процедуру окна.

Система предоставляет два типа подклассов: экземпляр и глобальный. В случае подклассификации экземпляра, приложение заменяет адрес процедуры единственного экземпляра окна. Приложение должно использовать подкласс экземпляра для подкласса существующего окна. В глобальном подклассеприложение заменяет адрес процедуры окна в структуре WNDCLASSEX класса окна. Все последующие окна, созданные с помощью класса, имеют адрес процедуры подкласса, но существующие окна класса не затрагиваются.

Подкласс экземпляра

Приложение подклассифицирует экземпляр окна, используя функцию SetWindowLongPtr. Приложение передает флаг GWL_WNDPROC, дескриптор окна, которое необходимо подклассировать, и адрес процедуры подкласса в SetWindowLongPtr. Процедура подкласса может находиться в исполняемом файле приложения или библиотеке DLL.

При передаче флага GWL_WNDPROCSetWindowLongPtr возвращает адрес исходной процедуры окна. Приложение должно сохранить этот адрес, используя его в последующих вызовах функции CallWindowProc, чтобы передать перехватанные сообщения исходной процедуре окна. Приложение также должно иметь исходный адрес процедуры окна, чтобы удалить подкласс из окна. Чтобы удалить подкласс, приложение вызывает SetWindowLongPtr еще раз, передавая адрес исходной процедуры окна с флагом GWL_WNDPROC и дескриптор окна.

Система владеет системными глобальными классами, а аспекты элементов управления могут измениться с одной версии системы на следующую. Если приложение должно подклассить окно, которое принадлежит системным глобальным классам, разработчик может потребоваться обновить приложение при выпуске новой версии системы.

Поскольку субклассирование экземпляра выполняется после создания окна, в окно нельзя добавить дополнительные байты. Приложения, которые используют подклассы окна, должны использовать список свойств окна для хранения любых данных, необходимых для экземпляра этого подклассифицированного окна. Для получения дополнительной информации см. свойства окна.

Когда приложение подклассирует окно, содержащее подклассы, оно должно удалить подклассы в обратном порядке их выполнения. Если порядок удаления не отменен, может возникнуть неустранимая системная ошибка.

Глобальный подкласс

Для создания глобального подкласса класса окна приложение должно иметь дескриптор окна этого класса. Приложению также требуется дескриптор для удаления подкласса. Чтобы получить дескриптор, приложение обычно создает скрытое окно класса, который будет подвергаться подклассификации. После получения дескриптора приложение вызывает функцию SetClassLongPtr, указав дескриптор, флаг GCL_WNDPROC и адрес процедуры подкласса. SetClassLongPtr возвращает адрес исходной процедуры окна для класса.

Исходный адрес процедуры окна используется в глобальном подклассировании таким же образом, как и в подклассировании экземпляра. Процедура подкласса передает сообщения исходной процедуре окна путем вызова CallWindowProc. Приложение удаляет подкласс из класса окна, вызывая SetClassLongPtr еще раз, указав адрес исходной процедуры окна, флаг GCL_WNDPROC и дескриптор окна класса, из которого удаляется подкласс. Приложение, которое глобально подклассирует класс элемента управления, должно удалить подкласс при завершении работы приложения; В противном случае может возникнуть неустранимая системная ошибка.

Глобальный подкласс имеет те же ограничения, что и подклассы экземпляров, а также некоторые дополнительные ограничения. Приложение не должно использовать дополнительные байты для класса или экземпляра окна, не зная точно, как используется исходная процедура окна. Если приложение должно связать данные с окном, оно должно использовать свойства окна.

Суперклассирование обработчика окна

Суперклассификация — это техника, позволяющая приложению создавать новый оконный класс с базовой функциональностью существующего класса, плюс усовершенствования, предоставляемые приложением. Суперкласс основан на существующем классе окна, называемом базовым классом . Часто базовый класс — это системный глобальный класс окна, например элемент управления редактированием, но он может быть любым классом окна.

Суперкласс имеет собственную процедуру окна, называемую процедурой суперкласса. Процедура суперкласса может выполнить три действия при получении сообщения: он может передать сообщение в исходную процедуру окна, изменить сообщение и передать его в исходную процедуру окна или обработать сообщение и не передать его в исходную процедуру окна. Если процедура суперкласса обрабатывает сообщение, оно может сделать это до, после или до и после того, как оно передает сообщение исходной процедуре окна.

В отличие от процедуры подкласса, процедура суперкласса может обрабатывать сообщения о создании окна (WM_NCCREATE, WM_CREATEи т. д.), но она также должна передавать их исходной процедуре окна базового класса, чтобы процедура окна базового класса могла выполнять свою процедуру инициализации.

Для суперкласса класса окна приложение сначала вызывает функцию getClassInfoEx, чтобы получить сведения о базовом классе. GetClassInfoEx заполняет структуру WNDCLASSEX значениями из структуры WNDCLASSEX базового класса. Затем приложение копирует собственный дескриптор экземпляра в член hInstance структуры WNDCLASSEX и копирует имя суперкласса в член lpszClassName. Если базовый класс имеет меню, приложение должно предоставить новое меню с теми же идентификаторами меню и скопировать имя меню в элемент lpszMenuName. Если процедура суперкласса обрабатывает сообщение WM_COMMAND и не передает его в процедуру окна базового класса, меню не требует соответствующих идентификаторов. GetClassInfoEx не возвращает lpszMenuName, lpszClassNameили hInstance члена структуры WNDCLASSEX.

Приложение также должно задать элемент lpfnWndProc структуры WNDCLASSEX. Функция GetClassInfoExзаполняет этот элемент адресом исходной процедуры окна для класса. Приложение должно сохранить этот адрес, передать сообщения в исходную процедуру окна, а затем скопировать адрес суперклассовой процедуры в элемент lpfnWndProc. При необходимости приложение может изменять любые другие член ы структуры WNDCLASSEX. После заполнения структуры WNDCLASSEX приложение регистрирует суперкласс, передав адрес структуры функции RegisterClassEx. Затем суперкласс можно использовать для создания окон.

Поскольку использование суперклассов регистрирует новый класс окна, приложение может добавить как к дополнительным байтам класса, так и к дополнительным байтам окна. Суперкласс не должен использовать исходные дополнительные байты для базового класса или окна по тем же причинам, что подкласс экземпляра или глобальный подкласс не должен использовать их. Кроме того, если приложение добавляет дополнительные байты для использования в класс или экземпляр окна, он должен ссылаться на дополнительные байты относительно количества дополнительных байтов, используемых исходным базовым классом. Так как количество байтов, используемых базовым классом, может отличаться от одной версии базового класса к следующей, начальная смещение для собственных дополнительных байтов суперкласса может также отличаться от одной версии базового класса к следующей.