Обновить

WinUI 3 без XAML: как написать декларативный GUI на чистом C++23, сжав проекцию WinRT в 50 раз

Уровень сложностиСложный
Время на прочтение18 мин
Охват и читатели5.4K
Всего голосов 6: ↑6 и ↓0+6
Комментарии30

Комментарии 30

А какой вес получается, например с GUI окном + кнопкой при статик линковке (без внешних зависимостей от runtime)? Жаль что у Microsoft до сих пор нет для C/C++ нормального решения для GUI ,без тяжелых фреймворков, например как это было удобно в VB6. Я лично использую WinAPI это тот еще ад, но компактно и если есть уже свои наработки то- быстро. Конечно ко всему нужно привыкать.

 у Microsoft до сих пор нет для C/C++ нормального решения для GUI ,без тяжелых фреймворков

MFC, WinForms никуда не делись (Forms правда без C++/CLI сомнительно). На шарпе для классик .NET 4.8 тоже мелкие приложения будут без зависимостей, еще и тогда WPF можно.

Upd. И как же я забыл еще про WTL

MFC -это довольно объемный доп. портфель с собой таскать или статик линковка делает exe огромных размеров.
WTL - это тот же самый по сути WinAPI, просто с ООП и поделенный на классы -так что излишний.

MFC всегда уже есть в системе. Линкуемся к уже существующей DLL.

WTL/MFC это просто один уровень абстракции и удобства к WinAPI, как он может быть излишним.

Уровень тонкий -> накладных на размер мало.

MFC -это довольно объемный доп. портфель

Он еще и тормозной. Помню, как делал на нем UI под Win9x на Celeron - то, что через WinAPI летало без задержек, через MFC ощутимо тормозило.

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

Было дело, потом с выходом библиотеки стандартных макросов для WinAPI писать на голом этом WinAPI стало местами проще, чем под MFC, тоже можно было в одной WinMain накатать относительно несложный диалог.

MFC тормозил, потому что держал глобальный map отображения объектов MFC на хендлы окон, т.е. по каждому событию под защитой мьютекса лез в эту мапу, доставал оттуда объект и смотрел - есть ли перехватчики на это сообщение. Причём, в одноядерных системах мьютексы были относительно дешевы, но как только началась многоядерность, так сразу всё - стали нужны interlocked-операции. В любом случае, поиск по мапе по каждому событию и затем линейный поиск по перехваченным номерам сообщений - это тормоза.

Для сравнения, ATL/WTL хранили указатель на свой объект в данных окна (GetWindowData или как там её), поэтому WTL и была одно время популярна из-за своей легковесности в рантайм, хотя писать на ATL/WTL тот еще мазохизм. ))

Всё верно. Но приложения выглядят морально устаревшими. Ситуация такова, что WinUI - это официальное будущее. Стоит начинать окучивать. ))

WinUI - ну да сейчас же модно "программистов" плодить с их "Hello World!" на 60 - 100 МБ

Так и есть, но это потому что приложение таскает свой "дом" на себе.

Привязка к WinUI удобна тем, что это общесистемная библиотека, т.е. измеряться будет только "добавочная стоимость" размера приложений, и она получается смехотворной по нынешним временам - первые версии читалки были в районе 300КB, пока туда не напихалась куча функционала, включая поддержку MathML для epub-формата и свистелки навроде псевдо-3D и настройки параметров этого псевдо 3D-отображения, чтобы буквы повторяли изгибы подложки, но сохраняли типографскую чёткость.

Сейчас приложение весит 1.2М
Сейчас приложение весит 1.2М

Репу читалки открыл: https://github.com/dmitry-valyukov/bukvitsa
Но смотреть пока не рекомендую - в wxl появляются новые хелперы, Bukvitsa должна будет переехать на последнее поколение "достижений", ужав код генерации UI, а то многовато самоповторов, надо повыносить стили отдельно (механизм пресетов уже есть в wxl - это легковесная альтернатива XAML-описанию стилей и объекта Style поверх него):
https://github.com/dmitry-valyukov/bukvitsa/blob/main/Reader/src/reader_panel.cpp

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

В отличие от классического Win32 API, элементы которого «зашиты» в ядро и библиотеки ОС, WinUI 3 поставляется отдельно от Windows как часть независимого пакета Windows App SDK.

Это рантаймы нужные только вашей проге ставить на машину - как то не гуд.
А статик линковка вам даст минимум 60Мб.

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

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

