Оконные windows приложения это

Обновлено: 01.07.2024

Всем привет! Продолжаем с вами изучать компьютерную грамотность. И если вы читали мои предыдущие статьи, то тогда вы уже много знаете и умеете.

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

А для тех, кто уже имеет представление об этом тоже будет неплохо ознакомиться с этим материалом.

Почему? Спросите вы.

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

А в этой самой статье мы как раз и рассмотрим их.

И так приступим.

Что это такое

Как мы уже знаем из одной из предыдущих статей – Windows в переводе означает «окна».

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


И как наверно вы уже заметили, чтобы вы не открыли это, отображается в прямоугольной области. Вот эта область и называется окно.

Основные виды

В зависимости от тех задач, которые предстоит выполнить пользователю окна можно подразделить на следующие виды;

  • Программные (приложений)
  • Документы
  • Запросов
  • Контекстных меню
  • Диалоговые
  • Активные

Программные (приложений)

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



Более подробно о компьютерных программах и приложениях можете почитать здесь.

Документы

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

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

Ярким примером является документ Word.


Запросы

Они появляются поверх всех остальных во время работы за ПК. В них отображаются запросы на подтверждение тех или иных действий или содержит запрос на определенную информацию.

Для них существует два действия предоставить ответ на запрос или подтвердить действие, или просто закрыть.

Еще их называют диалоговые, а они в свою очередь могут быть:

Модальные – это окна после появления которых блокируется приложение, и чтобы продолжить работу здесь следует завершить все действия.


По предложенным действиям их можно подразделить на три типа:

  • Требуется ввести определенную информацию
  • Оповещает пользователя о каких-либо совершённых действиях
  • Предлагает завершить или продолжить работу приложения

Немодальные – после появления приложение продолжает работать. Его можно свернуть или закрыть и продолжить работу в приложении.

Контекстное меню

Этот вид окон скрыт от глаз пользователей и вывести их можно нажатием правой кнопкой мыши. Они могут содержать дополнительные команды для программ и приложений.


Всплывающие

В основном они используются системой для информирования или с требованием совершить то или иное действие.


А также они часто появляются при работе в веб – браузерах при посещении различных сайтов. Но их появление можно легко запретить в настройках браузера.

Давайте я расскажу коротко об этих настройках на примере Яндекс.Браузера

Переходим в настройки


Ищем «сайты» и жмем на «расширенные настройки сайтов»


Ставим галочку «разрешены» или «запрещены»


Но эти вопросы мы будем рассматривать в рубрике «Освоение интернета» когда будем с вами изучать веб-браузеры. Так что подписывайтесь на обновления блога чтобы не пропустить.

О том, как это сделать можете почитать здесь.

Активные

Активным окном называют то которое расположено поверх остальных и в котором мы на данный момент работаем. Также можно встретить такое название как «рабочее окно».

При работе с несколькими окнами переключаться между ними можно с помощью мыши или горячих клавиш клавиатуры.

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

Теперь давайте переходить непосредственно к работе.

Работа с окнами Windows

Любое окно включает в себя элементы управления. Они могут отличаться в зависимости от того какой тип окна открыт. Но основные всё-таки присутствуют во всех видах.

Давайте разберем максимальное количество элементов на примере папки «мой компьютер». Так как с папками приходится работать очень часто.

Элементы управления


И так как мы видим на скриншоте показаны где располагаются основные элементы и их названия.

1 Системный значок

Этот значок находится верхнем левом углу и при нажатии на него открывается меню управления.


С помощью которого можно выполнить в зависимости от его расположения на мониторе следующие действия;

  • Восстановить
  • Переместить
  • Изменить размер
  • Свернуть
  • Развернуть
  • Закрыть

2 Заголовок

Выводится вверху и отображает название открытого объекта. В нашем случае «Этот компьютер». Если окно является активным, то он подсвечивается более ярким цветом.

При двукратном нажатии мыши на заголовок, оно раскроется до размеров вашего экрана.

3 Панель быстрого доступа

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

Также можно настроить отображение элементов.

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


А также здесь можно выбрать место расположения этой панели.

4 Кнопки управления

С помощью этих кнопок можно свернуть, развернуть или закрыть окно.

5 Строка меню и панель инструментов

