как сделать свое окно в виндовс

Организуем окна в Windows с помощью менеджеров окон

Здравствуйте, читатели ХабраХабр.
Недавно я начал самостоятельно изучать программирование, и с тех пор во время учебного процесса (ну или процесса примитивной разработки) регулярно сталкиваюсь со следующими проблемами:
лень учиться
— затраты времени и «сил» на организацию окон, с которыми работаешь в данный момент
— присутствие лишних окон, с которыми или в данный момент, или вообще не работаешь (например, консоль запущенного сервера)
— физический недостаток пространства для размещения всех окон, при котором будет удобно работать

Если в Google ввести запрос «менеджер окон Mac», выдается множество результатов утилит — менеджеров окон, обзоры и отзывы. А вот для Windows — полная тишина.
На любимом сервисе Toster мне подсказали несколько утилит, существенно облегчающих организацию рабочего пространства, которыми я теперь пользуюсь сам и хочу поделиться с другими.

Чтобы не тратить время тех, кто о них знает, сразу перечислю: AquaSnap, DIVVY и BetterDesktopTool.
Сам же постараюсь кратко описать их наиболее полезные функции.

AquaSnap

Коронной функцией этой программы считаю синхронное изменение размера окон. Странно, что фирме Microsoft в своем популярнейшем ПО с названием «Окна» (Windows) не пришла в голову идея реализовать это.

как сделать свое окно в виндовс. Смотреть фото как сделать свое окно в виндовс. Смотреть картинку как сделать свое окно в виндовс. Картинка про как сделать свое окно в виндовс. Фото как сделать свое окно в виндовс

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

как сделать свое окно в виндовс. Смотреть фото как сделать свое окно в виндовс. Смотреть картинку как сделать свое окно в виндовс. Картинка про как сделать свое окно в виндовс. Фото как сделать свое окно в виндовс

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

Небольшое отступление или «камень в огород LG»
В данный момент фирма LG активно рекламирует и пытается внедрить в новых моделях мониторов ту самую функцию синхронного изменения окон, но программное обеспечение работает исключительно криво, а резкие и краткие ответы операторов Call-центра создают впечатление, что маркетологи сработали хорошо, а вот разработчики «немного не успели» реализовать обещанное. Все вышесказанное проверенно и подтверждено покупкой (и последующим возвратом в магазин) монитора LG с заявленной функцией.

DIVVY

Из-за того, что AquaSnap выполняет весь необходимый функционал, я несколько раз устанавливал, а после удалял DIVVY.

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

как сделать свое окно в виндовс. Смотреть фото как сделать свое окно в виндовс. Смотреть картинку как сделать свое окно в виндовс. Картинка про как сделать свое окно в виндовс. Фото как сделать свое окно в виндовс

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

BetterDesktopTool

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

как сделать свое окно в виндовс. Смотреть фото как сделать свое окно в виндовс. Смотреть картинку как сделать свое окно в виндовс. Картинка про как сделать свое окно в виндовс. Фото как сделать свое окно в виндовс

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

Второй монитор

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

Источник

Как создать диалоговое окно (C++)

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

Если в проекте еще нет RC-файла, см. раздел Создание нового файла описания ресурсов.

Инструкции

Редактор диалоговых окон позволяет:

Создание нового диалогового окна

Если + рядом с типом ресурса диалогового окна отображается знак «плюс» (), это означает, что доступны шаблоны диалоговых окон. Щелкните знак «плюс», чтобы развернуть список шаблонов, выберите шаблон и нажмите кнопку создать.

В редакторе диалоговых окон откроется диалоговое окно создать.

Также можно открыть существующие диалоговые окна в редакторе диалоговых окон для редактирования.

Создание диалогового окна, которое пользователь не может выйти

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

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

Для создания диалогового окна, которое пользователи не могут выйти из приложения MFC, необходимо переопределить поведение по умолчанию OnOK и, OnCancel так как даже если удалить связанные кнопки, диалоговое окно по-прежнему может быть закрыто нажатием клавиши Ввод или ESC.

Указание расположения и размера диалогового окна

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

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

Свойство абсолютного соответствия, которое влияет на положение.

Если значение равно true, координаты задаются относительно экрана. Если значение равно false, координаты задаются относительно окна владельца диалогового окна.