И там не 60MB, конечно. Эти 60MB содержат в себе все 4 конфигурации (два для x86/x64 и два для ARM), но в систему конкретной программой будет установлена одна конфигурация. Уже установленный рантайм для x64 (не путать с SDK) весит в районе 20+ MB.

>рантаймы нужные только вашей проге

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

Теперь по матчасти.

Механизм обновлений WinUI 3 примерно такой же, как и для WinUI 2, на котором написано много системных приложений самой Windows, т.е. через фоновый процесс магазина приложений (даже если юзер не залогинен в нём).

Именно такое распространение обновлений графического бэкенда было обкатано на WinUI 2 и унаследовано следующей версией 3.

Т.е., MS переводит обновление приличной части зависимостей Windows на механизмы доставки обновлений магазина.

На практике это выглядит так:
- Зависимость программы будет только от мажорных версий, т.е. конкретно от WinUI 2, от WinUI 3, от WinUI 4 (гипотетически через десяток лет). Сегодня актуальна 3-я версия, поэтому у wxl зависимость от неё.
- Инсталляха целевой программы может таскать с собой redistributable MSIX-пакеты целиком, либо тонкий бутстрапер, который выкачает и установит. Если пакет уже стоит, то бутстрапперская часть инсталляции либо обновит минорную версию, либо ничего не сделает, если уже стоит такая же, либо более свежая версия.
- Пакет можно поставить на уровень пользователя или на уровень машины. Если поставить под админскими правами - будет один на всех пользователей. И это тоже приятная развилка - можно будет устанавливать программы туда, где юзер не имеет админских прав.

В любом случае, если будет установлено N программ, зависящих от WinUI 3, то система распухнет не на N x 60MB, а на 60 дополнительных мегабайт.

Или, допустим, очередная версия Windows Terminal обновится в зависимостях до WinUI 3 - и этот пакет окажется в системе автоматически.

Минорные версии прилетают в систему автоматом точно так же, как они прилетают сегодня для WinUI 2.

Но самое важное в другом - WinUI 2 зависит от системного XAML-движка, который обновляется вместе с операционкой и это принесло самой MS адскую головную боль, потому что ради внесения небольших патчей в сугубо в движок XAML им приходило выпускать обновление аж для всей операционки.

В WinUI 3 они окончательно отделили обновление графической библиотеки от операционки, теперь эти обновления приходят тихо и незаметно через магазин.

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

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

И еще лично я ожидаю, что немного допилят сам бутстрап, чтобы сделать первый посев максимально гладким, коль он будет идти по линии приложений, не контролируемых MS. Ну или не MS допилит, а появится готовый со стороны (или даже несколько на выбор), но не суть, это мне видится неизбежным в любом случае, потому что отрасль уже обратила внимание на WinUI 3 и теперь стоит ожидать приложений на этой подсистеме не только от MS (и очень редких от других игроков), как оно было для WinUI 2.

если будет установлено N программ, зависящих от WinUI 3, то система распухнет не на N x 60MB, а на 60 дополнительных мегабайт.

Это будет справедливо для любой программы? А то я как-то не видел двух независимых программ, которые бы использовали общие библиотеки Qt. :)

Да, для любой программы, использующей такой способ деплоя.

Qt — это классическая «вещь в себе», Windows о ней ничего не знает. Более того, есть несколько несовместимых конфигураций/сборок, смотря какая подсистема используется (msys или еще что-нибудь). Т.е., QT - это не только GUI-библиотека, это еще половина собственного рантайма, заменяющего рантайм Windows

С Windows App SDK / WinUI 3 ситуация иная:

  • Пакет устанавливается в системный каталог C:\Program Files\WindowsApps как глобальный MSIX Framework Package.

  • Операционная система Windows знает про него всё: она ведет зависимостей и подставляет этот слой рантайма программе через легкий 400-килобайтный бутстраппер (Microsoft.WindowsAppRuntime.Bootstrap.dll).

  • Обслуживание и минорные апдейты пакета делегированы фоновым службам операционной системы и Магазина приложений.

То есть WinUI 3 для Windows — это не сторонняя библиотека «сбоку», это новый, штатный, отчуждаемый платформенный слой GUI, который поставляется по схеме динамического разделения ресурсов. Если на машине крутится пять независимых программ на базе WinUI 3 / WXL, все они в рантайме будут лениво подхватывать один и тот же установленный в систему Framework-пакет.

И да, именно эта особеность деплоя была для меня одной из весомых причин выбрать WinUI 3 в качестве бэкенда для декларативных игрищ с GUI.

Официальное будущее - это кроссплатформа. И WinUI никак сюда не проходит.

Популярности у нее нет, так что я не одинок.