Расположена она под заголовком и содержит пункты при нажатии на которые мы получаем доступ к определенным командам в панели инструментов.

Команды различны для разных видов окон все зависит от того какую задачу они выполняют.

6 Панель задач (инструментов)

В панели в нашем случае предоставляется быстрый доступ к папкам и файлам наиболее просматриваемым.

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


8 Адресная строка

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

Или же можно просто ввести соответствующий адрес папки.

Но как показывает практика эти варианты не очень удобны. Проще воспользоваться «Панелью задач».

9 Рабочая область

Это самая большая область, в которой располагаются объекты находящиеся внутри папки.

10 Кнопки отображения элементов

С помощью этих кнопок возможно настроить отображение объектов в виде таблицы или больших эскизов.

11 Строка состояния

Строка состояния выполняет информационную роль.
Сколько находится объектов в папке и сколько из них выбрано

12 Полоса прокрутки

Появляется если объекты не умещаются в рабочей области. И чтобы посмотреть невидные глазу требуется прокрутить вниз или бок. Наведя курсор на полосу и зажав левую кнопку компьютерной мыши.

13 Угол и границы

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

Дополнительные элементы

Еще хотелось бы отметить два элемента управления находящихся на панели задач рабочего стола

Если вы незнакомы с рабочем столом и панелью задач в операционной системе виндовс то рекомендую прочитать статью про «Рабочий стол Windows»

Свернуть все окна

Эта кнопка находится в правом углу панели задач


Организация отображения окон

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


Элементы управления в диалоговых окнах

Наличие этих элементов (не обязательно всех сразу) выделяют их от всех других.

К ним относятся:

Вкладки – как правило располагаются под заголовком


Флажки – используются для отображения различных параметров со значением «да» или «нет». Если галочка стоит в квадратике, то «да» если ее там нет, то тогда «нет»


Радиокнопки – предоставляют возможность выбора одного варианта из нескольких.


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


Цифровые счётчики – используются для ввода числовых значение путем нажатия стрелок вверх или вниз.


Списки – предоставляется для выбора определенного значения.


Раскрывающиеся списки – нажав стрелку открывается список и после выбора нужного значения оно будет отображается.


Ползунковые регуляторы – с помощью них выбираем значение из определенного диапазона.


Командные кнопки – нужны для выбора определенного действия. Например, сохранить, применить, отмена и.т.д.


Горячие клавиши

Для более быстрой работы за компьютером часть операций по управлению можно выполнять с помощью клавиш клавиатуры.

Давайте рассмотрим какие именно сочетания клавиш применяются при работе с окнами.

1 Alt+Tab – переключение между открытыми окнами

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


И не отпуская клавишу Alt нажимаем кнопку Tab переключаясь между ними. После выбора нужного отпускаем обе кнопки.

2 Свернуть и развернуть все окна отобразив или скрыв рабочий стол

3 Свернуть и развернуть активное окно

4 Закрыть активное окно

5 Последовательно перебирать иконки панели задач

6 Запустить приложение иконка которого закреплена на панели задач и соответствует цифрам от 0 до 9

7 Сворачивает все окна кроме активного (вторым нажатие развернуть)

8 Сместить окно к левому краю вашего экрана

Win + стрелка влево

9 Сместить окно к правому краю вашего экрана

Win + стрелка в право

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

Win + стрелка вверх

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

Win + стрелка вниз

12 Если у вас несколько мониторов, то сочетание этих клавиш поможет перенести окно на другой монитор

Win + Shift + стрелка влево или вправо

Мнение автора

В моей практике мне очень часто приходилось пользоваться всеми элементами управления окнами так как я раньше проходил службу в УИС и работать за компьютером приходилось очень часто.

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

На этом все ждите новых статей на блоге пишите комментарии делитесь информацией в социальных сетях. Всем пока.

В структуре каркасного приложения Windows можно выделить следующие разделы, образующие «скелет» программы:

· получение дескриптора приложения;

· регистрация класса окна;

· создание главного окна;

· процедура главного окна.

Получение дескриптора приложения осуществляется функцией

HMODULE WINAPI GetModuleHandle( __in_opt LPCTSTR lpModuleName);

lpModuleName – имя загруженного модуля (.dll или .exe файла), включая путь; если принимает значение 0, то функция возвращает дескриптор исполняемого .exe – файла.

ATOM RegisterClass( CONST WNDCLASS *lpwcx);

style DD ? ;стиль границ окна и его поведение

lpfnWndProc WNDPROC ? ;адрес оконной процедуры

;Все окна, созданные на основе этого класса,

cbClsExtra DD ? ;количество дополнительно

cbWndExtra DD ? ;резервируемых байт, обычно 0

hInstance DD ? ;дескриптор приложения, полученный

hIcon DD ? ;дескриптор значка LoadIcon

hCursor DD ? ;дескриптор курсора LoadCursor

hbrBackground DD ? ;дескриптор кисти

Цвет фона окна можно также задать функцией CreateSolidBrush, аргумент которой – это константа, получаемая как комбинация трех цветов (RGB): красного, зеленого и синего. Цвет определяется одним 32-битным числом. В этом числе первый байт - интенсивность красного, второй байт - интенсивность зеленого, третий байт - интенсивность синего цвета. Последний байт равен нулю.

lpszMenuName DD 0 ;указатель на ASCIIZ строку

lpszClassName DD ? ;присвоение данному классу

Создание окна осуществляется с помощью функции, позволяющей создать экземпляр окна.

dwExStyle – определяет дополнительные стили создаваемого окна:

WS_EX_ACCEPTFILES = 10h – поддержка перетаскивания файлов

WS_EX_APPWINDOW = 00040000h – добавление окна на панель задач

WS_EX_CLIENTEDGE = 00000200h – стиль границ окна

WS_EX_COMPOSITED – перерисовка снизу вверх (Windows XP)

WS_EX_CONTEXTHELP =00000400h – значок «?» в строке заголовка окна

WS_EX_CONTROLPARENT=00010000h – окно содержит дочернее окно, использующееся в диалогах

WS_EX_DLGMODALFRAME = 1h – окно с двойной границей

WS_EX_LAYERED=00080000h – «послойное» окно (Windows XP)

WS_EX_LAYOUTRTL=00400000h – начало отсчета по горизонтали – справа

WS_EX_LEFT=00000000h –выравнивание свойств по левому краю (по умолчанию)

WS_EX_LEFTSCROLLBAR = 00004000h – полоса прокрутки слева

WS_EX_LTRREADING= 00000000h – отображение текста слева направо (по умолчанию)

WS_EX_MDICHILD – создание дочернего окна в многооконном интерфейсе (MDI)

WS_EX_NOACTIVATE= 08000000h – созданное окно не активируется

WS_EX_NOINHERITLAYOUT= 00100000h – окно не передает свое положение дочерним окнам

WS_EX_RIGHT = 00001000h – выравнивание свойств по правому краю

WS_EX_RIGHTSCROLLBAR = 00000000h – вертикальная полоса прокрутки в правой части окна (по умолчанию)

WS_EX_RTLREADING =00002000h – размещение текста справа налево

WS_EX_STATICEDGE =00020000h – окно с тркхмерным стилем границ

WS_EX_TOOLWINDOW = 00000080h – окно для плавающей панели инструментов

WS_EX_TOPMOST = 8h – расположение окна перед всеми окнами.

WS_EX_TRANSPARENT = 20h – окно без перерисовки

WS_EX_WINDOWEDGE = 00000100h – «приподнятый» стиль границ окна

lpClassName — указатель на ASCIIZ-строку с именем класса окна.

Можно использовать предопределенные классы для создания элементов окна:

COMBOBOX – набор переключателей;

EDIT – поле редактирования;

RICHEDIT_CLASS – объект Rich Edit 2.0;

SCROLLBAR – полоса прокрутки;

lpWindowName — указатель на ASCIIZ-строку с именем окна.

dwStyle определяет стиль окна приложения:

WS_CAPTION =000C00000h ;WS_BORDER | WS_DLGFRAME

x — координата левого верхнего угла окна

y — координата левого верхнего угла окна

nWidth — ширина окна (по умолчанию CW_USEDEFAULT (80000000h) )

nHeight — высота окна (по умолчанию CW_USEDEFAULT (80000000h) )

hWndParent — дескриптор родительского окна. Между двумя окнами Windows-приложения можно устанавливать родовидовые отношения. Дочернее окно всегда должно появляться в области родительского окна.

hMenu — дескриптор главного меню окна

hInstance — дескриптор приложения, создающего окно.

Функция CreateWindowEx возвращает дескриптор окна.

Для отображения окна используется функция

BOOL ShowWindow( HWND hWnd, int nCmdShow);

hWnd – дескриптор окна.

nCmdShow – константа, задающая начальный вид окна.

· заносит информацию о событии в экземпляр структуры MSG;

BOOL GetMessage( LPMSG lpMsg,

;возвращается функцией CreateWindowEx

;все константы начинаются с WM_

pt POINT <> ;координаты курсора мыши в момент помещения

BOOL TranslateMessage( const MSG *lpMsg);

LRESULT DispatchMessage( const MSG *lpmsg);

- Windows передает управление функции DispatchMessage;

- DispatchMessage завершает свое выполнение.

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

.MODEL FLAT, stdcall

include win.inc ; файл с константами и структурами

HWND DD 0 ; дескриптор главного окна

HINST DD 0 ; дескриптор приложения

TITLENAME DB 'Программа',0

CLASSNAME DB 'CLASS32',0

; получить дескриптор приложения

INVOKE GetModuleHandle, 0

; заполнить структуру окна стиль

MOV WC.style, CS_HREDRAW+CS_VREDRAW+CS_GLOBALCLASS

MOV WC.lpfnWndProc, OFFSET WNDPROC

MOV WC.cbClsExtra, 0

MOV WC.cbWndExtra, 0

MOV WC.hInstance, EAX

INVOKE LoadIcon, 0, IDI_APPLICATION

MOV WC.hIcon, EAX

INVOKE LoadCursor, 0, IDC_ARROW

MOV WC.hCursor, EAX

MOV WC.hbrBackground, GRAY_BRUSH ; цвет окна

MOV DWORD PTR WC.lpszMenuName, 0

MOV DWORD PTR WC.lpszClassName, OFFSET CLASSNAME

INVOKE RegisterClass, OFFSET WC

WS_CAPTION + WS_SYSMENU + WS_THICKFRAME + WS_GROUP +\

100, ; X — координата левого верхнего угла

100, ; Y — координата левого верхнего угла

400, ; DX - ширина окна

450, ; DY — высота окна

; проверка на ошибку

MOV HWND, EAX ; дескриптор окна

INVOKE ShowWindow, HWND, SW_SHOWNORMAL ; показать созданное окно

INVOKE UpdateWindow, HWND ;перерисовать видимую часть окна

OFFSET Message, 0,0,0

INVOKE TranslateMessage, OFFSET Message

INVOKE DispatchMessageA, OFFSET Message

; выход из программы (закрыть процесс)

INVOKE ExitProcess, Message.wParam

Оконная функция имеет следующие параметры:

Параметры оконной функции Windows помещает в стек.

WM_CREATE equ 1h ; создание окна

WM_DESTROY equ 2h ; закрытие окна

WM_PAINT equ 0Fh ; перерисовка окна

WM_COMMAND equ 111h ; обработка команды Windows

WM_LBUTTONDOWN equ 201h ; нажатие левой кнопки мыши

WM_LBUTTONUP equ 202h ; отжатие левой кнопки мыши

WM_LBUTTONDBLCLK equ 203h ; двойное нажатие левой кнопки мыши

WM_RBUTTONDOWN equ 204h ; нажатие правой кнопки мыши

WM_RBUTTONUP equ 205h ; отжатие правой кнопки мыши

WM_RBUTTONDBLCLK equ 206h ; двойное нажатие правой кнопки мыши

WM_MBUTTONDOWN equ 207h ; нажатие средней кнопки мыши

WM_MBUTTONUP equ 208h ; отжатие средней кнопки мыши

WM_MBUTTONDBLCLK equ 209h ; двойное нажатие средней кнопки мыши

Структура процедуры окна строится по принципу switch-case, выбирая из списка тип события, которое необходимо обработать.

HDC GetDC( HWND hWnd ); передается дескриптор окна

HWND hwnd, // дескриптор окна

LPPAINTSTRUCT lpPaint); // указатель на структуру PAINTSTRUCT

hdc DWORD 0 ; дескриптор контекста окна

fErase DWORD 0 ; 1 – стирать фон, 0 – оставить фон окна

left DWORD 0 ; левый

top DWORD 0 ; верхний