Проверка диалогового окна

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

вводить текст, выбирать пункты в полях со списками, включать и отключать параметры, выбирать команды;

тестировать последовательность табуляции;

проверять группировку элементов управления, например переключателей и флажков;

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

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

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

Когда Редактор диалоговых окон является активным окном, перейдите в > диалоговое окно Проверка формата меню.

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

Источник

Окна на чистом WinAPI. Или просто о сложном

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

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

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

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

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

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

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

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

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

О проблеме

Диалоговые окна упрощают работу с GUI, одновременно лишая нас возможности сделать что-то самостоятельно. Например, сообщения WM_KEYDOWN/WM_KEYUP, приходящие в оконную процедуру, «съедаются» в недрах DefDlgProc, беря на себя такие вещи, как: Навигация по Tab, обработка клавиш Esc, Enter, и т.д. Кроме того, диалоги не нужно создавать вручную: проще, ведь, набросать кнопок, списков, в редакторе ресурсов, вызвать в WinMain CreateDialog/DialogBox и все готово.

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

Tutorials?

Не побоюсь сказать, что все туториалы по созданию окон через WinAPI начинаются с такого незамысловатого кода, обозначая его, как «цикл обработки сообщений» (опущу детали по подготовке класса окна и прочую обвязку):

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

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

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

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

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

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

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

Собственно TranslateAccelerator этим и занимается: если видит WM_KEYDOWN и код клавиши, которые есть в этом списке, то (опять же ключевой момент) будет формировать сообщение WM_COMMAND (MAKEWPARAM(id, 1)) и отправлять в соответствующую для дескриптора окна, указанного в первом аргументе, процедуру обработки.

Из последней фразы, думаю, стало понятно, в чем проблема предыдущего кода.
Поясню: GetMessage выхватывает сообщения для ВСЕХ объектов типа «окно» (в число которых входят и дочерние: кнопки, списки и прочее), а TranslateAccelerator будет отправлять сформированную WM_COMMAND куда? Правильно: обратно в кнопку/список и т.д. Но мы обрабатываем WM_COMMAND в своей процедуре, а значит нам интересно ее получать в ней же.

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

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

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

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

IsDialogMessage

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

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

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

Вообще, она используется где-то в недрах 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 и не завершится на этом этапе. Все будет работать стройно.

Но и тут есть свои недостатки:
Каждый такой цикл будет обрабатывать сообщения только для «своего» окна. Про другие-то мы здесь не знаем. А значит, если где-то объявится еще один цикл, то все остальные окна не будут получать нужной обработки своих сообщений парой TranslateAccelerator/IsDialogMessage.

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

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

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

Во-первых, было бы логично, что только активное окно принимает сообщения. Т.е. для неактивного окна мы не будем транслировать акселераторы и передавать сообщения в IsDialogMessage.

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

Создадим простой 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.

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

Так вот HandleAccelArray, руководствуясь переданным ей дескриптором на активное окно, ищет это самое окно в нашей мапе, и если оно там есть, отдает это сообщение на трансляцию в TranslateAccelerator, а затем (если первый не увидел нужного) в IsDialogMessage. Если и последняя не обработала сообщение, то возвращаем FALSE, чтобы пройти по стандартной процедуре TranslateMessage/DispatchMessage.

Теперь каждое дочернее окно вправе добавить себе любимую таблицу акселераторов и спокойно ловить и обрабатывать 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 выглядит так:

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

И теперь, возвращаясь к тому же fceux, добавив всего одну строчку в код обработки команд от кнопок, мы получим желаемое: управлять дебагером с клавиатуры. Достаточно добавить небольшую обертку вокруг главного цикла сообщений и новую таблицу акселераторов с нужными соответствиями VK_KEY => IDC_DEBUGGER_BUTTON.

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

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

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

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

Источник

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

Классы окон

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

Каждое окно должно быть связано с классом окна, даже если программа создает только один экземпляр этого класса. Важно понимать, что класс окна не является «классом» в смысле C++. Вместо этого это структура данных, используемая внутри операционной системы. Классы окон регистрируются в системе во время выполнения. Чтобы зарегистрировать новый класс окна, начните с заполнения структуры вндкласс :

Необходимо задать следующие члены структуры:

Имена классов являются локальными для текущего процесса, поэтому имя должно быть уникальным только в пределах процесса. однако стандартные элементы управления Windows также имеют классы. При использовании любого из этих элементов управления необходимо выбрать имена классов, которые не конфликтуют с именами классов элементов управления. Например, класс окна для элемента управления Button называется «Button».

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

Чтобы создать новый экземпляр окна, вызовите функцию CreateWindowEx :

CreateWindowEx возвращает маркер в новое окно или нуль, если функция завершается ошибкой. Чтобы отобразить окно, т. е. сделать окно видимым, передайте в функцию ShowWindow маркер окна:

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

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

Источник

Rozov.Info

А вдруг пригодится….

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

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

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

Рассмотрим как же создать простое приложение выводящее на экран окно в операционной системе Windows с использованием Win API на языке С++:

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

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

int WINAPI WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd )

Эту функцию вызывает операционная система при запуске приложения и передает в неё 4 параметра:

hInstanceДескриптор текущего экземпляра приложения. Так как Windows является многозадачной системой, то очевидно, что одна и та же программа может быть запущена несколько раз. Для того чтобы различать экземпляры программ, каждому экземпляру присваивается условный номер – хэндл (handle). Отмечу, так же, что в Win32 присваиваются хэндлы чему угодно – окну, меню, курсору, иконке и т.д.
hPrevInctanceУказатель на предыдущий запущенный экземпляр. Всегда равен NULL. В Windows 3.1 hPrevInctance являлся хэндлом предыдущего экземпляра программы. Если запускается первый экземпляр программы, то параметр hPrevInctance был равен нулю. Этот параметр можно было использовать для того, чтобы не позволить системе запускать более одного экземпляра программы. В Win32 hPrevInctance оставлен исключительно для совместимости с предыдущими версиями Windows.
lpCmdLineУказатель на командную строку запускаемой программы. Представляет собой указатель на строку параметров, которые были указаны после имени запускаемой программы. При необходимости программа может проанализировать этот аргумент и выполнить некоторые действия.
nCmdShowСпособ визуализации окна. Определяет, в каком виде создаваемое окно будет появляться на экране. Окно может появиться развернутым на весь экран, свернутым в панель задач, иметь произвольный размер на рабочем столе и другие характеристики. В Win API определяется 11 возможных значений этого параметра. Их идентификаторы начинаются с SW (Show Window).

Возможные значения параметра nCmdShow приведены ниже:

SW_HIDEСкрывает окно и активизирует другое окно.
SW_MAXIMIZEРаспахивает указанное окно на весь экран.
SW_MINIMIZEМинимизирует указанное окно и активизирует следующее окно верхнего уровня Z буфера.
SW_RESTOREАктивизирует и отображает окно. Если окно минимизировано или развернуто, система восстанавливает его в исходное положение и размер. Приложение должно указать этот флаг при восстановлении свернутого окна.
SW_SHOWАктивирует окно и выводит на экран это в его текущем размере и позиции.
SW_SHOWMAXIMIZEDАктивизирует окно и отображает его как развернутое окно.
SW_SHOWMINIMIZEDАктивизирует окно и отображает его как свернутое окно.
SW_SHOWMINNOACTIVEОтображает окно как свернутое окно. Это значение аналогично SW_SHOWMINIMIZED, за исключением того, что окно не активизируется.
SW_SHOWNAОтображает окно в его текущем размере и позиции. Это значение аналогично SW_SHOW, за исключением того, что окно не активизируется.
SW_SHOWNOACTIVATEОтображает окно в его последнем размер и положение. Это значение аналогично SW_SHOWNORMAL, за исключением того, что окно не активируется.
SW_SHOWNORMALАктивизирует и отображает окно. Если окно минимизировано или развернуто, система восстанавливает его в исходное положение и размер. Приложение должно указать этот флаг при показе окна в первый раз.

Указатель типа int предшествующий названию функции говорит о том, что функция должна вернуть вызывающей её системе целое значение, а характеристика WINAPI – определяет порядок передачи параметров при вызове процедуры. Наименование характеристик говорит само за себя – Windows Application Programming Interface – применяются соглашения о передаче параметров, принятых в системах Windows.

