#c #windows #winapi #user-interface #registerclass
#c #Windows #winapi #пользовательский интерфейс #registerclass
Вопрос:
Я хотел бы спросить, почему при разработке графического интерфейса Windows с использованием API необходимо регистрировать класс window? Какова концепция этого?
Я уже прочитал первые 3 главы книги Чарльза Петцольда «Программирование Windows«, но мне все еще интересно, какова цель явной регистрации класса. Почему я должен хотеть сделать это явно? Почему это не выполняется в фоновом режиме, например, в функции CreateWindow() (или CreateWindowEx())? Я имею в виду, почему код, который RegisterClass() не выполняется внутри CreateWindow(), или почему CreateWindow() не вызывает сам RegisterClass()?
Я также читал документацию по MSDN и знаю, что функция RegisterClass() связывает оконную процедуру с классом window, заполняя структуру WNDCLASS. Я знаю, что это функция, которая обрабатывает сообщения из ОС, однако почему необходимо регистрировать эту функцию (WinProc) в классе внутри отдельной функции из CreateWindow()?
Я могу понять причины существования функции CreateWindow() и почему она автоматически не отображает созданное окно. Это означает, что я также понимаю назначение функции ShowWindow().
Я уверен, что для такого поведения должны быть веские причины, позволяющие программисту регистрировать класс, когда он хочет, я просто не вижу этих причин, и именно поэтому я прошу вас, ребята, пролить свет на эту тему.
Пожалуйста, имейте в виду, что я новичок в разработке графического интерфейса с Windows API. Я создал некоторые графические интерфейсы в MATLAB, которые, отличаясь от Windows API, все же позволили мне понять некоторые принципы Windows, в частности назначение функций обратного вызова. Я не знаю, полезна ли эта информация, но если вам нужно провести какие-то аналогии, пожалуйста, будьте моим гостем.
Комментарии:
1. Класс является шаблоном. Возможно, вы захотите, чтобы несколько окон имели один и тот же класс. Не говоря уже о том, что было бы сложнее сделать это в
CreateWindow
с такими классами, как «Button», которые уже есть.2. Ну, у RegisterClass есть что, дюжина параметров? (учитывая, что каждый элемент структуры WNDCLASS (EX) является параметром. И у CreateWindow (например) есть что, 8 параметров mas или menos (плюс или минус)? Разбиение его на два вызова упрощает жизнь. RegisterClass необходимо вызывать только один раз для ваших собственных классов WND и никогда для классов, зарегистрированных ОС, таких как EDIT, STATIC, LISTBOX и т.д. Вы бы предпочли каждый раз заполнять 20 параметров? Я уверен, что есть устаревшие причины, по которым Windows работала на 16 битах, а память была выгружена повсеместно.
3. Я уверен, что в блоге Рэймонда Чена может быть что-то интересное: blogs.msdn.microsoft.com/oldnewthing/20050418-59/?p=35873
Ответ №1:
Поскольку вы отметили свой вопрос C , я приведу вам аналогию с C …
RegisterClass
по сути, вы определяете класс и включаете его в свою программу (очень похоже на #include
в C ). WNDPROC
это ваш обработчик всего, что происходит в окне, если и когда создается экземпляр.
CreateWindow
концептуально это то же самое, что вы делаете new
в C . Вы просите Windows создать новое окно, и вы должны указать ему тип окна. Windows включает в себя набор предопределенных окон, таких как Button или Edit, но если вы хотите создать экземпляр своего собственного окна, тогда все в порядке, вам просто нужно указать ему «класс», который вы хотели бы создать. Вы уже зарегистрировали этот класс, вызвав RegisterClass
, поэтому Windows теперь может перейти прямо к определению и создать экземпляр вашего окна.
Комментарии:
1. Однако, вот моя мысль: когда мы используем RegisterClass(), мы фактически не определяем наш класс, мы просто присваиваем значения структуре (которые можно понимать как некоторые общедоступные свойства нашего класса). То же самое происходит, когда мы используем CreateWindow(), мы просто присваиваем значения некоторым другим свойствам. На самом деле, если мы подумаем о вашей аналогии, я считаю, что было бы логичнее изменить аргументы RegisterClass() и CreateWindow(): визуальные аспекты экземпляров класса должны быть почти одинаковыми (подумайте о кнопках и переключателях), возможно, изменив размер и цвет для
2. каждый экземпляр класса. Однако поведение, действия, которые должны выполняться каждым экземпляром, это то, что, скорее всего, будет отличаться для каждого экземпляра. Итак, я думаю так: поскольку визуальные аспекты (шаблон) должны быть очень похожими для каждого экземпляра, присвоите этим свойствам некоторые значения по умолчанию, т.Е. Измените аргументы CreateWindow() и RegisterClass(). Это было бы более логично, по крайней мере, для меня. Однако я знаю, что моя логика неверна, я просто не знаю, где.
3. Но если вы подумаете об этом, размер, положение и родительский элемент окна (который устанавливается CreateWindow) не имеют ничего общего с классом окна (как установлено RegisterClass). Аналогично, кто-то, создающий окно, не должен беспокоиться о том, какая функция обрабатывает сообщения, которые будут отправлены в это окно.
4. Я вижу, что если вы создаете элемент управления, может быть полезно связать поведение элемента управления с его классом window. Интересно, что диалоговые окна работают так, как вы предлагаете, где указано их поведение при их создании.
5. Диалоговое окно из класса WC_DIALOG. WNDPROC этого класса вызывает DLGPROC, который вы предоставляете, и способен анализировать шаблон диалога, переданный в CreateDialog. Вы могли бы сделать то же самое для элементов управления, то есть: написать свой «универсальный класс управления» и свою собственную функцию createControl.
Ответ №2:
Другой способ думать заключается в том, что Windows является закрытым исходным кодом, поэтому разработчики API не хотят, чтобы вы много знали о API. Итак, теперь они думают: «Что, если пользователь захочет создать свой собственный класс window со своим собственным поведением?». Вот почему WNDCLASS создан для того, чтобы пользователи могли объявлять информацию о классе, которая им нужна, присваивая значение, например, names, procedure в поле member. Это что-то вроде заполнения формы. Таким образом, вы можете видеть, что авторы API достигают 2 вещей:
(1) пользователи ничего не знают об API, поскольку они явно не расширяют классы API до пользовательских, потому что, если они это делают, поэтому авторы API должны предоставлять заголовки классов, и пользователи могут ошибиться с тем, что Windows больше не закрывается.
(2) пользователи по-прежнему могут определять свои собственные классы окон.
Теперь, после того как вы определили свой собственный класс window и хотите его использовать, вам нужно зарегистрировать класс, чтобы ОС Windows знала, что это за класс, чтобы они могли сохранять информацию о нем для дальнейшей необходимости, а затем вы можете создать его экземпляр.
Ответ №3:
Вам нужно RegisterClass, чтобы определить стиль, процедуру окна, которая необходима для программирования потока, которому принадлежит окно, для ответа на сообщения и события и делать что-то или ничего для каждого сообщения, которое получает окно, и для каждого происходящего события, значка вашего окна, курсора, который пользователь видит при наведении курсора на окно, фона клиента окна и меню Windows.
Как вы можете представить окно без всех этих свойств?
Может быть, вы спросите, почему все эти свойства окна не являются параметрами функции CreateWindow, поэтому я устанавливаю их с помощью функции CreateWindow, а не с помощью функции RegisterClass, верно?
Если все свойства окна являются параметрами функции CreateWindow, то функция CreateWindow очень сложна, а строка, которая вызывает CreateWindow должным образом, очень длинная.
Это делает код очень большим, менее читаемым и менее производительным.
RegisterClass значительно упрощает создание Windows.
Это одна из причин, по которой Microsoft хочет, чтобы разработчики Win32 сначала вызывали RegisterClass перед CreateWindow.
Также предположим, что вам нужны по крайней мере два окна с одинаковыми свойствами.
Вы выделяете только один экземпляр структуры WNDCLASS, устанавливаете его поля для установки общих свойств ваших окон и вызываете функцию RegisterClass только один раз, но вы вызываете CreateWindow столько раз, сколько необходимо для создания всех окон, которые вы хотите, но все с одинаковым именем класса.
RegisterClass не только значительно упрощает и укорачивает код, но и предотвращает дублирование одного и того же большого кода в CreateWindow.
RegisterClass также делает код более производительным.
Это отличный дизайн, позволяющий сначала выделить экземпляр WNDCLASS, задать его поля, вызвать функцию RegisterClass, а затем вызвать функцию CreateWindow столько раз, сколько вы хотите.
Хотя вам нужно вызвать RegisterClass несколько раз, если вы хотите Windows с разными свойствами, конечно.
Вам также придется изменять экземпляр WNDCLASS перед каждым вызовом функции RegisterClass.
Ответ №4:
Я думаю, что фактическая причина связана с классами системного окна:
«Многие системные классы доступны для использования всеми процессами, в то время как другие используются только внутри системы. Поскольку система регистрирует эти классы, процесс не может их уничтожить.» Источник:https://learn.microsoft.com/en-us/windows/win32/winmsg/about-window-classes
Обратите внимание по этой ссылке, что многие вещи в win32, которые считаются «виджетами» (такие как кнопки, панели инструментов, поля со списком и т.д.), На самом деле являются Windows, поскольку у них есть класс window. Они предоставляются системой и могут переопределять поведение, но их исходный код по умолчанию скрыт от прикладного программиста.