right DWORD 0 ; правый

bottom DWORD 0 ; нижний угол прямоугольника для перерисовки

fRes DWORD 0 ; резервный, используется системой

fIncUp DWORD 0 ; резервный, используется системой

Reserv DB 32 dup(0) ; резервный, используется системой

Для вывода текста в окно используется функция

HDC hdc, // дескриптор контекста окна

int nXStart, // координата Х начальной позиции

int nYStart, // координата Н начальной позиции

LPCTSTR lpString, // указатель на строку символов

int cbString); // количество байт для вывода

Предварительно задать цвет фона и букв можно посредством функций

HDC hdc, // дескриптор контекста окна

COLORREF crColor); // цвет фона RGB

HDC hdc, // дескриптор контекста окна

COLORREF crColor); // цвет букв RGB

Центр системы координат для окна находится в левом верхнем углу, ось Y направлена вниз, ось Х - вправо. Это общепринятый вариант для графических экранов.

Для окончания перерисовки окна используется функция

HWND hWnd, // дескриптор окна

CONST PAINTSTRUCT *lpPaint // указатель на структуру PAINTSTRUCT

); // полученную функцией BeginPaint

void PostQuitMessage( int nExitCode);

Аргументом функции является код завершения приложения.

Казалось бы, что WinAPI уходит в прошлое. Давно уже существует огромное количество кросс-платформенных фреймфорков, Windows не только на десктопах, да и сами Microsoft в свой магазин не жалуют приложения, которые используют этого монстра. Помимо этого статей о том, как создать окошки на WinAPI, не только здесь, но и по всему интернету, исчисляется тысячами по уровню от дошколят и выше. Весь этот процесс разобран уже даже не по атомам, а по субатомным частицам. Что может быть проще и понятнее? А тут я еще…

Но не все так просто, как кажется.

Почему о WinAPI сейчас?

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

Здесь я не зря дал ссылку на репозиторий, т.к. видно, что ребята столкнулись с проблемой, о которой речь пойдет ниже, но так и не решили ее.

О чем это я? А вот об этом кусочке кода:

Ответ такой: так делать нельзя!

И, возвращаясь, к изначальному вопросу о WinAPI: очень много популярных, и не очень, проектов продолжают его использовать и в настоящее время, т.к. лучше, чем на чистом API многие вещи не сделать (тут можно бесконечно приводить аналогии вроде сравнения высокоуровневых языков и ассемблера, но сейчас не об этом). Да и мало ли почему? Просто используют и все тут.

О проблеме

Обойти такие мелкие неприятности просто. Есть, как минимум, два вполне легальных способа:

Tutorials?


Здесь действительно все просто:

Because the return value can be nonzero, zero, or -1, avoid code like this:

И ниже приводится пример правильного цикла.

Стоит сказать, что в шаблонах VS для Win32 приложений, написан именно такой неправильный цикл. И это очень печально. Ведь мало кто будет вникать в то, что сделали сами авторы, ведь это априори правильно. И неправильный код множится вместе с багами, которые очень сложно отловить.

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


Этот вариант я видел чаще всего. И он (та-дам) снова неправильный!

Сперва о том, что изменилось (потом о проблемах этого кода):

Ясно, что TranslateAccelerator надо вызывать для нашего созданного окна:


И вроде все хорошо и замечательно теперь: мы разобрали все детально и все должно работать идеально.

И снова нет. :-) Это будет работать правильно, пока у нас ровно одно окно — наше. Как только появится немодальное новое окно (диалог), все клавиши, которые будут в нем нажаты оттранслируются в WM_COMMAND и отправляться куда? И опять же правильно: в наше главное окно.

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

IsDialogMessage

На самом деле, делает она чуть больше, чем следует из названия. А именно:

  • Осуществляет навигацию по дочерним контролам кнопками Tab/Shift+Tab/вверх/вниз/вправо/влево. Плюс еще кое-что, но этого нам достаточно
  • По нажатии на ESC формирует WM_COMMAND( IDCANCEL )
  • По нажатии на Enter формирует WM_COMMAND( IDOK ) или нажатие на текущую кнопку по умолчанию
  • Переключает кнопки по умолчанию (рамочка у таких кнопок чуть ярче остальных)
  • Ну и еще разные штуки, которые облегчают пользователю работу с диалогом