Следующим шагом нужно создать, заполнить и зарегистрировать класс окна. Класс окна представляет собой структуру с именем WNDCLASS.

Прототип структуры WNDCLASS выглядит следующим образом:

styleСтиль окна определяется комбинацией нескольких предопределенных констант. Довольно часто он задается равным нулю, что означает «стиль по умолчанию»
lpfnWndProcУказатель на оконную процедуру.
cbClsExtraОпределяет количество дополнительных байт резервируемых структуре класса.
cbWndExtraОпределяет количество дополнительных байт резервируемых структуре окна.
hInstanceДескриптор экземпляра, который содержит оконную процедуру для класса.
hIconДескриптор иконки. Этот элемент должен содержать дескриптор ресурса иконки. Если этот элемент имеет значение NULL, система устанавливает значок по умолчанию.
hCursorДескриптор курсора. Этот элемент должен содержать дескриптор ресурса курсора. Если этот элемент имеет значение NULL, приложение должно явно установить формы курсора при перемещении мыши в окне приложения.
hbrBackgroundДескриптор кисти фона. Этот элемент может быть дескриптором кисти, которая будет использоваться для окраски фона, или это может быть значение цвета.
lpszMenuNameУказатель на имя ресурса меню. Если этот элемент имеет значение NULL, окна этого класса не имеют меню.
lpszClassNameУказатель имя только что созданного нами класса окна. Максимальная длина lpszClassName 256.

Регистрация класса окна осуществляется функцией RegisterClass прототип которой выглядит:

ATOM RegisterClass( CONST WNDCLASS *lpWndClass );

В качестве параметров функция принимает указатель на структуру WNDCLASS созданную нами ранее.

И наконец, функция создания окна — CreteWindow. Вот прототип этой функции:

HWND CreateWindow ( LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam );

lpClassNameУказатель на имя класса окна.
lpWindowNameУказатель на имя окна. При использовании CreateWindow для создания элементов управления, таких как кнопки, флажки и статические элементы управления, в lpWindowName указывается идентификатор элемента.
dwStyleОпределяет стиль окна. Этот параметр может быть комбинацией стилей окна.
xЗадает начальное горизонтальное положение окна.
уЗадает начальное вертикальное положение окна.
nWidthОпределяет ширину окна в пикселях.
nHeightОпределяет высоту окна в пикселях.
hWndParentДескриптор родителя(владельца) создаваемого окна.
hMenuДескриптор меню.
hInstanceХэндл экземпляра окна.
lpParamМы пока использовать не будем.

При успешном выполнении функция возвращает дескриптор созданного окна, при ошибке NULL.

Для того чтобы корректно отобразить окно на экране, следует выполнить ещё две функции ShowWindow и UpdateWindow.

BOOL ShowWindow( HWND hWnd, int nCmdShow )

Функция ShowWindow отображает окно на экране. Первый параметр – дискриптор окна, второй – режим отображения. В качестве этого параметра обычно используют параметр nWinMode функции WinMain.

BOOL UpdateWindow( HWND hWnd )

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

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

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

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

while (GetMessage(&msg, NULL, 0, 0))

В цикле обработки сообщений присутствует три функции. Эти функции есть там всегда, но кроме них в цикле могут быть и другие. Функция GetMessage выбирает из очереди сообщений приложения очередное приложение. Вместо этой функции используют так же функции PostMessage и PeekMessage.

Функция TransleteMessage преобразует сообщения WM_KEYDOWN и WM_KEYUP в WM_CHAR. Функция DispatchMessage просто переправляет сообщение оконной процедуре.

Во всех трех функциях присутствует указатель на строку MSG. Разберём её:

hwndДескриптор окна.
messageкод сообщения.
wParamдополнительный параметр.
lParamдополнительный параметр.
timeвремя посылки сообщения.
ptположение курсора мыши.

Оконная процедура — еще один компонент, отвечающий за обработку сообщений окна. Эта функция вызывается системой и имеет четыре параметра, совпадающих с первыми четырьмя членами структуры MSG. Искусство API-программирования заключается в основном в написании оконных функций.

Вот прототип оконной функции:

LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )

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

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *