WinRT — это COM ── IInspectable, .winmd, языковые проекции и почему WinUI до сих пор стоит на двоичном контракте

· Обновлено: · · Windows, WinRT, COM, WinUI, Windows App SDK, Разработка для Windows

История изменений (первая версия, опубликована 29 Aug 2026)
Первая публикация

В приложение WPF или WinForms хочется добавить новые возможности Windows. Но вызов пикера WinRT даёт исключение. Читаешь про WinUI — кажется, будто UI нужно строить заново. Такая растерянность складывается, если разделить устройство WinRT и выбор UI-фреймворка.

Отправная точка статьи: WinRT тоже стоит на двоичном контракте COM. Microsoft прямо пишет «The Windows Runtime is based on COM (Windows Runtime основан на COM)».1 И внедрение таблицы Excel в Word из предыдущей статьи про OLE-объект, и нынешние WinRT и WinUI в корне имеют тот же IUnknown.

Сначала фиксируем три составляющих WinRT, затем оговорки при вызове из настольного приложения, в конце — как обращаться с существующими активами. Кому — разработчики с опытом COM или настольной разработки Windows; среда — Windows 10/11 и .NET 6 и новее (C#) или C++17 (C++/WinRT); сложность — средняя.

1. Сначала выводы

Три вывода, которые стоит зафиксировать.

  • WinRT — не управляемая среда выполнения, а ABI (двоичный контракт) на базе COM. К контракту добавлены .winmd, передающий сведения о типах, и языковые проекции, чтобы вызов из каждого языка выглядел естественно.1234
  • Большинство WinRT API можно использовать из существующих приложений WPF, WinForms и Win32. Но нужно проверить три предпосылки: передачу HWND, package identity и инициализацию потока.5678
  • Полный переход UI на WinUI и частичное использование WinRT API — разные решения. WinUI тоже стоит на ABI WinRT; существующие активы COM/ActiveX и WinRT могут сосуществовать на одной основе.921

Дальше связи проще ловить в таком порядке.

Что нужно понять Главы
Почему можно сказать «WinRT — это COM» 2–3: общее с COM и IInspectable
Почему вызов из C# и C++ выглядит естественно 4–5: .winmd и языковые проекции
Что проверить, вызывая из существующего приложения 6: HWND, package identity, апартамент
Нужно ли переходить на WinUI 7–9: основание WinUI, решение о переходе, условия регистрации уведомлений

Карта знаний ниже — чтобы возвращаться к связям элементов. Если сначала читать объяснение — с главы 2 по порядку.

На схеме сплошная линия обозначает отношение, которое выполняется всегда, а пунктирная — условное отношение (условия указаны в пояснении к каждому отношению на странице сведений). Полный список отношений (всего 20, с доказательствами и степенью уверенности) и определения основных понятий собраны на странице сведений карты знаний (на японском). Данные: JSON-LD / Turtle

2. И у OLE, и у WinRT корень — тот же двоичный контракт

В блоге мы шли за классическим COM: замысел COM, модель потоков STA/MTA, обращение с ActiveX/OCX, составной документ OLE. Всё это техника с 1990-х.

WinRT — API-основа, введённая в Windows 8 (2012). Сейчас это набор API пространства имён Windows.*: тосты, общий доступ, Bluetooth, OCR; он же основание WinUI и Windows App SDK.10 На вид — совсем другой мир, по сути — непрерывность.

Общее обещание: вызывать через интерфейс

И COM-компонент, и класс WinRT открывают возможности через интерфейс. Сравнение базовых интерфейсов даёт такую связь.1

Классический COM WinRT
База интерфейса — IUnknown База интерфейса — IInspectable. Его база — IUnknown

То есть WinRT не заменили механизмом, не связанным с COM, а нарастили один слой над IUnknown. Счётчик ссылок, QueryInterface и HRESULT живут как есть.

Документация C++/WinRT тоже называет WinRT API «эволюцией COM (an evolution of COM)» и описывает дизайн: API на базе COM используют через языковые проекции.211

Родословная классического COM и WinRTНа общей основе двоичного контракта COM через IUnknown и vtable рядом стоят мир классического COM 1990-х — OLE, ActiveX — и мир WinRT с 2012 и WinUI с Windows App SDK над ним; они не исключают друг друга, а непрерывныДвоичный контракт COM (IUnknown, vtable)Классический COM (OLE, ActiveX, свой COM)WinRT (IInspectable, .winmd)WinUI / Windows App SDKМогут сосуществовать на одной основе

Рис. 1: Классический COM и WinRT — не разные миры, а два поколения на одном двоичном контракте.

Поэтому статья — не просто «знакомство с новым API». Это проверка, где знание COM, которое уже есть, работает в разработке Windows 2026 года.

3. IInspectable над IUnknown

Неизменная основа и три добавленных метода

Официальная спецификация системы типов WinRT фиксирует: каждый интерфейс WinRT неявно требует IInspectable, а IInspectable требует IUnknown. IUnknown по-прежнему определяет три метода: QueryInterface, AddRef, Release.12

Над ними IInspectable добавляет три метода.13

Метод Роль
GetIids Вернуть перечень IID интерфейсов, которые реализует этот объект
GetRuntimeClassName Вернуть полностью квалифицированное имя типа WinRT (Windows.Storage.StorageFile и т. п.) как HSTRING
GetTrustLevel Вернуть уровень доверия объекта
IInspectable над IUnknownКаждый интерфейс WinRT требует IInspectable, IInspectable требует IUnknown. IUnknown даёт QueryInterface, AddRef, Release; IInspectable — GetIids, GetRuntimeClassName, GetTrustLevel; сверху методы каждого интерфейса WinRTIUnknown (QI, AddRef, Release)IInspectable (GetIids, имя типа, уровень доверия)Методы каждого интерфейса WinRT

Рис. 2: Объект WinRT кладёт три метода IInspectable на три метода IUnknown, а сверху — отдельные API.

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

Важнее числа добавленных методов то, что имя типа можно связать с метаданными.

В классическом COM стандартный способ узнать натуру объекта во время выполнения — «знать IID и спросить через QueryInterface». Для скриптовых языков был отдельный путь IDispatch.

В WinRT имя типа из GetRuntimeClassName разрешают по метаданным .winmd следующей главы. Оттуда получают полное определение методов, свойств и событий. Сама спецификация говорит: возможность получить имя типа WinRT, разрешимое по метаданным, «делает языковые проекции возможными (enables language projection)».12

От GetRuntimeClassName к языковой проекцииВызывающая сторона вызывает GetRuntimeClassName объекта и получает полностью квалифицированное имя типа WinRT; разрешение этого имени в Windows Metadata даёт полное определение типа — и это делает проекцию в каждый язык возможнойОбъект WinRTИмя типа (GetRuntimeClassName)Разрешить определение типа в .winmdЯзыковые проекции становятся возможны

Рис. 3: «Во время выполнения можно взять имя типа, по имени типа — метаданные» — центр устройства WinRT.

«Наследование» и «требование» пользовательских интерфейсов разделяют

Есть и отличие, на которое смотрят привыкшие к COM. В системе типов WinRT нет наследования между пользовательскими интерфейсами. Производных вроде IFileSystemBindData2 : IFileSystemBindData классического COM намеренно нет; вместо этого объявляют «интерфейс A требует (requires) интерфейс B».121

Это отдельно от цепочки базы ABI IUnknownIInspectable, которую мы уже видели. Эта база остаётся основанием каждого интерфейса WinRT.

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

4. Что решило .winmd ── ад привязки сведений о типах

Трудность классического COM была в «как раздать сведения о типах»

На практике классического COM больше, чем сама реализация интерфейса, занимало как донести сведения о типах.

Кто использует Путь доставки сведений о типах
C++ Контракт пишут в IDL, MIDL порождает заголовки и прокси/заглушки
VB6, скрипты Раздают библиотеку типов (TLB)
.NET Отдельно делают сборку взаимодействия

У TLB ограничения типов, ближе к автоматизации: в IDL можно записать то, чего в TLB не будет. Плюс пути по языкам разные, поэтому устаревание одного ведёт к несовпадению типов. Эту боль разбирали в статье про библиотеку типов и dscom и статье про обратную совместимость интерфейсов DLL и COM.

.winmd — общий контракт, который читают все языки

Ответ WinRT — Windows Metadata (.winmd). API описывают машиночитаемыми метаданными; инструменты и языковые проекции читают их и порождают проекцию под каждый язык.3

Windows поставляет метаданные всех системных WinRT API и даёт API разрешения пространств имён и типов во время выполнения. В Windows SDK есть копия для времени компиляции. Сторонние тоже, приложив .winmd к своему компоненту WinRT, входят в языковые проекции тем же механизмом, что системные API.3

Что изменилось — форма раздаваемых сведений о типах. Вместо разъехавшихся по языкам TLB, заголовков и сборок взаимодействия одну .winmd читают проекции всех языков.

Но IDL не стал ненужным. Компонент WinRT по-прежнему описывают контрактом в IDL (MIDL 3.0, обновлённый под WinRT), и компилятор MIDL порождает .winmd.14

Конвейер изготовления компонента WinRTКонтракт компонента WinRT по-прежнему пишут в IDL, то есть MIDL 3.0; компилятор MIDL компилирует его в .winmd. Раздают именно эту .winmd; проекции каждого языка вроде cppwinrt.exe и cswinrt.exe читают её и порождают проекцию. Заменили не IDL, а форму раздаваемых сведений о типахОписать контракт (IDL, MIDL 3.0)Компилятор MIDL.winmd (раздаваемые сведения о типах)Породить проекцию каждого языка

Рис. 4: Вход контракта (IDL) по-прежнему в строю; выход раздаваемых сведений о типах унифицирован в .winmd.

Тот же формат файла, что у .NET, но не управляемая среда выполнения

Физический формат .winmd — та же спецификация ECMA-335, что у сборок CLR. Но правила допустимых сочетаний данных отличаются от сборок CLR. Взять формат и нуждаться в CLR для выполнения — разное.3

Здесь системные API и сторонние компоненты читают раздельно.

Объект Связь .winmd и реализации
Системные WinRT API .winmd — чистые метаданные без исполняемого кода. Реализация в машинных DLL ОС; CLR для выполнения не нужна
Сторонний компонент WinRT .winmd иногда содержит код реализации. У управляемого (написанного на C#) компонента с MSIL для выполнения нужна соответствующая среда .NET

Открыть .winmd инструментом — похоже на сборку .NET, отсюда частое «WinRT = управляемый». Но содержимое системного .winmd — контракт интерфейсов COM.3

Разделение .winmd и реализации.winmd — метаданные в физическом формате ECMA-335; системные не содержат исполняемого кода и суть контракт, реализация системных WinRT API — в машинных DLL ОС. Из-за этого разделения, хотя .winmd выглядит как сборка .NET, системным WinRT API CLR не нужен (у .winmd стороннего управляемого компонента есть MSIL и нужна среда .NET)Системные без кодаОпределение типа соответствует реализации.winmd (контракт, формат ECMA-335)Машинная DLL ОС (реализация)Системным API CLR не нужен

Рис. 5: У системных WinRT API .winmd — контракт, реализация — машинная DLL ОС. Формат в духе .NET, выполнение — машинный COM.

Сведения о типах классического COM против .winmdВ классическом COM пути сведений о типах расходились по языкам — из IDL заголовки C++, из библиотеки типов VB6 и скрипты, из сборки взаимодействия .NET — и это давало разъезд; в WinRT одну .winmd читают проекции всех языков сообщаКлассический COM: путь по языкамIDL → заголовок C++TLB → VB6, скриптыСборка взаимодействия → .NET.winmd (единые метаданные)Проекции всех языков читают сообща

Рис. 6: Раздачу сведений о типах, разъехавшуюся по языкам, .winmd сложила в форму «одни метаданные читают все».

Ограничения не исчезли — ось сменилась на удобство проекции

Для знающих классический COM одной фразой: .winmd — «библиотека типов заново». Роль, которую пыталась нести TLB, заново спроектировали на проверенном формате ECMA-335 как канон, общий всем языкам с самого начала — тогда место становится ясным.

Но ограничения не пропали. Ограничения TLB, ближе к автоматизации, сменились ограничениями собственной системы типов WinRT с осью «можно ли безопасно проецировать во все языки». Отсутствие наследования между пользовательскими интерфейсами из главы 3 — один пример.12

Поэтому существующий контракт COM/IDL не всегда можно перенести в WinRT как есть. Иногда API нужно проектировать заново.

Смена ограничений библиотеки типов на ограничения системы типов WinRTОграничения выразительности TLB (библиотеки типов), ближе к автоматизации, в .winmd не сняты, а сменились ограничениями собственной системы типов WinRT с осью безопасной проекции во все языки. Пример — отсутствие наследования пользовательских интерфейсов; существующий контракт COM/IDL не всегда переносится как есть, иногда API нужно проектировать зановоСменаОграничения TLB (ближе к автоматизации)Ограничения системы типов WinRT (ось проецируемости)Пример: пользовательское наследование нельзяСуществующий контракт COM иногда пересматривают

Рис. 7: Ограничения TLB не «исчезли», а сменились другими, с осью проецируемости во все языки.

5. C++/WinRT и C#/WinRT — не «обёртка», а проекция

Общий контракт показывают в естественной форме каждого языка

Когда есть общий контракт .winmd, показ в каждом языке можно породить инструментом. Это языковая проекция (language projection). WinRT API открывают в идиоме каждого языка, пряча детали COM, и дают опыт программирования, естественный для этого языка.411

Проекции, которые Microsoft поддерживает сейчас, две.4

Проекция Что порождает Черты
C++/WinRT cppwinrt.exe порождает из .winmd проекционные заголовки под C++ Проекция на заголовках стандартного C++17. Расширения языка вроде C++/CX не нужны; преемник C++/CX и WRL11
C#/WinRT (CsWinRT) cswinrt.exe порождает из .winmd код C# и делает сборку взаимодействия Проекция под .NET. Цепочка инструментов независима от среды выполнения1516

История стороны C# чуть путает, поэтому разделяют. До .NET Core 3.x использование WinRT/winmd среда .NET поддерживала встроенно. В .NET 5 эту встроенную поддержку сняли и перешли на C#/WinRT.16 WinRT API не перестали быть доступны — сменилось место, отвечающее за проекцию.

Сейчас в C# указание TFM вроде net8.0-windows10.0.19041.0 само подтягивает проекционную сборку Windows SDK.10

Порождение проекции каждого языка из .winmdОдну .winmd cppwinrt.exe читает и порождает проекционные заголовки под C++17, cswinrt.exe — сборку взаимодействия под C#; WinRT API открываются в идиоме каждого языка.winmd (контракт API)cppwinrt.exe → заголовки C++17cswinrt.exe → сборка взаимодействия C#Вызов в идиоме C++Вызов в идиоме C#

Рис. 8: Проекция — не рукописная обёртка, а то, что инструмент механически порождает из контракта (.winmd).

Даже порождённое автоматически, сущность вызова — по-прежнему COM

В статье говорим «проекция», а не «обёртка», чтобы подчеркнуть: это не слой перевода, который человек ведёт за каждым API, а механизм, выводимый из метаданных механически. API, лежащие в .winmd, с самого начала можно иметь во всех поддерживаемых языках.

И из какого бы языка ни вызывать, под проекцией происходит тот же вызов COM. Например, в C# await picker.PickSingleFolderAsync() — проекция мостит IAsyncOperation WinRT в мир Task .NET. На стороне ABI всё равно вызов метода через vtable и HRESULT. Поэтому ошибка является в виде исключения COM (HRESULT вроде 0x80070005).

Слои от кода C# до WinRT API ОСКод приложения на C# или C++ через языковую проекцию превращается в вызов vtable IInspectable ABI WinRT и доходит до WinRT API, который реализует ОС. Проекция прячет детали COM, сущность вызова — COMКод приложения (C#, C++)Языковая проекцияABI WinRT (vtable IInspectable)Реализация WinRT API ОС

Рис. 9: Проекция прячет «детали» COM, а не сам COM.

Зная эту структуру, неполадки делят на два слоя. Несовпадение версии порождённого кода или пропуск настройки TFM — слой проекции; HRESULT, апартамент, счётчик ссылок — слой ABI. Во втором опыт разработки COM — то же оружие.

6. Где спотыкается настольное приложение ── HWND, identity, апартамент

Сначала разделяют «можно сослаться на API» и «условия работы»

Большинство WinRT API можно вызывать из настольных приложений WPF, WinForms и Win32.5 Вход вызова в C# и C++ разный.10

Среда Первая настройка
C# / .NET 6 и новее TargetFramework в TFM с версией ОС Windows вроде net8.0-windows10.0.19041.0
C++ Пакет NuGet Microsoft.Windows.CppWinRT, C++/WinRT на C++17 и новее

Но «сослались» не значит, что каждый API сразу работает. Проверяют три пункта. Условия регистрации тостов отдельно — глава 9.

Что проверить Основная мера
Нужно ли окно места показа Передать HWND через COM interop под UI
Нужна ли package identity Дать identity упаковкой MSIX или пакетом, указывающим на внешнее расположение
Инициализирован ли поток под WinRT В машинном коде инициализировать, задав STA/MTA. В C# обычно занимается среда выполнения

Место 1: UI вроде пикера передают HWND

Часть пикеров, диалогов и UI общего доступа исходит из CoreWindow UWP как места показа. В настольном приложении CoreWindow нет, поэтому до показа явно передают HWND окна-владельца.6

Вход для пикеров — COM-интерфейс IInitializeWithWindow. Он наследует IUnknown и даёт объекту WinRT, которым пользуются в настольном приложении, окно-владелец.17

В C# HWND сначала получают в зависимости от UI-фреймворка.186

Окно-владелец Как получить HWND
Window WinUI WinRT.Interop.WindowNative.GetWindowHandle
Окно WPF WindowInteropHelper
Форма WinForms Свойство Handle формы

Затем передают пикеру WinRT.Interop.InitializeWithWindow.Initialize(picker, hwnd) и показывают. В C++/WinRT объект берут через as<IInitializeWithWindow>(), затем вызывают Initialize(hwnd). Пропустить инициализацию — исключение или тихий сбой.1819

Современному объекту WinRT через QueryInterface берут классический интерфейс COM и инициализируют. Что этот мост — официальный приём, тоже показывает: WinRT — это COM.

UI общего доступа — другой интерфейс. К DataTransferManager IInitializeWithWindow не применяют. Берут отдельный IDataTransferManagerInterop и передают HWND в ShowShareUIForWindow.6

Новые пикеры Windows App SDK — тоже другой путь. Microsoft.Windows.Storage.Pickers принимает WindowId в конструкторе, шаблон InitializeWithWindow не нужен. Но это не API, который работает от одной настройки TFM. Кроме внедрения Windows App SDK, для unpackaged-приложения предпосылка — развёртывание и инициализация среды выполнения на стороне доставки.19

Порядок показа пикера из настольного приложенияНастольное приложение после создания пикера, если сразу вызвать PickSingleFolderAsync, получает исключение или тихий сбой; нужно сначала взять HWND окна-владельца, передать через Initialize IInitializeWithWindow и затем показатьПикер (WinRT)Настольное приложениеПикер (WinRT)Настольное приложениеalt[Показать без HWND][Сначала передать HWND]СоздатьPickSingleFolderAsyncИсключение или тихий сбойЗадать HWND через IInitializeWithWindowPickSingleFolderAsyncПикер показывается

Рис. 10: «В настольном приложении нет CoreWindow» официально закрывают явной передачей HWND.

Место 2: есть API, которым нужна package identity

История тостов (ToastNotificationHistory), список переходов, цель общего доступа и часть других WinRT API работают только у приложения с package identity (упакованного). Вызов из unpackaged, которое разносят классическим установщиком, падает.7

Мер две. Упаковать в MSIX или, сохранив существующий установщик, дать идентификатор «пакетом, указывающим на внешнее расположение» (так называемый sparse package).20 Какие API требуют identity, сверяют по официальному перечню.7

Два пути к API, которым нужна package identityWinRT API, которым нужна package identity, из unpackaged падают; identity дают либо упаковкой MSIX, либо пакетом, указывающим на внешнее расположение, который оставляет существующий установщик и даёт только идентификаторХотим API, которым нужна identityУпаковать в MSIXПакет, указывающий на внешнее расположениеПолучить package identityРаботают история уведомлений и т. п.

Рис. 11: Мера для API с обязательной identity — развилка «MSIX» или «существующий установщик + идентификатор».

Место 3: проверяют инициализацию потока и STA/MTA

Потоку, который работает с объектами WinRT, нужна предварительная инициализация под WinRT. В машинном коде берут RoInitialize или winrt::init_apartment и задают модель параллельности STA/MTA. В приложениях C# WPF/WinForms инициализацией обычно занимается среда выполнения.8

RoInitialize — вход поколения WinRT в той же рамке, что CoInitializeEx COM. Документация CoInitialize сама указывает: если пользуетесь Windows Runtime, вместо этого вызывайте RoInitialize или Windows::Foundation::Initialize.21

Поток UI WPF/WinForms — STA; объекты UI трогают на потоке UI; блокирующее ожидание на STA ведёт к взаимной блокировке. Образ мысли из статьи про STA/MTA жив и для WinRT API.

Есть API, которые не заработают, даже подготовив HWND и identity

Меры выше — про API, у которых есть вход для настольного использования. API, которые сами зависят от CoreWindow или ApplicationView, в настольном приложении недоступны. Тогда инициализацию не добавляют — ищут замену.57

Развилка мест, где спотыкаются, вызывая WinRT API с рабочего столаСначала подтверждают, что поток инициализирован под WinRT (в машинном коде STA/MTA явно задают RoInitialize и т. п.; в C# обычно занимается среда выполнения); затем если нужный WinRT API — UI, исходящий из CoreWindow, передают HWND через IInitializeWithWindow или берут новый пикер; если нужна package identity — дают идентификатор MSIX или пакетом с внешним расположением; API, зависящие от самого CoreWindow или ApplicationView, на рабочем столе недоступны, ищут замену; остальные большинство API вызывают как есть после настройки TFM или C++/WinRTUIНужна identityЗависит от самого CoreWindowИначеИнициализация потокаКаков нужный API?В машинном коде явно, в C# обычно самоHWND или новый пикерMSIX или идентификаторИскать заменуВызывать как есть

Рис. 12: Исходя из инициализации потока (в машинном коде явно, в C# обычно на среде выполнения), места спотыкания делят на три линии, у каждой — типовая мера.

Соответствие инициализации потока COM и WinRTКлассический COM инициализирует поток CoInitializeEx, задавая STA или MTA; WinRT инициализирует RoInitialize, задавая ту же модель параллельности STA или MTA. Документация CoInitialize тоже указывает при WinRT вызывать RoInitialize; понятие апартамента общееКлассический COM: CoInitializeExАпартамент (STA / MTA)WinRT: RoInitializeПоток UI — STA, осторожно с ожиданием

Рис. 13: Имя API инициализации сменилось, понятие апартамента используют то же.

7. Основание WinUI ── открытая разработка не меняет контракт

Переход к открытой разработке — не смена двоичного контракта

Microsoft официально объявила летом 2025 поэтапный подход: основную разработку WinUI переносят на открытую площадку GitHub. Четыре этапа: чаще обновлять зеркало, дать локальную сборку, принять вклад сообщества после выстраивания тестов, в итоге сделать GitHub главной базой разработки.22

На момент публикации статьи (конец августа 2026) официальная документация тоже прямо пишет, что «WinUI разрабатывают открыто (built in the open)». Ход ежедневной инженерии можно смотреть в открытом репозитории.9

Разработчику, который шёл за сменой поколений WinForms → WPF → UWP → WinUI, естественно почувствовать «опять сменится фреймворк». Но сменявшиеся UI-фреймворки и основание под ними нужно смотреть раздельно. Win32 и COM и ABI WinRT с 2012 оставались на том же месте.

Окно WinUI тоже подкреплено HWND

WinUI — набор API WinRT, поставляемый как часть Windows App SDK.923 Его Microsoft.UI.Xaml.Windowокно, подкреплённое HWND, которое сменяет модель окна на базе CoreWindow поколения UWP. Официальный учебник взаимодействия тоже начинается с получения дескриптора окна.24

То есть приложение WinUI — приложение Win32, в котором на окне HWND работает дерево объектов по контракту IInspectable. И знание QueryInterface, счётчика ссылок и апартамента из COM, и знание HWND и цикла сообщений из Win32 в разборе неполадок WinUI работают как есть.

Смена поколений UI-фреймворков и неизменная основаWinForms, WPF, XAML UWP, WinUI — UI-фреймворки сменяли поколения, но WinForms и WPF сидят прямо на основе Win32 и COM, а XAML UWP и WinUI — на той же основе Win32 и COM через ABI WinRT. Сменялся верхний слой, контракт в основании не менялсяСмена поколений UI-фреймворковWinForms, WPFXAML UWPWinUI (сейчас)ABI WinRT (с 2012)Неизменная основа (Win32 + COM)

Рис. 14: Всплывал и оседал слой фреймворка. WinForms и WPF — прямо на Win32+COM, UWP и WinUI — через ABI WinRT на той же основе.

Слои, на которых стоит приложение WinUIXAML и элементы WinUI поставляются как часть Windows App SDK, работают на ABI WinRT, то есть контракте IInspectable, а ниже — основа COM и HWND Win32. Под сменой поколений UI-фреймворка этот контракт в основании не менялсяWinUI (XAML, элементы)Windows App SDKABI WinRT (IInspectable)COM + Win32 (HWND)

Рис. 15: Под WinUI — ABI WinRT, ещё ниже — классический COM и Win32. Сложилось иначе, основа та же.

Частичное смешение через XAML Islands оценивают с ограничениями поколения

Стратегию «в существующий экран WPF/WinForms смешать только элементы WinUI» нужно оценивать, разделив поколения XAML Islands.

Поколение Положение при использовании из WPF/WinForms
XAML Islands поколения UWP Есть элементы-обёртки Windows Community Toolkit. Но для WPF/WinForms — до поколения .NET Core 3.x, в нынешнем .NET не поддерживается25
Поколение WinUI 3 DesktopWindowXamlSource Windows App SDK умеет размещать из WPF, WinForms и Win32. Но удобных элементов-обёрток поколения UWP нет; нагрузка реализации и проверки — напрямую API размещения26

Планируя поэтапное смешение, безопаснее не исходить только из смешения на единицу элемента. На 2026 год крепче опираться на использование WinRT API на единицу функции (глава 6) и разделение на единицу экрана или процесса.

8. Следствия для бизнес-приложений ── полный переход и частичное использование раздельно

«WinRT — новый другой мир, чтобы пользоваться, существующие активы только выбросить и строить заново». Это недоразумение, с которым встречаются в практике заказной разработки, расходится, если разделить надвое.

Существующие активы COM и WinRT могут сосуществовать

В приложение WPF, которое пользуется автоматизацией Excel COM, несёт элементы ActiveX и вызывает собственный COM-компонент, можно добавить WinRT API. Это не трюк, а сочетание возможностей на одной основе COM.

Например тосты: настраивают TFM, ссылаются на API и выполняют условия регистрации, чтобы уведомление вышло. Чтобы второе не забыть, в главе 9 разбираем по путям. В C++/WinRT интерфейсы и WinRT, и классического COM ведут одним механизмом winrt::com_ptr и winrt::implements.21

Обновление UI и добавление функции оценивают отдельно

«Полностью переносить UI на WinUI» и «использовать WinRT API только где нужно» — решения разного масштаба, срока и риска.

Полный переход UI — вопрос выбора фреймворка, зависит от экранных активов, сторонних элементов и организации разработки. Это решение разбирали в WinForms, WPF или WinUI: практическая таблица выбора. Частичное использование WinRT API — небольшое улучшение, к которому существующее приложение можно приступить сегодня.

В заказе, где нужны только тосты, полный переход UI оценивать не нужно. И наоборот: из «на WinUI не переходим» не следует откладывать и использование WinRT API.

Полный переход и частичное использование — разные решенияПолный переход UI на WinUI — большое решение выбора фреймворка, зависит от экранных активов и организации; частичное использование WinRT API — малое решение, которое в существующее приложение WPF или WinForms добавляют сегодня настройкой TFM; эти два не смешивают«Хотим новые возможности Windows»Полный переход UI (большое решение)Частичное использование WinRT API (малое решение)Зависит от экранных активов и организацииВ существующее приложение — сегодня

Рис. 16: К «новой возможности» два пути; смешать — сбить и оценку, и решение.

9. Таблица решений ── WinRT-версия «оставить, обернуть, заменить»

По ситуации выбирают только нужное изменение

Как продолжение таблицы решений ActiveX, сводим решения WinRT по ситуациям.

Ситуация Рекомендация Почему
Из WPF/WinForms хотим тосты, общий доступ, Bluetooth и другие WinRT API Частично использовать настройкой TFM (или внедрением C++/WinRT) Вызывать сегодня без перехода UI. Но UI общего доступа — через IDataTransferManagerInterop (глава 6); тосты — дополнение под таблицей106
Исключение / тихий сбой пикера или диалога Передать HWND через IInitializeWithWindow. Для нового — новый пикер с WindowId (нужно внедрение Windows App SDK) Официальный приём закрыть дизайн, исходящий из CoreWindow, через HWND619
Не работают история уведомлений, список переходов и т. п. Дать package identity упаковкой MSIX или пакетом с внешним расположением API с обязательной identity исходят из упаковки720
Существующие активы COM/ActiveX/OLE Не выбрасывать. Оставить / обернуть / заменить — по активу Не исключают WinRT, сосуществуют на одной основе (глава 8)
UI нового настольного приложения WinUI как первый кандидат (WPF тоже в строю) Открытая разработка прояснила направление вложений. Основание — ABI WinRT229
Частично смешать элементы WinUI в существующий экран WPF/WinForms Оценивать осторожно, закладывая нагрузку реализации без обёрток Islands поколения UWP — до .NET Core 3.x; поколение WinUI 3 — только API размещения2526
План исходя из «WinRT кончился вместе с UWP» Поправить предпосылку WinRT — нынешняя API-основа, вызываемая с рабочего стола5

Тост одной настройки TFM на экран не выйдет

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

Путь классического ToastNotificationManager

У unpackaged без package identity предпосылка — регистрация ярлыка меню «Пуск» с назначенным AppUserModelID (AUMID). Без него тост не вывести.27

У упакованного MSIX identity пакета даёт AUMID, эта ручная регистрация не нужна.

Путь AppNotificationManager Windows App SDK

На рекомендуемом сейчас пути нужны внедрение Windows App SDK и вызов Register() при запуске. Дальше условия расходятся по форме пакета.28

Форма пакета Что проверить дополнительно
unpackaged Нужно развернуть среду выполнения Windows App SDK на каждом ПК доставки. Register() выполняет регистрацию COM-сервера
Упакован в MSIX Автоматическая регистрация Register() не работает. В Package.appxmanifest объявляют COM-активатор

Плюс на пути Windows App SDK уведомления из процесса, повышенного до администратора, не поддерживаются. Show не бросает исключение и тихо сбоит. Приложению, которому нужно повышение, стоит отдать уведомления отдельному неповвышенному процессу.28

Подробности реализации регистрации — в Значок в области уведомлений и toast в Windows-приложении: ошибки NotifyIcon и выбор AppNotification.

Два пути тоста и нужная регистрацияЧтобы вывести тост из настольного приложения, классический путь ToastNotificationManager ветвится по packaged: unpackaged проходит регистрацию ярлыка меню Пуск с AppUserModelID, packaged получает AppUserModelID от identity пакета. Путь AppNotificationManager Windows App SDK кроме внедрения SDK и Register при запуске для unpackaged требует развёртывания среды выполнения на каждом ПК доставки, для упакованного MSIX — объявления COM-активатора в манифесте. Дальше на пути Windows App SDK ветвь повышен ли процесс: уведомления из процесса, повышенного до администратора, не поддерживаются, Show тихо сбоит, поэтому на этом пути уведомление показывается только у неповвышенного процесса; приложению с повышением уведомления отделяют в неповвышенный процессНетДаНетДаНетДаХотим вывести тостКлассика: ToastNotificationManagerWASDK: AppNotificationManagerpackaged?Регистрация ярлыка AUMIDidentity даёт AUMIDВнедрение SDK + Register()packaged?Развернуть среду выполненияCOM-объявление в манифестеУведомление показываетсяПовышенный процесс?Не поддерживается: Show тихо сбоитУведомления отделить в неповвышенный процесс

Рис. 17: Оба пути доходят до показа, только выполнив предпосылки формы упаковки. Путь Windows App SDK даже при всех предпосылках из повышенного процесса не показывает.

В конце возвращаются к «оставить, обернуть, заменить»

Нужна новая возможность или обновить сам UI. Вернувшись к этому вопросу, использование WinRT и замену существующих активов решают раздельно.

Поток решения, как жить с существующими активами и WinRTОт существующего настольного приложения: если новые возможности Windows не нужны — оставить; если нужны — обернуть частичным использованием WinRT API (тогда смотреть места спотыкания HWND, package identity и инициализации потока главы 6); замену на WinUI рассматривать, только когда нужно обновить сам UIХватает как естьНовая возможностьОбновить UIСуществующее настольное приложениеЧто нужно?Оставить (сопровождать как есть)Обернуть (частично использовать WinRT API)Заменить (оценить WinUI)Смотреть HWND, identity, инициализацию (глава 6)

Рис. 18: Та же схема «оставить, обернуть, заменить», что у таблицы решений ActiveX, ложится и на сторону WinRT.

10. Итог

WinRT — не новая среда выполнения, отвязанная от COM. Это API-основа, в которой двоичный контракт COM сочетают с метаданными и проекцией в каждый язык.

Элемент Роль, зафиксированная в статье
IUnknown и IInspectable Основа — QueryInterface и счётчик ссылок; добавляют три метода получения имени типа и прочего
.winmd Общий всем языкам контракт, по которому из имени типа берут определение. Берёт формат ECMA-335; системные исполняемого кода не содержат
C++/WinRT, C#/WinRT Из контракта порождают API под каждый язык. Проекция C# с .NET 5 — цепочка инструментов, независимая от среды выполнения

Даже если снаружи естественный API C# или C++, внизу вызов COM через vtable и HRESULT. Поэтому, поняв передачу HWND на рабочем столе, package identity, STA/MTA и инициализацию потока, неполадки WinRT тоже проще разбирать.

Перенос основной разработки WinUI на открытую площадку объявили летом 2025 как поэтапный подход. На момент публикации в официальной документации тоже «built in the open», но контракт внизу IUnknownIInspectable от этого не сменился.229

Вывод для бизнес-приложений тот же. Существующие активы COM/ActiveX и WinRT могут сосуществовать. Не смешивать полный переход UI и частичное использование WinRT API — так держат точность оценки и решения.

И составной документ 1990-х из статьи про OLE, и нынешний WinUI стоят на том же IUnknown. Знать COM — не просто «разбираться в наследии». Это уметь читать основание нынешней Windows.

Похожие статьи

Смежные области консультирования

Компания KomuraSoft LLC занимается разработкой COM-компонентов и сопровождением, доработкой и заменой Windows-бизнес-приложений, в которых есть активы COM. Можно начать с этапа, где содержание этой статьи и есть вопрос: «оставить WPF и пользоваться тостами и пикером», «вызов WinRT API остановился исключением», «переходить на WinUI или опираться на существующие активы».

Справочные ссылки

  1. Microsoft Learn, Author COM components with C++/WinRT. О том, что и COM-компонент, и класс WinRT открывают возможности интерфейсами; прямое «The Windows Runtime is based on COM»; интерфейс классического COM происходит от IUnknown, интерфейс WinRT — от IInspectable, IInspectable — от IUnknown; производные пользовательских интерфейсов вроде IFileSystemBindData2 : IFileSystemBindData — возможность классического COM, в системе типов WinRT их намеренно нет.  2 3 4 5 6

  2. Microsoft Learn, Consume COM components with C++/WinRT. О том, что в COM программируют не объектами, а через интерфейсы; это же за кулисами WinRT API, эволюции COM (an evolution of COM); умный указатель COM winrt::com_ptr ведёт WinRT и классический COM одним приёмом.  2 3 4

  3. Microsoft Learn, Windows Metadata (WinMD) files. О том, что WinRT API описывают машиночитаемыми метаданными .winmd, которыми пользуются инструменты и языковые проекции; Windows поставляет метаданные всех системных WinRT API и API разрешения; сторонние входят в языковые проекции тем же форматом; физический формат — спецификация ECMA-335 (как у сборок CLR), системный WinMD — чистые метаданные.  2 3 4 5

  4. Microsoft Learn, Windows Runtime (WinRT) language projections. О том, что языковая проекция открывает WinRT API в идиоме каждого языка; .winmd определяет WinRT API, проекция его читает; Microsoft поддерживает две: C++/WinRT (C++17 и новее) и C#/WinRT (.NET).  2 3

  5. Microsoft Learn, WinRT APIs callable from a desktop app. О том, что большинство WinRT API доступны из настольных приложений .NET и машинного C++; исключения — классы, спроектированные только для UWP, вроде CoreDispatcher, CoreWindow, ApplicationView.  2 3 4

  6. Microsoft Learn, Display WinRT UI objects that depend on CoreWindow. О том, что часть пикеров, всплывающих окон и диалогов зависит от CoreWindow; CoreWindow в настольном приложении не поддерживается; классам, реализующим IInitializeWithWindow (или равносильный IDataTransferManagerInterop), до показа можно задать HWND окна-владельца; порядок для WinUI 3, WPF и WinForms.  2 3 4 5 6

  7. Microsoft Learn, WinRT APIs not supported in desktop apps. О двух линиях WinRT API, недоступных в настольном приложении: API, зависящие от UI-возможностей только UWP, и API, требующие package identity (ToastNotificationHistory, JumpList и т. п.); вторые поддерживаются только у приложения, упакованного MSIX.  2 3 4 5

  8. Microsoft Learn, RoInitialize function (roapi.h). О том, что RoInitialize инициализирует текущий поток под Windows Runtime с указанной моделью параллельности (RO_INIT_SINGLETHREADED / RO_INIT_MULTITHREADED); каждый поток, который активирует и оперирует объектами WinRT, нуждается в предварительной инициализации; противоречащее указание на потоке, уже инициализированном как MTA, даёт RPC_E_CHANGED_MODE.  2

  9. Microsoft Learn, WinUI 3. О том, что WinUI — рекомендуемый нативный UI-фреймворк для новых настольных приложений Windows; поставляется как часть Windows App SDK; работает с Windows 10 версии 1809; разрабатывается открыто.  2 3 4 5

  10. Microsoft Learn, Call Windows Runtime APIs in desktop apps. О том, что с .NET 6 указание TFM с версией ОС Windows (net10.0-windows10.0.22621.0 и т. п.) подтягивает пакет нацеливания Windows SDK и даёт вызывать WinRT API; в C++ — пакет NuGet Microsoft.Windows.CppWinRT и C++/WinRT на C++17 и новее.  2 3 4

  11. Microsoft Learn, Introduction to C++/WinRT. О том, что C++/WinRT — языковая проекция полностью на стандартном современном C++17, реализованная как библиотека на заголовках; рекомендуемый преемник C++/CX и WRL; WinRT спроектирован на API COM с доступом через языковые проекции; проекция прячет детали COM; cppwinrt.exe порождает проекционные заголовки из .winmd.  2 3

  12. Microsoft Learn, The Windows Runtime (WinRT) type system. О том, что каждый интерфейс WinRT неявно требует IInspectable, IInspectable требует IUnknown; IUnknown определяет QueryInterface, AddRef, Release; три метода, которые добавляет IInspectable: GetIids, GetRuntimeClassName, GetTrustLevel; GetRuntimeClassName возвращает имя типа, разрешимое по метаданным, и это делает языковые проекции возможными; наследования между пользовательскими интерфейсами в системе типов WinRT нет, выражают через requires.  2 3 4

  13. Microsoft Learn, IInspectable interface (inspectable.h). О том, что IInspectable даёт возможности, нужные каждому классу WinRT; наследует IUnknown; имеет три метода GetIids, GetRuntimeClassName, GetTrustLevel. 

  14. Microsoft Learn, Introduction to Microsoft Interface Definition Language 3.0. О том, что MIDL 3.0 — сжатый современный синтаксис объявления типов WinRT; контракт WinRT по-прежнему пишут в IDL, компилятор MIDL порождает метаданные Windows (.winmd). 

  15. Microsoft Learn, C#/WinRT. О том, что cswinrt.exe в пакете NuGet C#/WinRT обрабатывает .winmd, порождает код C# и компилирует в сборку взаимодействия; то же место, что у C++/WinRT, порождающего заголовки под C++. 

  16. Microsoft Learn, Built-in support for WinRT is removed from .NET. О том, что в .NET 5 встроенную поддержку Windows Runtime сняли из .NET и перешли на цепочку инструментов CsWinRT.  2

  17. Microsoft Learn, IInitializeWithWindow interface (shobjidl_core.h). О интерфейсе, который даёт объекту WinRT, используемому в настольном приложении, окно-владелец; наследует IUnknown и имеет метод Initialize(HWND). 

  18. Microsoft Learn, Use WinRT COM interop classes in .NET. О том, что часть объектов WinRT вроде пикера файлов и диалога до работы в настольном приложении нуждается в HWND; типобезопасные классы C# WinRT.Interop.WindowNative и WinRT.Interop.InitializeWithWindow позволяют инициализировать без рукописного QueryInterface.  2

  19. Microsoft Learn, Tutorial: Open files and folders with pickers in WinUI. О том, что классические Windows.Storage.Pickers в настольном приложении (WinUI 3) без инициализации HWND до показа дают исключение или тихий сбой; у настольного приложения WinUI 3 нет CoreWindow; новые пикеры Windows App SDK (Microsoft.Windows.Storage.Pickers) принимают WindowId в конструкторе, шаблон InitializeWithWindow не нужен.  2 3

  20. Microsoft Learn, Features that require package identity. О том, что часть возможностей Windows и WinRT API во время выполнения требуют package identity; кроме раздачи пакетом MSIX идентификатор даёт и пакет, указывающий на внешнее расположение (packaged with external location).  2

  21. Microsoft Learn, CoInitialize function (objbase.h). О том, что CoInitialize инициализирует библиотеку COM как STA; новым приложениям следует вызывать CoInitializeEx; при Windows Runtime вместо этого нужно вызывать RoInitialize или Windows::Foundation::Initialize. 

  22. GitHub, WinUI: Now Developing in the Open (microsoft/microsoft-ui-xaml Discussion #10700). Официальное объявление конца июля 2025. Поэтапный подход к открытию репозитория WinUI: чаще обновлять зеркало, дать локальную сборку, принять вклад сообщества после выстраивания тестов, в итоге сделать GitHub главной базой разработки.  2 3

  23. Microsoft Learn, Windows App SDK. О том, что Windows App SDK — нынешний набор библиотек разработки приложений Windows, включающий WinUI. 

  24. Microsoft Learn, Walkthrough: WinUI 3 app with Win32 interop. О том, что класс Window WinUI расширен поддержкой настольного окна; в настольном приложении WinUI 3 Window подкреплён дескриптором окна Win32 (HWND), его можно взять и оперировать Win32 API. 

  25. Microsoft Learn, Host UWP XAML controls in desktop apps (UWP XAML Islands). О том, что XAML Islands поколения UWP — механизм посадки элементов UWP XAML в настольные приложения WPF, WinForms и C++; использование из WPF/WinForms ограничено приложениями поколения .NET Core 3.x и в нынешнем .NET и .NET Framework не поддерживается.  2

  26. Microsoft Learn, DesktopWindowXamlSource Class (Microsoft.UI.Xaml.Hosting). О центральном классе API размещения XAML Windows App SDK; умеет размещать элементы WinUI в произвольном элементе UI, связанном с HWND; доступен из настольных приложений WPF, Windows Forms и Win32 (Windows API).  2

  27. Microsoft Learn, Quickstart: Sending a toast notification from the desktop. О том, что отправка тоста из настольного приложения исходит из ярлыка меню «Пуск» с System.AppUserModel.ID; в CreateToastNotifier нужно передать этот AppUserModelID, иначе тост не покажется. 

  28. Microsoft Learn, Use app notifications with a .NET app. О том, что в приложении WPF/WinForms для AppNotificationManager Windows App SDK после регистрации обработчика NotificationInvoked нужно вызвать Register(); у unpackaged Register() сам регистрирует COM-сервер, чтобы при щелчке по уведомлению запустить приложение; предпосылки — внедрение Windows App SDK и конфигурация вызова WinRT API.  2

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

Эти страницы показывают тему статьи в более широком контексте услуг и решений.

Статья напрямую связана со следующими услугами.

Частые вопросы

Вопросы, которые часто возникают при консультациях по теме статьи.

WinRT — управляемая среда выполнения вроде .NET?
Нет. WinRT (Windows Runtime) — не среда выполнения с виртуальной машиной и сборщиком мусора, а ABI (двоичный контракт) на базе COM. Документация Microsoft прямо пишет «The Windows Runtime is based on COM»; каждый интерфейс WinRT требует IInspectable, происходящий от IUnknown. Сущность вызова по-прежнему COM через vtable, на AddRef/Release и QueryInterface. Имя «.winmd» и близость к .NET часто принимают за управляемую среду, но .winmd — файл метаданных, который берёт тот же физический формат, что ECMA-335; системный .winmd исполняемого кода не содержит. Из C# вызов выглядит естественно, потому что языковая проекция порождает проекцию под C# из метаданных.
Говорят, UWP уже не мейнстрим. Есть ли смысл учить WinRT сейчас?
Есть. Модель приложений UWP и API-основа WinRT — разное. После сжатия UWP большинство WinRT API по-прежнему дают вызывать из настольных приложений WPF, WinForms и Win32; многие «нынешние возможности Windows» — тосты, общий доступ, Bluetooth, OCR — опубликованы как WinRT API. И WinUI (Windows App SDK), нативный UI-фреймворк, который Microsoft сейчас рекомендует, стоит на ABI WinRT. То есть устройство WinRT (IInspectable, .winmd, языковые проекции) — не наследство UWP, а само основание нынешней разработки приложений Windows.
Можно ли вызывать WinRT API из приложения WPF или WinForms?
Можно. С .NET 6 достаточно поставить TargetFramework проекта в TFM с версией ОС Windows вроде net8.0-windows10.0.19041.0 — подтянется проекционная сборка Windows SDK, и WinRT API пространства имён Windows.* вызывают прямо из C#. В C++ ставят пакет NuGet Microsoft.Windows.CppWinRT и берут C++/WinRT на C++17 и новее. Но есть три места, где спотыкаются. Первое: UI-классам, исходящим из CoreWindow, вроде пикеров и диалогов, до показа нужно передать HWND окна-владельца через IInitializeWithWindow (исключение — DataTransferManager UI общего доступа: не IInitializeWithWindow, а отдельный IDataTransferManagerInterop, HWND передают в ShowShareUIForWindow). Второе: часть API вроде истории уведомлений и списка переходов требует package identity (упаковка MSIX или пакет, указывающий на внешнее расположение). Третье: потоку, который работает с объектами WinRT, нужна предварительная инициализация. В машинном коде модель параллельности STA/MTA задают winrt::init_apartment или RoInitialize (в приложениях C# WPF/WinForms этим обычно занимается среда выполнения). API, которые сами зависят от CoreWindow или ApplicationView, в настольном приложении изначально недоступны.
В настольном приложении вызов пикера вроде FolderPicker даёт исключение. Почему?
Потому что часть WinRT-классов пикеров и диалогов спроектирована исходя из CoreWindow UWP как места показа. В настольном приложении CoreWindow нет, поэтому до показа нужно явно указать окно-владелец. Конкретно: сначала получают HWND окна-владельца (у Window WinUI — WinRT.Interop.WindowNative.GetWindowHandle, у WPF — WindowInteropHelper, у WinForms — свойство Handle формы) и в C# передают пикеру через WinRT.Interop.InitializeWithWindow.Initialize. В C++/WinRT объект приводят к IInitializeWithWindow (as<IInitializeWithWindow>()) и вызывают Initialize(hwnd). Без этой инициализации будет исключение или тихий сбой. Новые пикеры Windows App SDK (Microsoft.Windows.Storage.Pickers) переделаны: WindowId принимают в конструкторе, сам этот шаблон инициализации не нужен (это API Windows App SDK, одного TFM мало: нужны внедрение SDK и, для unpackaged-приложения, развёртывание и инициализация среды выполнения на стороне доставки).
Разработку WinUI вроде открыли на GitHub. Существующие приложения WPF/WinForms нужно выбрасывать?
Спешить выбрасывать не нужно. Открытие основной разработки WinUI — заявление направления «Microsoft всерьёз вкладывается в нативный фреймворк», а не объявление о прекращении существующих фреймворков. WPF и WinForms по-прежнему поддерживаются как часть .NET. Решение делят надвое. Одно — переносить ли UI-фреймворк: это большой разговор, зависящий от объёма экранных активов, сторонних элементов и организации разработки. Другое — частично ли использовать WinRT API из существующего приложения: это начинают сегодня настройкой TFM. Но TFM только даёт вызывать API; например тосту кроме вызова нужна регистрация уведомления (классический путь — для unpackaged регистрация ярлыка меню «Пуск» с AppUserModelID; у упакованного identity пакета даёт AppUserModelID, вручную не нужно; путь Windows App SDK — внедрение SDK, для unpackaged ещё среда выполнения Windows App SDK на каждом ПК доставки, и вызов Register() у AppNotificationManager; у упакованного MSIX автоматическая регистрация Register() не работает, плюс в Package.appxmanifest нужно объявить COM-активатор). И на пути Windows App SDK уведомления из процесса, повышенного до администратора, не поддерживаются: Show не бросает исключение и тихо сбоит — приложению, которому нужно повышение, стоит отдать уведомления отдельному неповвышенному процессу. Даже тогда, если нужны только тосты, переход на WinUI не требуется. Частичное смешение элементов WinUI в существующие экраны WPF/WinForms (XAML Islands) нужно оценивать по поколениям. Islands поколения UWP для WPF/WinForms поддерживаются только до .NET Core 3.x; у поколения WinUI 3 API размещения XAML Windows App SDK (DesktopWindowXamlSource) доступен и из WPF/WinForms, но удобных элементов-обёрток нет, нагрузка реализации велика, поэтому сейчас безопаснее оценивать осторожно.

Об авторе

Страница с профилем автора статьи.

Го Комура

Представитель KomuraSoft LLC

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

Публичные ссылки

Вернуться в блог