Во-вторых, она нам облегчит жизнь по всем остальным пунктам, перечисленным в списке (и даже немного больше).

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

Although the IsDialogMessage function is intended for modeless dialog boxes, you can use it with any window that contains controls, enabling the windows to provide the same keyboard selection as is used in a dialog box.

Т.е. теперь, если мы оформим цикл так:


То наше окошко будет иметь навигацию, как в родном диалоге Windows. Но теперь мы получили два недостатка:

Пора поговорить о том, чего нет в туториалах и ответах.

Как правило (как правило! Если кому-то захочется большего, то можно регистрировать свой класс для диалогов и работать так. И, если же, кому-то это интересно, я могу дополнить этим статью) WM_KEYDOWN хотят тогда, когда хотят обработать нажатие на клавишу, которая выполнит функцию в независимости от выбранного контрола в окне — т.е. некая общая функция для всего данного конкретного диалога. А раз так, то почему бы не воспользоваться богатыми возможностями, которые нам сама WinAPI и предлагает: TranslateAccelerator.

Везде используют ровно одну таблицу акселераторов, и только для главного окна. Ну действительно: цикл GetMessage-loop один, значит и таблица одна. Куда еще их девать?

На самом деле, циклы GetMessage-loop могут быть вложенными. Давайте еще раз посмотрим описание PostQuitMessage:

The PostQuitMessage function posts a WM_QUIT message to the thread's message queue and returns immediately; the function simply indicates to the system that the thread is requesting to quit at some time in the future.
If the function retrieves the WM_QUIT message, the return value is zero.

Таким образом, выход из GetMessage-loop осуществится, если мы вызовем PostQuitMessage в процедуре окна. Что это значит?

Мы можем для каждого немодального окна в нашей программе создавать свой собственный подобный цикл. В данном случае DialogBoxParam нам не подходит, т.к. оно крутит свой собственный цикл и повлиять мы на него не можем. Однако если создадим диалог через CreateDialogBoxParam или окно через CreateWindow, то можно закрутить еще один цикл. При этом в каждом таком окне и диалоге мы должны вызывать PostQuitMessage:


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

Дело в том, что внешний цикл «встал» на вызове DispatchMessage, который вызвал нашу процедуру, которая крутит свой собственный внутренний цикл GetMessage с таким же DispatchMessage. Классический вложенный вызов (в данном случае DispatchMessage). Посему внешний цикл не получит WM_QUIT и не завершится на этом этапе. Все будет работать стройно.

Делаем красиво

Т.к. правильная постановка задачи является половиной решения, то сперва надо эту самую задачу правильно же и поставить.

Создадим простой std::map, который будет мапить дескриптор окна в дескриптор таблицы акселераторов. Вот так:


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


Ну и после закрытия окна удалять. Вот так:


Теперь, как создаем новый диалог/окно, вызываем AddAccelerators( hNewDialog, IDR_MY_ACCEL_TABLE ). Как закрываем: DelAccel( hNewDialog ).


Значительно лучше! Что же там в HandleAccelArray и зачем там GetActiveWindow()?

Есть две функции, возвращающих дескриптор активного окна GetForegroundWindow и GetActiveWindow. Отличие первой от второй вполне доходчиво описано в описании второй:

The return value is the handle to the active window attached to the calling thread's message queue. Otherwise, the return value is NULL.


Теперь каждое дочернее окно вправе добавить себе любимую таблицу акселераторов и спокойно ловить и обрабатывать WM_COMMAND с нужным кодом.

А что там еще об одной строчке в коде обработчика WM_COMMAND?

To differentiate the message that this function sends from messages sent by menus or controls, the high-order word of the wParam parameter of the WM_COMMAND or WM_SYSCOMMAND message contains the value 1.

Обычно код обработки WM_COMMAND выглядит так:


Теперь можно написать так:

P.S.: Мало кто знает, но можно создавать свою собственную таблицу акселераторов, а теперь и применять ее прямо налету.

P.P.S.: Т.к. DialogBox/DialogBoxParam крутит собственный цикл, то от при вызове диалога через них акселераторы работать не будут и наш цикл (или циклы) будет «простаивать».

P.P.P.S.: После вызова HandleAccelWindow мап l_mAccelTable может измениться, т.к. TranslateAccelerator или IsDialogMessage вызывают DispatchMessage, а там может встретиться AddAccelerators или DelAccel в наших обработчиках! Поэтому лучше его после этой функции не трогать.

Пощупать код можно здесь. За основу был взят код, генерируемый из стандартного шаблона MS VS 2017.

в этом пошаговом руководстве показано, как создать традиционное Windows классическое приложение в Visual Studio. в примере приложения, которое вы создадите, будет использоваться Windows API для вывода "Hello, Windows desktop!". "Hello, World!". Код, созданный в этом пошаговом руководстве, можно использовать в качестве шаблона для создания других классических приложений Windows.

Для краткости в тексте пропущены некоторые операторы кода. В разделе Построение кода в конце документа показан полный код.

Предварительные требования

Компьютер под управлением Microsoft Windows 7 или более поздних версий. Для обеспечения оптимальной среды разработки рекомендуется использовать Windows 10.

Копия Visual Studio. Сведения о скачивании и установке Visual Studio см. в этой статье. Когда вы запускаете установщик, убедитесь, что установлена рабочая нагрузка Разработка классических приложений на C++ . Не беспокойтесь, если вы не установили эту рабочую нагрузку при установке Visual Studio. Вы можете снова запустить установщик и установить ее сейчас.

Подробные сведения о рабочей нагрузке Разработка классических приложений на C++ в Visual Studio Installer.

Базовые значения об использовании интегрированной среды разработки Visual Studio. Если вы уже использовали классические приложения для Windows, вы, вероятно, справитесь. Общие сведения см. в обзоре возможностей интегрированной среды разработки Visual Studio.

Основные навыки владения языком C++. Не волнуйтесь, мы не будем делать ничего сложного.

создание проекта Windows классических приложений

чтобы создать первый проект Windows desktop, выполните следующие действия. в процессе работы вы вводите код рабочего Windows приложения. Чтобы ознакомиться с документацией по предпочтительной версии Visual Studio, используйте селектор Версия. Он находится в верхней части оглавления на этой странице.

создание проекта Windows desktop в Visual Studio 2019

В главном меню выберите Файл > Создать > Проект, чтобы открыть диалоговое окно Создание проекта.

в верхней части диалогового окна задайте для параметра язык значение C++, задайте для параметра платформа значение Windows и задайте для параметра Project тип значение рабочий стол.

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

В Обозреватель решений щелкните правой кнопкой мыши проект Десктопапп , выберите Добавить, а затем выберите новый элемент.

снимок экрана: диалоговое окно "добавление нового элемента" в Visual Studio 2019 с установленным > Visual C и плюсом, а также параметр файла c плюсом/с выделенным.

Теперь проект создан и исходный файл открыт в редакторе. Чтобы продолжить, перейдите к созданию кода.

создание проекта Windows desktop в Visual Studio 2017

В меню Файл выберите команду Создать, а затем пункт Проект.

в левой области диалогового окна создание Project разверните узел установленные > Visual C++ и выберите пункт Windows рабочий стол. в средней области выберите мастер рабочего стола Windows.

снимок экрана: диалоговое окно "создание Project" в Visual Studio 2017 с установленным > Visual C плюс плюс > Windows рабочего стола, выбранный параметр "мастер настольных систем Windows" и десктопапп введено в текстовом поле "имя".

В Обозреватель решений щелкните правой кнопкой мыши проект Десктопапп , выберите Добавить, а затем выберите новый элемент.

снимок экрана: диалоговое окно "добавление нового элемента" в Visual Studio 2017 с установленным > Visual C и плюсом, а также параметр файла c плюсом/с выделенным.

Теперь проект создан и исходный файл открыт в редакторе. Чтобы продолжить, перейдите к созданию кода.

создание проекта Windows desktop в Visual Studio 2015

В меню Файл выберите команду Создать, а затем пункт Проект.

в левой области диалогового окна создание Project разверните узел установленные > шаблоны > Visual C++, а затем выберите пункт Win32. В средней области выберите шаблон Проект Win32.

снимок экрана: диалоговое окно "создание Project" в Visual Studio 2015 с установленными шаблонами > > Visual C плюс плюс > win32, выделенный параметр win32 Project и десктопапп, введенные в текстовом поле имя.