Кроме того, производительностью XAML я недоволен. Что WPF, что Avalonia - тормоза. Что там в WinUI с учетом п1, даже неохота смотреть.

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

На некоторой стадии разработки будут попытки разработки альтернативного бэкенда.

Таки, Flutter, а затем SwiftUI показали удобный принцип рисования, убрав с задачи разработки GUI налёт сакральности, превратив процесс в полную ерунду в пересчёте на когнитивные затраты.

Разрабатываемое приложение-читалка 1.2 метра, внутри вся типографика и прочие радости, будут отдельные статьи по ней,

А зависимости есть? Смотрели импорт?

Зависимости:
---
api‑ms‑win‑core‑winrt‑error‑l1-1-1.dll
api‑ms‑win‑core‑winrt‑l1-1-0.dll
api‑ms‑win‑crt‑heap‑l1-1-0.dll
api‑ms‑win‑crt‑locale‑l1-1-0.dll
api‑ms‑win‑crt‑math‑l1-1-0.dll
api‑ms‑win‑crt‑runtime‑l1-1-0.dll
api‑ms‑win‑crt‑stdio‑l1-1-0.dll
api‑ms‑win‑crt‑string‑l1-1-0.dll

COMCTL32.dll
ole32.dll
OLEAUT32.dll
d2d1.dll d3d11.dll
DWrite.dll
SHELL32.dll

USER32.dll
GDI32.dll
KERNEL32.dll

Microsoft.WindowsAppRuntime.Bootstrap.dll

MSVCP140.dll
MSVCP140_ATOMIC_WAIT.dll
VCRUNTIME140.dll
VCRUNTIME140_1.dll
---

Microsoft.WindowsAppRuntime.Bootstrap.dll — вот эта весит 400 KB.

И да, в планах обязательно проверить статическую линкову с рантаймом, сколько оно добавит, потому что CRT/CppRT тоже надо деплоить, если линковаться динамически.

Обычно рантайм добавляет немного - смотря, что из него используется. Обычный диапазон от 300 KB до 1.5 MB, где подсистема iostream занимает сразу под пол‑метра, именно поэтому в wxl есть свой тоненький file и async_file прямо поверх WinAPI.

Так и как можно попробовать wxl?

Примерно в следующий вторник вместе с очередной статьёй.
DSL-описание требует хелперов под популярные сценарии - это ожидаемое "открытие" для таких технологий. На одних мини-примерах далеко не уедешь.

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

целые армии разработчиков, 100% времени пишущих под Linux, делают это из‑под Windows

Чо? Откуда это? Кто собирал эту статистику? Где можно взглянуть?

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

Понятно. Впечатление от собственной эхо-камеры обобщили на всю вселенную.

Разве сегодня Linux требуется защищать? Он в топе и везде, всё у него хорошо. ))

Разве сегодня Linux требуется защищать?

Мне по барабану. Почему вопрос ко мне?

Ещё есть кроссплатформенная Avalonia. Да, она не для C++. Но странно, что её не упомянули в статье.

Верно, под дотнет есть несколько родственных XAML-фреймврков и Avalonia одна из них. Но для меня представляли интерес библиотеки на C# поверх Авалонии и аналогичных, призванных писать во Flutter-стиле без XAML. Именно так я знакомился с объёмом задачи и с тем, какие хелперы придётся накрутить для поддержки декларативной записи.

В С++ оказалось несколько проще с перегрузкой операторов, это помогло отшлифовать синтаксис описания, он выглядит чище, чем в аналогичных проектах на C#.

И, самое главное, современные корутины C++ принесли полные аналоги async/await в экосистему С++, и GUI-первейшее законное их место, чтобы переводить кучерявый событийный код в уютный-плоский через новомодную асинхронщину.

Меня одного настораживает обилие в статье восторженных эпитетов, прилагательных в превосходной степени и подобного? :)

Есть немного. ))
Потому что "за державу обидно" (С).

Сложившееся реноме современного GUI (как такового) обитает где-то возле понятий "грязь", "тормоза", "говнокодинг" и прочее, и прочее... Могу ошибаться, конечно, но я "слышу" это примерно так. Хотя в этой области есть настоящие находки и отличные технологии, но которым просто не дали ума или которые незаслуженно малозаметны, или слишком нишевые и еще куча причин.

Но это всё был лишь фон, эдакий затянувшийся на десятки лет дискомфорт. Настоящим мотивом было еще одно важное слово - "гемморой". ))

А вот это уже вызов! С этим можно попробовать пободаться...

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации