Что такое класс окна windows

Что такое класс окна windows

Прикладная программа, когда создается окно, должна предоставить следующую информацию:

В разделах ниже описываются эти атрибуты.

Каждое окно принадлежит определенному классу окна. Прикладная программа должна зарегистрировать класс окна перед созданием любого окна этого класса. Класс окна (window class) определяет большинство аспектов внешнего вида и поведения. Главный компонент класса окна — это оконная процедура (window procedure), функция которой получать и обрабатывать все вводимые данные и запросы, посланные окну. Окна предоставляют входные данные и запросы в форме сообщений (messages). Для большей информации о классах окна, оконных процедурах или сообщениях смотрите Классы окна, Оконные процедуры или Сообщения и Очереди сообщений.

Окно может иметь имя. Имя окна (window name) (называемое также оконный текст (window text)) — это текстовая строка, которая идентифицирует окно для пользователя. Главное окно, диалоговое окно или окно сообщения, если представлено, обычно показывает свое имя окна в своей строке заголовка. Для элемента управления внешний вид имени окна зависит от класса элементов управления. Кнопка, поле редактирования или статический элемент управления отображают свое оконное имя внутри прямоугольника, который занимает элемент управлением. Окно со списком, комбинированное окно или статический элемент управления не показывают имя своего окна.

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

Каждое окно имеет один или несколько стилей окна. Стиль окна (window style) — это име-нованная константа, которая определяет аспекты внешнего вида и поведения окна, которые не определяет класс окна. Например, класс SCROLLBAR создает линейку прокрутки, а стили SBS_HORZ и SBS_VERT определяют создание или горизонтальной или вертикальной линейки прокрутки. Несколько стилей окна применяют все окна, но большинство их применяют окна конкретного класса окна. Окна и, до некоторой степени, оконная процедура класса, интерпретируют стили.

Родительское или самостоятельное окно

Окно может иметь родительское окно. Окно, которое имеет родительское окно, называется дочерним окном (child window). Родительское окно (parent window) предоставляет систему координат, которая используется для позиционирования дочернего окна. Наличие родительского окна воздействует на аспекты внешнего вида окна; например, дочернее окно обрезается так, что-бы ни одна часть дочернего окна не могла появиться вне рамок своего родительского окна. Окно, у которого нет родительского окна или родитель которого самое главное окно, называется окном верхнего уровня (top-level window). Прикладная программа использует функцию EnumWindows, чтобы получить дескриптор каждого из своих окон верхнего уровня. Функция EnumWindows, в свою очередь, передает дескриптор каждого окна верхнего уровня в определенную программой функцию повторного вызова EnumWindowsProc.

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

Расположение, размер и позиция в Z-последовательности

Каждое окно имеет расположение, размер и позицию в Z-последовательности. Расположение — это координаты верхнего левого угла окна, относительно верхнего левого угла экрана или, в случае дочернего окна, верхнего левого угла рабочей области родителя. Размер окна — это его ширина и высота, измеряемая в пикселях. Позиция окна в Z-последовательности (Z order) — это позиция окна в стеке перекрывающихся окон. Для получения дополнительной информации, см «1.6 Z-последовательность (Z Order)».

Идентификатор Дочернего окна или дескриптор Меню

Дочернее окно может иметь идентификатор дочернего окна (child-window identifier), уникальное значение определенное программой, связанное с дочерним окном. Идентификаторы дочернего окна особенно полезны в прикладных программах, которые создают многочисленные дочерние окна. При создании дочернего окна, прикладная программа определяет идентификатор дочернего окна. После создания окна, прикладная программа может изменять идентификатор окна, используя функцию SetWindowLong, или может отыскать идентификатор, используя функцию GetWindowLong.

Читайте также:  Как остановить обновление системы windows 10

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

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

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

Первая программа на WinAPI

WinAPI или Windows API (Application Programming Interface) — это библиотека для создания классических приложений Windows. Сама библиотека WinAPI написана на языке C и представляет собой коллекцию функций, структур и констант. Она объявлена в определённых заголовочных файлах и реализована в статических (.lib) и динамических (.dll) библиотеках.

В данном уроке мы создадим нашу первую программу на WinAPI. Для начала создайте проект. Выберите меню File -> New -> Project:

В открытом окне в левой панели выберите Other, затем Empty Project (пустой проект). Там же доступен шаблон Windows Desktop Application, но мы напишем программу с нуля, так как шаблон по умолчанию пока слишком сложен для нас. В нижней части выберите имя проекта, его местоположение и хотите ли вы создать решение для него. Местоположение может быть любым, для меня это C:\prog\cpp\

В обозревателе решений щёлкните правой кнопкой мышки и выберите Add -> New Item.

В открывшемся окне выберите C++ File (.cpp) и введите имя файла в нижней части — main.cpp.

Перед тем как мы начнём рассматривать код, давайте поговорим о типах данных в WinAPI и соглашениях вызова (calling conventions).

Типы данных в WinAPI

WinAPI переопределяет множество стандартных типов языка C. Некоторые переопределения зависят от платформы для которой создаётся программа. Например, тип LRESULT, если его скомпилировать для x86, будет типом long. Но если скомпилировать программу для x64, то LRESULT будет типом __int64. Вот так LRESULT определяется на самом деле (он зависит от LONG_PTR, а LONG_PTR может уже быть или __int64, или long):

Соглашения по вызову (Calling Conventions) — __stdcall

В коде ниже перед именами функций вы встретите __stdcall. Это одно из соглашений по вызову функций. Соглашение по вызову функций определяет каким образом аргументы будут добавляться в стек. Для __stdcall аргументы помещаются в стек в обратном порядке — справа налево. Также, __stdcall говорит, что после того как функция завершится, она сама (а не вызывающая функция) удалит свои аргументы из стека. Все функции WinAPI используют __stdcall соглашение.

WinAPI переопределяет __stdcall в WINAPI, CALLBACK или APIENTRY, которые используются в разных ситуациях. Поэтому в примерах из MSDN вы не увидите __stdcall, но нужно помнить что именно оно будет использоваться.

Типы WinAPI пишутся в верхнем регистре.

Описатели/дескрипторы (Handles) в WinAPI

Handle на русский язык сложно перевести однозначно. Наверное, наиболее частое употребление в русском имеет слово дескриптор. По сути это ссылка на ресурс в памяти. Например, вы создаёте окно. Это окно хранится в памяти и оно имеет запись в таблице, которая хранит указатели на все созданные системные ресурсы: окна, шрифты, файлы, картинки. Указатель на ваше окно в данной таблице называется дескриптором окна (handle of the window).

Любой указатель это просто переопределение типа void*. Примеры дескрипторных типов в WinAPI: HWND, HINSTANCE, HBITMAP, HCURSOR, HFILE, HMENU.

Подытожим: дескрипторы используются для получения доступа к каким-либо системным ресурсам.

Читайте также:  Kak windows movie maker

WinAPI окна

Давайте посмотрим на код самой простой WinAPI программы:

Вначале нужно добавить WinAPI: статичную библиотеку, которая содержит определения различных функций и включить заголовочный файл с объявлениями этих функций, структур и констант. user32.lib содержит основные возможности Windows — всё, что касается окон и обработки событий.

На следующей строке мы объявляем функцию обратного вызова (callback), которая будет вызываться, когда наше приложение получает какое-либо сообщение от операционной системы. Мы вернёмся к этому ниже.

Функция WinMain

WinMain — точка входа в программу, а как мы помним такая функция вызывается операционной системой.

Главная функция приложений под Windows отличается от консольной версии. Она возвращает целое число и это всегда ноль. __sdtcall говорит, что аргументы добавляются в стек в обратном порядке и WinMain сама удаляет их из стека по завершении. WinMain принимает 4 аргумента:

hInstance — дескриптор экземпляра приложения. Можете думать о нём, как о представлении вашего приложения в памяти. Он используется для создания окон.

Второй аргумент — наследие шестнадцатибитных версий Windows. Уже давно не используется.

Третий аргумент представляет аргументы командной строки. Пока мы не будем им пользоваться.

nCmdShow — специальный флаг, который можно использовать при создании окон. Он говорит о состоянии окна: должно ли оно показываться нормально, на полный экран или быть свёрнутым.

Теперь давайте посмотрим как создаются окна.

Классы окон (Window Classes)

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

Сначала нужно заполнить структуру WNDCLASS. Пусть вас не смущает название WNDCLASS — это не C++ класс. В данном случае, класс — всего лишь термин используемый в WinAPI:

Здесь мы инициализируем структуру WNDCLASS нулями, определяем обязательные поля и регистрируем класс.

lpfnWndProc имеет тип WNDPROC. Как говорилось выше, это указатель на функцию WindowProc, которую мы объявили в самом начале. У каждого оконного класса должна быть своя оконная процедура.

hInstance — дескриптор экземпляра приложения. Все оконные классы должны сообщать, какое приложение их зарегистрировало. Мы используем первый параметр функции WinMain.

lpszClassName — имя класса, задаётся пользователем. В Windows все классы называются в верхнем регистре (примеры: BUTTON, EDIT, LISTBOX), мы будем делать также в наших уроках.

WNDCLASS содержит больше полей: стиль, иконка, имя меню, но мы можем пропустить их. Некоторые из них мы рассмотрим в следующих уроках. Вы можете посмотреть полный список в документации к WinAPI на MSDN (официальном сайте Microsoft с документацией).

В конце мы регистрируем наш класс с помощью функции RegisterClass. Мы передаём адрес структуры WNDCLASS. Теперь мы можем создать окно.

Первая WinAPI программа — Пустое окно

В WinAPI есть функция для создания окон — CreateWindow:

Первый параметр — имя класса. В данном случае он совпадает с именем класса, который мы зарегистрировали. Второй — имя окна, это та строка, которую пользователи программы будут видеть в заголовке. Следующий — стиль. WS_OVERLAPPEDWINDOW говорит, что WinAPI окно имеет заголовок (caption), кнопки сворачивания и разворачивания, системное меню и рамку.

Четыре числа определяют позицию левого верхнего угла окна и ширину/высоту.

Затем идут два указателя nullptr. Первый — дескриптор родительского окна, второй — меню. У нашего окна нет ни того, ни другого.

hInstance — дескриптор на экземпляр приложения, с которым связано окно.

В последний аргумент мы передаём nullptr. Он используется для специальных случаев — MDI (Multiple Document Interface ) — окно в окне.

CreateWindow возвращает дескриптор окна. Мы можем использовать его для обращения к окну в коде. Теперь мы можем показать и обновить окно.:

ShowWindow (показать окно) использует параметр nCmdShow функции WinMain для контроля начального состояния (развёрнуто на весь экран, минимизировано, обычный размер). UpdateWindow (обновить окно) мы обсудим в следующих уроках.

Читайте также:  Internet explorer для windows media player

Главный цикл WinAPI

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

Перед циклом мы объявляем переменную типа MSG (от message — сообщение) — в этой структуре Windows кодирует события. Если произошло событие WM_QUIT, то мы завершаем цикл.

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

Очередь сообщений (Message Queue) в WinAPI

Все оконные приложения управляются событиями (event-driven). В операционной системе существует очередь сообщений. Когда происходит какое-либо событие в любой программе, в эту очередь посылается сообщение. Также, любая программа имеет свою очередь сообщений. Windows проверяет каждое сообщение в системной очереди и посылает их в программные очереди. В действительности всё немного сложнее, так как очереди сообщений связаны с потоками, но мы обсудим это позже. На данный момент запомните, что каждое приложение имеет свою собственную очередь сообщений.

Сообщение это просто структурная переменная MSG. Давайте посмотрим на определение этой структуры:

hwnd — дескриптор окна, которому принадлежит сообщение.

message — идентификатор сообщения (UINT — unsigned integer).

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

time — понятно из названия — время, когда было создано сообщение.

pt — позиция курсора на экране в момент генерации сообщения. POINT — тип WinAPI для описания точек с координатами (x,y).

Приложение в бесконечном цикле проверяет свою очередь сообщений, смотрит на свойство message и решает, что делать с данным сообщением (как его обработать).

Функция PeekMessage проверяет очередь и берёт последнее сообщение. Затем, она берёт информацию о сообщении и помещает её в переменную msg. Последний аргумент заставляет удалить сообщение из очереди.Итак, в условии мы проверяем, содержит ли очередь сообщений приложения какое-либо сообщение. Если содержит, мы заполняем переменную msg и удаляем сообщение из очереди. Затем вызываем две функции.

TranslateMessage — генерирует дополнительное сообщение если произошёл ввод с клавиатуры (клавиша с символом была нажата или отпущена). По умолчанию, клавиатура генерирует так называемые сообщения виртуального ключа (virtual key). TranslateMessage генерирует ещё одно сообщение, которое сообщает информацию о символе. Мы поговорим об этом позже. Пока что: вызов TranslationMessage нужен, чтобы обработать ввод символов с клавиатуры.

Функция DispatchMessage посылает сообщение в функцию WindowProc.

Оконная процедура (Window Procedure) WindowProc

Оконная процедура — это специальная функция в которой мы обрабатываем сообщения. В данный момент нам нужно обработать только одно важное сообщение, а для всех остальных выполнить стандартное действие. Давайте посмотрим на наш вариант WindowProc:

Обратите внимание, что мы сами нигде не вызываем WindowProc. Оконная процедура привязана к классу окна. И когда мы вызываем DispatchMessage, система сама вызывает оконную процедуру, связанную с окном. Такие функции называются функциями обратного вызова (callback functions) — они не вызываются напрямую. Также обратите внимание, что данная функция получает только часть свойств MSG структуры.

Внутри WindowProc мы проверяем поле message структуры MSG. Оно содержит идентификатор сообщения. В Windows определено много констант для разных сообщений. В данной программе мы проверяем WM_DESTROY. Это сообщение посылается, когда окно уничтожается, в момент, когда оно уже удалено с экрана. В ответ на это сообщение мы вызываем PostQuitMessage — она говорит системе, что приложение будет закрыто и посылает сообщение WM_QUIT в очередь сообщений программы (не в системную).

Если пришло сообщение, которое мы не хотим обрабатывать сами, мы передаём его в DefWindowProc — действие по умолчанию.

Заключение

В данном уроке мы создали пустое но полностью функциональное стандартное окно операционной системы Windows. В следующих уроках мы обсудим разные части WinAPI, а шаблон из данного урока станет основой для наших программ на DirectX и OpenGL.

Оцените статью