На странице Обзор мастера приложений Win32 нажмите кнопку Далее.

Создание Десктопапп на странице обзора мастера приложений Win32.

на странице Параметры приложений в разделе тип приложения выберите Windows приложение. В разделе Дополнительные параметры снимите флажок предкомпилированный заголовок, а затем выберите пустой проект. Чтобы создать проект, нажмите кнопку Готово.

В Обозреватель решений щелкните правой кнопкой мыши проект десктопапп, выберите Добавить, а затем выберите новый элемент.

снимок экрана: диалоговое окно "добавление нового элемента" в Visual Studio 2015 с установленным > Visual C и плюсом, а также параметр файла c плюсом/с выделенным.

Теперь проект создан и исходный файл открыт в редакторе.

Создание кода

далее вы узнаете, как создать код для Windows классического приложения в Visual Studio.

Запуск классического приложения Windows

точно так же, как у каждого приложения C и C++ должна быть main функция в качестве начальной точки, каждое Windows классическое приложение должно иметь WinMain функцию. WinMain имеет следующий синтаксис:

Сведения о параметрах и возвращаемом значении этой функции см. в разделе WinMain Entry Point.

Что такое дополнительные слова, такие как, или, или WINAPI CALLBACK HINSTANCE _In_ ? традиционный API Windows использует определения типов и макросов препроцессора, чтобы изменялись некоторые сведения о типах и коде, зависящем от платформы, такие как соглашения о вызовах, __declspec объявления и директивы pragma компилятора. в Visual Studio можно использовать функцию " быстрые сведения " IntelliSense, чтобы увидеть, что определяются этими определениями и макросами. Наведите указатель мыши на интересующую слово или выберите его и нажмите клавиши CTRL + K, CTRL + I для небольшого всплывающего окна, содержащего определение. Дополнительные сведения см. в разделе Using IntelliSense. Параметры и возвращаемые типы часто используют аннотации SAL , чтобы помочь в перехвате ошибок программирования. Дополнительные сведения см. в разделе Использование аннотаций SAL для сокращения числа дефектов кода C/C++.

для Windows настольных приложений требуется <> Windows. h. <в файле Tchar. h> определен TCHAR макрос, который в конечном итоге разрешается в, wchar_t Если в проекте ОПРЕДЕЛЕН символ Юникода, в противном случае — значение char . Если вы всегда создаете Юникод с включенным параметром UNICODE, то не нужно использовать TCHAR и может быть просто использоваться wchar_t напрямую.

наряду с WinMain функцией, каждое Windows классическое приложение также должно иметь функцию window-procedure. Эта функция обычно называется WndProc , но вы можете назвать ее по своему усмотрению. WndProc имеет следующий синтаксис:

Дополнительные сведения см. в разделе Процедуры окна.

Добавление функциональных возможностей в функцию WinMain

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

Дополнительные сведения о полях приведенной выше структуры см. в разделе вндклассекс.

Теперь можно создать окно. Используйте функцию CreateWindowEx .

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

на этом этапе окно было создано, но нам по-прежнему нужно сообщить Windows, чтобы сделать его видимым. Вот что делает этот код:

На этом этапе функция WinMain должна напоминать приведенный ниже код.

Добавление функциональных возможностей в функцию WndProc

HDC в коде — это обработчик контекста устройства, который используется для рисования в клиентской области окна. Используйте BeginPaint функции и EndPaint для подготовки и завершения рисования в клиентской области. BeginPaint Возвращает маркер контекста устройства отображения, используемый для рисования в клиентской области. EndPaint завершает запрос на рисование и освобождает контекст устройства.

Сборка кода

Как обещано, вот полный код для рабочего приложения.

Сборка примера

Удалите код, введенный в хелловиндовсдесктоп. cpp в редакторе. Скопируйте этот пример кода и вставьте его в хелловиндовсдесктоп. cpp:

В меню Построение выберите Построить решение. Результаты компиляции должны появиться в окне вывод в Visual Studio.

Чтобы запустить приложение, нажмите клавишу F5. окно, содержащее текст "Hello, Windows desktop!" должно отображаться в левом верхнем углу экрана.

Снимок экрана выполняемого Project Десктопапп.

Поздравляем! вы выполнили это пошаговое руководство и создали традиционное Windows классическое приложение.

Читайте также: