WinRT ist COM — IInspectable, .winmd, Sprachprojektionen und warum WinUI weiterhin auf einem Binärvertrag sitzt
· Aktualisiert am: · Go Komura · Windows, WinRT, COM, WinUI, Windows App SDK, Windows-Entwicklung
Änderungsverlauf (Erstfassung, veröffentlicht am 29. Aug 2026)
- Erstveröffentlichung
Sie möchten einer WPF- oder WinForms-Anwendung eine neue Windows-Funktion hinzufügen. Der Aufruf eines WinRT-Pickers löst jedoch eine Ausnahme aus. Lesen Sie dann über WinUI, und es wirkt, als müssten Sie die Benutzeroberfläche neu bauen. Diese Verwirrung löst sich, sobald Sie die Funktionsweise von WinRT von der Wahl des UI-Frameworks trennen.
Der Ausgangspunkt dieses Artikels ist, dass auch WinRT auf dem COM-Binärvertrag sitzt. Microsoft selbst hält klar fest: „The Windows Runtime is based on COM“.1 Die in Word eingebettete Excel-Tabelle aus dem vorigen Artikel zu OLE-Objekten und das heutige WinRT und WinUI haben dasselbe IUnknown an der Wurzel.
Hier halten wir zuerst die drei Elemente fest, aus denen WinRT besteht, betrachten dann, worauf bei der Nutzung aus einer Desktop-App zu achten ist, und überlegen schließlich, wie bestehende Assets zu behandeln sind. Die vorgesehenen Leser sind Entwicklerinnen und Entwickler mit Erfahrung in COM oder der Windows-Desktopentwicklung, die Voraussetzungen sind Windows 10/11 und .NET 6 oder höher (C#) oder C++17 (C++/WinRT), der Schwierigkeitsgrad ist Mittelstufe.
1. Zuerst die Kernaussage
Es gibt drei Schlussfolgerungen, die Sie festhalten sollten.
- WinRT ist keine verwaltete Laufzeit, sondern ein auf COM aufgebautes ABI (ein Binärvertrag). Zu diesem Vertrag kommen
.winmd, das Typinformationen trägt, und Sprachprojektionen, mit denen jede Sprache natürlich aufrufen kann.1234 - Die meisten WinRT-APIs lassen sich aus bestehenden WPF-, WinForms- und Win32-Apps nutzen. Drei Voraussetzungen müssen jedoch geprüft werden: die Übergabe eines HWND, die Paketidentität und die Threadinitialisierung.5678
- Eine vollständige UI-Migration nach WinUI und die gezielte Nutzung von WinRT-APIs sind getrennte Entscheidungen. Auch WinUI sitzt auf dem WinRT-ABI, und bestehende COM/ActiveX-Assets und WinRT können auf derselben Grundlage koexistieren.921
Ab hier fällt der Zusammenhang am leichtesten, wenn Sie in der folgenden Reihenfolge lesen.
| Was Sie wissen möchten | Wo Sie lesen |
|---|---|
| Warum lässt sich sagen „WinRT ist COM“? | Abschnitte 2–3: was es mit COM teilt, und IInspectable |
| Warum können C# und C++ so natürlich aufrufen? | Abschnitte 4–5: .winmd und Sprachprojektionen |
| Was muss geprüft werden, um es aus einer bestehenden App zu nutzen? | Abschnitt 6: HWND, Paketidentität, Apartments |
| Sollen wir nach WinUI migrieren? | Abschnitte 7–9: worauf WinUI sitzt, die Migrationsentscheidung, die Registrierungsbedingungen für Benachrichtigungen |
Die Wissenskarte unten dient dazu, die Beziehungen der Elemente nachzuschlagen. Wenn Sie lieber zuerst die Erklärung lesen, fahren Sie der Reihe nach mit Abschnitt 2 fort.
In der Abbildung kennzeichnet eine durchgezogene Linie eine stets geltende Beziehung und eine gestrichelte Linie eine bedingte (die Bedingungen stehen bei jeder Beziehung auf der Detailseite). Die vollständige Liste der Beziehungen (20 insgesamt, mit Beleg und Sicherheitsgrad) und die Definitionen der wichtigsten Konzepte sind auf der Detailseite der Wissenskarte (auf Japanisch) zusammengestellt. Daten: JSON-LD / Turtle
2. OLE und WinRT teilen an der Wurzel denselben Binärvertrag
In diesem Blog haben wir bisher die Welt des klassischen COM verfolgt: die Entwurfsphilosophie von COM, das Threadmodell STA/MTA, der Umgang mit ActiveX/OCX und OLE-Verbunddokumente. All das sind Technologien aus den 1990er-Jahren.
WinRT dagegen ist die mit Windows 8 (2012) eingeführte API-Grundlage. Heute stellt sie Toastbenachrichtigungen, Freigabe, Bluetooth, OCR und mehr als die APIs in den Windows.*-Namespaces bereit und ist auch das, worauf WinUI und das Windows App SDK stehen.10 Alt und neu wirken wie völlig getrennte Welten, inhaltlich sind sie jedoch durchgängig.
Was sie teilen, ist das Versprechen, über Schnittstellen aufzurufen
COM-Komponenten und WinRT-Klassen legen ihre Funktionalität beide über Schnittstellen offen. Vergleicht man die Basisschnittstellen, sieht die Beziehung so aus.1
| Klassisches COM | WinRT |
|---|---|
Die Basis jeder Schnittstelle ist IUnknown |
Die Basis jeder Schnittstelle ist IInspectable, dessen Basis IUnknown ist |
Mit anderen Worten: WinRT hat COM nicht durch einen fremden Mechanismus ersetzt; es ist eine weitere Schicht, auf IUnknown gestapelt. Referenzzählung, QueryInterface und HRESULT leben alle so weiter, wie sie waren.
Die C++/WinRT-Dokumentation nennt die WinRT-APIs ebenfalls „an evolution of COM“ und erklärt, dass sie als COM-basierte APIs über Sprachprojektionen genutzt werden sollen.211
flowchart TB
accTitle: Die Abstammung von klassischem COM und WinRT
accDescr: Auf der gemeinsamen Grundlage des COM-Binärvertrags aus IUnknown und vtables stehen nebeneinander die klassische COM-Welt von OLE und ActiveX aus den 1990er-Jahren und die Welt von WinRT ab 2012 mit WinUI und dem Windows App SDK darauf; die beiden schließen einander nicht aus, sondern sind durchgängig
base["COM-Binärvertrag (IUnknown, vtable)"]
base --> classic["Klassisches COM (OLE, ActiveX, eigenes COM)"]
base --> winrt["WinRT (IInspectable, .winmd)"]
winrt --> winui["WinUI / Windows App SDK"]
classic -.-> coexist["Können auf derselben Grundlage koexistieren"]
winrt -.-> coexist
Abbildung 1: Klassisches COM und WinRT sind keine getrennten Welten, sondern zwei Generationen, alt und neu, auf demselben Binärvertrag.
Deshalb ist dieser Artikel nicht bloß „eine Einführung in eine neue API“. Es ist ein Artikel, der bestätigt, wo das COM-Wissen, das Sie bereits haben, in der Windows-Entwicklung von 2026 greift.
3. IInspectable auf IUnknown
Das unveränderte Fundament und die drei hinzugefügten Methoden
Die offizielle Spezifikation des WinRT-Typsystems legt fest, dass jede WinRT-Schnittstelle implizit IInspectable fordert und IInspectable IUnknown fordert. Was IUnknown definiert, sind wie immer die drei Methoden QueryInterface, AddRef und Release.12
Darüber fügt IInspectable die folgenden drei Methoden hinzu.13
| Methode | Rolle |
|---|---|
GetIids |
Gibt die Liste der IIDs der Schnittstellen zurück, die dieses Objekt implementiert |
GetRuntimeClassName |
Gibt den vollständig qualifizierten WinRT-Typnamen (etwa Windows.Storage.StorageFile) als HSTRING zurück |
GetTrustLevel |
Gibt die Vertrauensstufe des Objekts zurück |
flowchart TB
accTitle: IInspectable, das auf IUnknown sitzt
accDescr: Jede WinRT-Schnittstelle fordert IInspectable, und IInspectable fordert IUnknown. IUnknown stellt QueryInterface, AddRef und Release bereit; IInspectable stellt GetIids, GetRuntimeClassName und GetTrustLevel bereit; und die Methoden jeder WinRT-Schnittstelle sitzen darauf
unk["IUnknown (QI, AddRef, Release)"]
insp["IInspectable (GetIids, Typname, Vertrauensstufe)"]
api["Methoden der jeweiligen WinRT-Schnittstelle"]
unk --> insp
insp --> api
Abbildung 2: Ein WinRT-Objekt stapelt die drei Methoden von IInspectable auf die drei Methoden von IUnknown, und die einzelnen APIs sitzen darauf.
Von einem Typnamen zu den Definitionen von Methoden, Eigenschaften und Ereignissen
Was zählt, ist nicht die Zahl der hinzugefügten Methoden, sondern die Fähigkeit, einen Typnamen mit Metadaten zu verbinden.
Im klassischen COM war der Standardweg, die Identität eines Objekts zur Laufzeit zu erfahren, „die IID kennen und über QueryInterface fragen“. Für Skriptsprachen gab es einen getrennten Pfad, IDispatch.
In WinRT lässt sich der aus GetRuntimeClassName gewonnene Typname gegen die .winmd-Metadaten des nächsten Abschnitts auflösen. Von dort erhalten Sie die vollständige Definition seiner Methoden, Eigenschaften und Ereignisse. Die Spezifikation selbst sagt, dass ein über Metadaten auflösbarer WinRT-Typname „enables language projection“.12
flowchart TB
accTitle: Von GetRuntimeClassName zur Sprachprojektion
accDescr: Wenn die Aufruferseite GetRuntimeClassName auf einem Objekt aufruft, kommt der vollständig qualifizierte WinRT-Typname zurück; die Auflösung dieses Typnamens gegen Windows Metadata liefert die vollständige Definition des Typs, und das macht die Projektion in jede Sprache möglich
obj["WinRT-Objekt"] --> name["Typname (GetRuntimeClassName)"]
name --> md["Die Typdefinition in .winmd auflösen"]
md --> proj["Sprachprojektion wird möglich"]
Abbildung 3: „Der Typname ist zur Laufzeit verfügbar, und der Typname führt zu den Metadaten“ ist das Herzstück der WinRT-Mechanik.
„Vererbung“ und „Requires“ bei benutzerdefinierten Schnittstellen trennen
Es gibt auch einen Unterschied, den COM-Erfahrene beachten sollten. Das WinRT-Typsystem kennt keine Vererbung zwischen benutzerdefinierten Schnittstellen. Eine Ableitung wie das klassische COM-IFileSystemBindData2 : IFileSystemBindData fehlt bewusst; stattdessen wird sie durch die Deklaration „Schnittstelle A fordert Schnittstelle B (requires)“ ausgedrückt.121
Das ist eine andere Sache als die bisher gesehene ABI-Basiskette IUnknown → IInspectable. Diese Basis bleibt das Fundament jeder WinRT-Schnittstelle.
Benutzerdefinierte Verträge wurden in eine lockerere Form verschoben, die nicht vom vtable-Vererbungslayout abhängt. Gleichzeitig laufen die Aufrufe selbst weiterhin über die vtable. Es ist wichtig, die Schreibweise der Verträge nicht mit dem Mechanismus des Aufrufs zu verwechseln.
4. Was .winmd gelöst hat — die Bindungshölle der Typinformationen
Die Schwierigkeit des klassischen COM lag darin, „wie man Typinformationen verteilt“
In der Praxis des klassischen COM ging mehr Aufwand in die Verteilung der Typinformationen als in die Implementierung der Schnittstellen selbst.
| Verbraucher | Pfad für die Lieferung der Typinformationen |
|---|---|
| C++ | Den Vertrag in IDL schreiben, Header und Proxy/Stub mit MIDL erzeugen |
| VB6, Skripting | Eine Typbibliothek (TLB) verteilen |
| .NET | Eine eigene Interop-Assembly bauen |
Eine TLB hat automatisierungsorientierte Typbeschränkungen: Manche Informationen, die sich in IDL schreiben lassen, passen nicht in eine TLB. Und weil jede Sprache ihren eigenen Pfad hat, entstehen Typabweichungen, sobald einer davon veraltet. Diese Schwierigkeiten haben wir in dem Artikel zu Typbibliotheken und dscom und dem Artikel zur Abwärtskompatibilität von DLL- und COM-Schnittstellen behandelt.
.winmd ist der gemeinsame Vertrag, den jede Sprache liest
WinRTs Antwort ist Windows Metadata (.winmd). Die APIs werden als maschinenlesbare Metadaten beschrieben, und Werkzeuge und Sprachprojektionen lesen sie, um eine Projektion für jede Sprache zu erzeugen.3
Windows liefert die Metadaten jeder systemseitig bereitgestellten WinRT-API mit und stellt außerdem APIs bereit, die Namespaces und Typen zur Laufzeit auflösen. Das Windows SDK enthält eine Kopie für die Kompilierzeit. Auch Dritte können an der Sprachprojektion über denselben Mechanismus wie die System-APIs teilnehmen, indem sie einer eigenen WinRT-Komponente eine .winmd beilegen.3
Was sich hier geändert hat, ist die Form, in der Typinformationen verteilt werden. Anstelle von TLBs, Headern und Interop-Assemblys, die je Sprache verstreut waren, liest nun eine einzige .winmd die Projektion jeder Sprache.
Gleichwohl ist IDL nicht überflüssig geworden. Wenn Sie eine WinRT-Komponente erstellen, beschreiben Sie den Vertrag weiterhin in IDL (MIDL 3.0, für WinRT modernisiert), und der MIDL-Compiler erzeugt die .winmd.14
flowchart TB
accTitle: Die Produktionspipeline einer WinRT-Komponente
accDescr: Der Vertrag einer WinRT-Komponente wird weiterhin in IDL geschrieben, also MIDL 3.0, und der MIDL-Compiler kompiliert ihn in eine .winmd. Verteilt wird diese .winmd, und das Projektionswerkzeug jeder Sprache, etwa cppwinrt.exe oder cswinrt.exe, liest sie, um die Projektion zu erzeugen. Ersetzt wurde nicht IDL, sondern die Form, in der Typinformationen verteilt werden
idl2["Den Vertrag schreiben (IDL, MIDL 3.0)"]
midl2["MIDL-Compiler"]
winmd4[".winmd (verteilte Typinformationen)"]
proj3["Die Projektion jeder Sprache erzeugen"]
idl2 --> midl2
midl2 --> winmd4
winmd4 --> proj3
Abbildung 4: Der Einstieg des Vertrags (IDL) bleibt in Betrieb; der Ausgang, die verteilten Typinformationen, wurde auf .winmd vereinheitlicht.
Dasselbe Dateiformat wie .NET, aber keine verwaltete Laufzeit
Das physische Format einer .winmd nutzt die ECMA-335-Spezifikation, dieselbe wie eine CLR-Assembly. Die Regeln, welche Datenkombinationen gültig sind, unterscheiden sich jedoch von denen für CLR-Assemblys. Das Leihen des Formats und die Notwendigkeit der CLR zur Ausführung sind zwei verschiedene Dinge.3
Hier müssen Sie System-APIs und Drittanbieterkomponenten getrennt lesen.
| Gegenstand | Beziehung zwischen der .winmd und der Implementierung |
|---|---|
| Systemseitig bereitgestellte WinRT-APIs | Die .winmd ist reine Metadaten ohne ausführbaren Code. Die Implementierung liegt in nativen OS-DLLs, und die CLR wird zur Ausführung nicht gebraucht |
| WinRT-Komponenten Dritter | Die .winmd kann auch Implementierungscode enthalten. Für eine verwaltete Komponente (in C# geschrieben), die MSIL enthält, wird die entsprechende .NET-Laufzeit zur Ausführung benötigt |
Weil eine .winmd in einem Werkzeug wie eine .NET-Assembly wirkt, liegt das Missverständnis „WinRT = verwaltet“ nahe. Aber der Inhalt einer systemseitig bereitgestellten .winmd ist ein Vertrag für COM-Schnittstellen.3
flowchart TB
accTitle: Trennung von .winmd und Implementierung
accDescr: Eine .winmd ist Metadaten, die das physische ECMA-335-Format leihen; die systemseitig bereitgestellten sind Verträge ohne ausführbaren Code, und die Implementierung der systemseitig bereitgestellten WinRT-APIs liegt in nativen OS-DLLs. Wegen dieser Trennung wird die CLR zur Ausführung der System-WinRT-APIs nicht gebraucht, obwohl eine .winmd wie eine .NET-Assembly wirkt (die .winmd einer verwalteten Drittanbieterkomponente enthält MSIL und braucht die .NET-Laufzeit)
winmd3[".winmd (Vertrag, ECMA-335-Format)"]
impl["Native OS-DLL (Implementierung)"]
winmd3 -.->|"Systemseitig: kein Code"| note3["System-APIs brauchen keine CLR"]
impl --> note3
winmd3 ---|"Typdefinitionen entsprechen der Implementierung"| impl
Abbildung 5: Bei systemseitig bereitgestellten WinRT-APIs ist die .winmd der Vertrag und die Implementierung eine native OS-DLL. Das Format wirkt wie .NET, die Ausführung ist natives COM.
flowchart TB
accTitle: Typinformationen des klassischen COM gegenüber .winmd
accDescr: Im klassischen COM war der Pfad der Typinformationen je Sprache geteilt, von IDL zu C++-Headern, von Typbibliotheken zu VB6 und Skripting, von Interop-Assemblys zu .NET, was Inkonsistenzen verursachte, während in WinRT eine einzige .winmd gemeinsam von den Projektionen jeder Sprache gelesen wird
subgraph old["Klassisches COM: ein Pfad je Sprache"]
idl["IDL zu C++-Headern"]
tlb["TLB zu VB6 und Skripting"]
ia["Interop-Assembly zu .NET"]
end
winmd[".winmd (einzige Metadaten)"]
winmd --> all["Gemeinsam gelesen von der Projektion jeder Sprache"]
Abbildung 6: .winmd hat die sprachweise Streuung der Typinformationen zu „eine Metadatendatei, die alle lesen“ zusammengefaltet.
Die Einschränkungen sind nicht verschwunden; sie haben sich auf eine Achse der Projizierbarkeit verschoben
Für Kenner des klassischen COM in einem Satz: .winmd ist „die Typbibliothek, neu gemacht“. Denken Sie daran als die Rolle, die eine TLB zu spielen versuchte, von vornherein als einzige gemeinsame Wahrheitsquelle aller Sprachen neu entworfen, auf dem bewährten ECMA-335-Format, und die Einordnung wird klar.
Die Einschränkungen sind jedoch nicht weg. Die automatisierungsorientierten Einschränkungen von TLBs wurden ersetzt durch die Einschränkungen des eigenen Typsystems von WinRT, dessen Achse „sich sicher in jede Sprache projizieren lässt“ ist. Das Fehlen der Vererbung zwischen benutzerdefinierten Schnittstellen aus Abschnitt 3 ist ein Beispiel.12
Folglich lässt sich ein bestehender COM/IDL-Vertrag nicht unbedingt unverändert nach WinRT tragen. Die API muss möglicherweise neu entworfen werden.
flowchart TB
accTitle: Ersetzung der Typbibliothekseinschränkungen durch die des WinRT-Typsystems
accDescr: Die automatisierungsorientierten Ausdruckseinschränkungen der TLB (Typbibliothek) wurden durch .winmd nicht entfernt, sondern durch die Einschränkungen des eigenen Typsystems von WinRT ersetzt, dessen Achse die sichere Projektion in jede Sprache ist. Ein Beispiel ist das Fehlen benutzerdefinierter Schnittstellenvererbung; ein bestehender COM/IDL-Vertrag lässt sich nicht unbedingt unverändert übernehmen, und die API muss möglicherweise neu entworfen werden
tlb["TLB-Einschränkungen (automatisierungsorientiert)"] -->|"Ersetzt durch"| wrt["Einschränkungen des WinRT-Typsystems (Achse Projizierbarkeit)"]
wrt -.-> ex["Beispiel: keine benutzerdefinierte Vererbung"]
wrt -.-> re["Bestehende COM-Verträge können Neuentwurf brauchen"]
Abbildung 7: Die TLB-Einschränkungen sind nicht „verschwunden“; sie wurden durch andere Einschränkungen ersetzt, deren Achse die Projizierbarkeit in jede Sprache ist.
5. C++/WinRT und C#/WinRT sind Projektionen, keine „Wrapper“
Den gemeinsamen Vertrag jeder Sprache in ihrer natürlichen Form zeigen
Sobald es einen gemeinsamen Vertrag in Form von .winmd gibt, lässt sich die Sicht für jede Sprache automatisch durch Werkzeuge erzeugen. Das ist eine Sprachprojektion (language projection). Sie legt WinRT-APIs im Idiom jeder Sprache offen und verbirgt die Details von COM, wodurch ein Programmiererlebnis entsteht, das sich für diese Sprache natürlich anfühlt.411
Die Projektionen, die Microsoft derzeit unterstützt, sind die folgenden zwei.4
| Projektion | Was sie erzeugt | Eigenschaften |
|---|---|---|
| C++/WinRT | cppwinrt.exe erzeugt C++-Projektionsheader aus .winmd |
Eine headerdateibasierte Projektion in Standard-C++17. Keine Spracherweiterungen wie die von C++/CX sind nötig; der Nachfolger von C++/CX und WRL11 |
| C#/WinRT (CsWinRT) | cswinrt.exe erzeugt C#-Code aus .winmd und macht daraus eine Interop-Assembly |
Die Projektion für .NET. Eine von der Laufzeit unabhängige Toolchain1516 |
Die Geschichte auf der C#-Seite ist etwas verwirrend, daher entwirren wir sie. Bis .NET Core 3.x hatte die .NET-Laufzeit eine eingebaute Unterstützung für den Verbrauch von WinRT/winmd. In .NET 5 wurde diese eingebaute Unterstützung entfernt, und die Rolle wanderte zu C#/WinRT.16 WinRT-APIs wurden nicht unbenutzbar; wo die Projektion anfällt, hat sich geändert.
Heute werden, wenn Sie in C# ein TFM wie net8.0-windows10.0.19041.0 angeben, die Projektionsassemblys des Windows SDK automatisch referenziert.10
flowchart TB
accTitle: Erzeugung der Projektionen für jede Sprache aus .winmd
accDescr: Wenn cppwinrt.exe die einzige .winmd liest, erzeugt es C++17-Projektionsheader; wenn cswinrt.exe sie liest, erzeugt es eine C#-Interop-Assembly; und die WinRT-APIs werden in einer Form offengelegt, die dem Idiom jeder Sprache folgt
winmd2[".winmd (der API-Vertrag)"]
winmd2 --> cpp["cppwinrt.exe zu C++17-Headern"]
winmd2 --> cs["cswinrt.exe zu C#-Interop-Assembly"]
cpp --> cppcode["Im C++-Idiom aufrufbar"]
cs --> cscode["Im C#-Idiom aufrufbar"]
Abbildung 8: Eine Projektion ist kein handgeschriebener Wrapper; Werkzeuge erzeugen sie mechanisch aus dem Vertrag (.winmd).
Auch wenn sie erzeugt wird, bleibt der Aufruf selbst COM
Dieser Artikel sagt „Projektion“ statt „Wrapper“, um zu betonen, dass es ein mechanisch aus Metadaten abgeleiteter Mechanismus ist, keine Übersetzungsschicht, die Menschen API für API pflegen. Jede in der .winmd vorhandene API lässt sich von Anfang an in jeder unterstützten Sprache nutzbar machen.
Und aus welcher Sprache Sie auch aufrufen: unter der Projektion geschieht derselbe COM-Aufruf. Wenn Sie etwa in C# await picker.PickSingleFolderAsync() schreiben, brückt die Projektion WinRTs IAsyncOperation in die Welt von .NETs Task. Auf der ABI-Seite werden dennoch vtable-Methodenaufrufe und HRESULT verwendet. Deshalb erscheinen Fehler in Form von COM-Ausnahmen (ein HRESULT wie 0x80070005).
flowchart TB
accTitle: Die Schichten vom C#-Code zur WinRT-API des OS
accDescr: Der C#- oder C++-Code der App wird über die Sprachprojektion in WinRT-ABI-Aufrufe umgewandelt, also vtable-Aufrufe auf IInspectable, und erreicht die vom OS implementierte WinRT-API. Die Projektion verbirgt nur die Details von COM; der Aufruf selbst ist COM
code["App-Code (C#, C++)"]
proj2["Sprachprojektion"]
abi["WinRT-ABI (IInspectable-vtable)"]
os["OS-Implementierung der WinRT-API"]
code --> proj2
proj2 --> abi
abi --> os
Abbildung 9: Was die Projektion verbirgt, sind die „Details“ von COM, nicht COM selbst.
Wer diese Struktur kennt, kann Störungen in zwei Schichten teilen. Eine Versionsabweichung im erzeugten Code oder eine fehlende TFM-Einstellung ist die Projektionsschicht; HRESULTs, Apartments und Referenzzählung sind die ABI-Schicht. In der letzteren hilft COM-Entwicklungserfahrung unmittelbar.
6. Wo Desktop-Apps hängen bleiben — HWND, Identität, Apartments
Zuerst „die API referenzieren können“ von „den Bedingungen, unter denen sie funktioniert“ trennen
Die meisten WinRT-APIs lassen sich aus WPF-, WinForms- und Win32-Desktop-Apps aufrufen.5 Der Einstieg für den Aufruf unterscheidet sich zwischen C# und C++ wie folgt.10
| Umgebung | Erste Einrichtung |
|---|---|
| C#/.NET 6 oder höher | TargetFramework auf ein TFM mit Windows-OS-Version setzen, etwa net8.0-windows10.0.19041.0 |
| C++ | Das NuGet-Paket Microsoft.Windows.CppWinRT hinzufügen und C++/WinRT mit C++17 oder höher nutzen |
Die APIs referenzieren zu können bedeutet jedoch nicht, dass jede API unverändert funktioniert. Prüfen Sie die folgenden drei Punkte. Die Registrierungsbedingungen für Toastbenachrichtigungen sind getrennt in Abschnitt 9 behandelt.
| Was zu prüfen ist | Wesentliche Abhilfe |
|---|---|
| Braucht sie ein Fenster zur Anzeige? | Einen HWND über das zur UI passende COM-Interop übergeben |
| Braucht sie eine Paketidentität? | Identität mit MSIX oder einem Paket mit externem Speicherort verleihen |
| Ist der Thread für WinRT initialisiert? | Im nativen Code mit Angabe von STA/MTA initialisieren. In C# übernimmt das in der Regel die Laufzeit |
Stolperstelle 1: Einen HWND an UI wie Picker übergeben
Einige Picker, Dialoge und die Freigabe-UI erwarten ein UWP-CoreWindow als Anzeigefläche. Eine Desktop-App hat kein CoreWindow, daher muss der HWND des Besitzerfensters vor der Anzeige des Objekts ausdrücklich übergeben werden.6
Der Einstieg, der für Picker und Ähnliches genutzt wird, ist eine COM-Schnittstelle namens IInitializeWithWindow. Sie erbt von IUnknown und stellt WinRT-Objekten, die in Desktop-Apps genutzt werden, ein Besitzerfenster bereit.17
In C# holen Sie zuerst den HWND je nach verwendetem UI-Framework.186
| Besitzerfenster | Wie der HWND geholt wird |
|---|---|
Ein WinUI-Window |
WinRT.Interop.WindowNative.GetWindowHandle |
| Ein WPF-Fenster | WindowInteropHelper |
| Ein WinForms-Formular | Die Handle-Eigenschaft des Formulars |
Als Nächstes übergeben Sie ihn mit WinRT.Interop.InitializeWithWindow.Initialize(picker, hwnd) an den Picker und zeigen ihn erst dann. In C++/WinRT holen Sie das Objekt als as<IInitializeWithWindow>() und rufen dann Initialize(hwnd) auf. Überspringen Sie die Initialisierung, wirft sie oder scheitert still.1819
Ein modernes WinRT-Objekt durch QueryInterface auf eine klassische COM-Schnittstelle initialisieren: Dass diese Brücke die offizielle Praxis ist, ist ein weiterer Ort, an dem WinRT zeigt, dass es COM ist.
Die Freigabe-UI nutzt eine andere Schnittstelle. Für DataTransferManager verwenden Sie nicht IInitializeWithWindow. Sie verwenden das eigene IDataTransferManagerInterop und übergeben den HWND an ShowShareUIForWindow.6
Die neueren Picker des Windows App SDK sind ein weiterer getrennter Pfad. Microsoft.Windows.Storage.Pickers nimmt eine WindowId im Konstruktor entgegen, daher ist das InitializeWithWindow-Muster unnötig. Es sind jedoch keine APIs, die sich mit einer TFM-Einstellung allein nutzen lassen. Zusätzlich zum Hinzufügen des Windows App SDK braucht eine nicht paketierte App die Laufzeit auf den Zielrechnern bereitgestellt und initialisiert.19
sequenceDiagram
accTitle: Schritte, um einen Picker aus einer Desktop-App anzuzeigen
accDescr: Nachdem eine Desktop-App einen Picker erzeugt hat, führt der unveränderte Aufruf von PickSingleFolderAsync zu einer Ausnahme oder einem stillen Fehlschlag, daher muss zuerst der HWND des Besitzerfensters geholt und über Initialize von IInitializeWithWindow übergeben werden, bevor der Picker angezeigt wird
participant A as Desktop-App
participant P as Picker (WinRT)
A->>P: Erzeugen
alt Anzeigen ohne HWND zu übergeben
A->>P: PickSingleFolderAsync
P-->>A: Ausnahme oder stilles Fehlschlagen
else Zuerst den HWND übergeben
A->>P: Den HWND über IInitializeWithWindow setzen
A->>P: PickSingleFolderAsync
P-->>A: Der Picker wird angezeigt
end
Abbildung 10: Die Lücke „es gibt kein CoreWindow auf dem Desktop“ durch ausdrückliche HWND-Übergabe zu füllen, ist die offizielle Praxis.
Stolperstelle 2: Einige APIs verlangen eine Paketidentität
Einige WinRT-APIs, etwa der Verlauf der Toastbenachrichtigungen (ToastNotificationHistory), Sprunglisten und Freigabeziele, funktionieren nur in Apps, die eine Paketidentität haben (paketierte Apps). Der Aufruf aus einer nicht paketierten App, die mit einem herkömmlichen Installer verteilt wird, scheitert.7
Es gibt zwei Abhilfen. Die App mit MSIX paketieren oder ein „Paket mit externem Speicherort“ (ein sogenanntes Sparse Package) nutzen, das eine Identität verleiht und den bestehenden Installer behält.20 Welche APIs eine Identität verlangen, lässt sich in der offiziellen Liste prüfen.7
flowchart TB
accTitle: Zwei Pfade zu APIs, die eine Paketidentität verlangen
accDescr: Der Aufruf einer WinRT-API, die eine Paketidentität verlangt, aus einer nicht paketierten App scheitert, daher geben Sie der App eine Paketidentität entweder durch Paketierung mit MSIX oder mit einem Paket mit externem Speicherort, das nur den Bezeichner verleiht und den bestehenden Installer behält
need["Eine identitätspflichtige API nutzen wollen"]
need --> m1["Mit MSIX paketieren"]
need --> m2["Paket mit externem Speicherort"]
m1 --> id2["Paketidentität erhalten"]
m2 --> id2
id2 -.-> okid["Benachrichtigungsverlauf usw. funktionieren"]
Abbildung 11: Die Abhilfe für identitätspflichtige APIs ist eine Wahl aus zwei: „MSIX“ oder „bestehender Installer + Verleihen eines Bezeichners“.
Stolperstelle 3: Threadinitialisierung und STA/MTA prüfen
Ein Thread, der WinRT-Objekte behandelt, muss zuvor für WinRT initialisiert werden. Im nativen Code nutzen Sie RoInitialize oder winrt::init_apartment und geben das Concurrency-Modell an, STA oder MTA. In C#-WPF/WinForms-Apps übernimmt die Laufzeit die Initialisierung in der Regel.8
RoInitialize ist der Einstieg der WinRT-Generation im selben Rahmen wie COMs CoInitializeEx. Die CoInitialize-Dokumentation selbst verweist darauf, bei Nutzung der Windows Runtime stattdessen RoInitialize oder Windows::Foundation::Initialize aufzurufen.21
Der UI-Thread von WPF/WinForms ist ein STA; UI-Objekte müssen auf dem UI-Thread angefasst werden; blockierende Wartezeiten auf einem STA laden Deadlocks ein. Das Denken aus dem STA/MTA-Artikel überträgt sich unverändert auf WinRT-APIs.
Einige APIs lassen sich selbst mit HWND und Identität nicht nutzen
Die bisherigen Abhilfen betreffen APIs, die einen Einstieg für die Desktop-Nutzung haben. APIs, die von CoreWindow oder ApplicationView selbst abhängen, lassen sich aus Desktop-Apps nicht nutzen. In dem Fall suchen Sie statt zusätzlicher Initialisierung nach einer Ersatz-API.57
flowchart TB
accTitle: Verzweigung der Stolperstellen beim Aufruf von WinRT-APIs vom Desktop
accDescr: Zuerst bestätigen, dass der Thread für WinRT initialisiert ist (im nativen Code STA/MTA ausdrücklich mit RoInitialize oder ähnlich angeben; in C# übernimmt das in der Regel die Laufzeit). Dann, wenn die aufzurufende WinRT-API UI ist, die ein CoreWindow voraussetzt, einen HWND über IInitializeWithWindow übergeben oder die neuen Picker nutzen; wenn sie eine Paketidentität verlangt, einen Bezeichner mit MSIX oder einem Paket mit externem Speicherort verleihen; APIs, die von CoreWindow oder ApplicationView selbst abhängen, lassen sich auf dem Desktop nicht nutzen, daher nach einer Ersatz-API suchen; und die große restliche Menge der APIs lässt sich unverändert nur mit der TFM- oder C++/WinRT-Einrichtung aufrufen
pre["Threadinitialisierung"] --> q{"Was für eine API ist es?"}
pre -.-> auto["Nativ: ausdrücklich; C#: meist automatisch"]
q -->|"UI"| h["HWND oder die neuen Picker"]
q -->|"Identität erforderlich"| p2["MSIX oder Bezeichner verleihen"]
q -->|"Hängt von CoreWindow selbst ab"| x["Nach einer Ersatz-API suchen"]
q -->|"Alles andere"| ok3["Unverändert aufrufbar"]
Abbildung 12: Mit der Threadinitialisierung als Voraussetzung (ausdrücklich im nativen Code, in C# in der Regel der Laufzeit überlassen) fallen die Stolperstellen in drei Familien, jede mit einer Standardabhilfe.
flowchart TB
accTitle: Entsprechung der Threadinitialisierung zwischen COM und WinRT
accDescr: Im klassischen COM wird ein Thread mit CoInitializeEx unter Angabe von STA oder MTA initialisiert, während in WinRT mit RoInitialize unter Angabe desselben Concurrency-Modells STA oder MTA initialisiert wird. Die CoInitialize-Dokumentation verweist auch darauf, bei Nutzung von WinRT RoInitialize aufzurufen, und das Apartmentkonzept ist gemeinsam
com3["Klassisches COM: CoInitializeEx"] --> apt["Apartment (STA / MTA)"]
wrt["WinRT: RoInitialize"] --> apt
apt -.-> rule["UI-Thread ist STA; Wartezeiten beachten"]
Abbildung 13: Der Name der Initialisierungs-API hat sich geändert, aber dasselbe Apartmentkonzept wird weiterverwendet.
7. Worauf WinUI sitzt — Entwicklung in der Öffentlichkeit ändert den Vertrag nicht
Der Wechsel zur Entwicklung in der Öffentlichkeit ist keine Änderung des Binärvertrags
Im Sommer 2025 kündigte Microsoft offiziell als stufenweises Vorgehen die Politik an, die WinUI-Hauptentwicklung öffentlich auf GitHub zu führen. Es gibt vier Stufen: die Aktualisierungsfrequenz des Spiegels erhöhen, lokale Builds ermöglichen, Communitybeiträge annehmen, sobald Tests stehen, und schließlich GitHub zum hauptsächlichen Entwicklungsstandort machen.22
Zum Veröffentlichungszeitpunkt dieses Artikels (Ende August 2026) hält auch die offizielle Dokumentation fest, dass WinUI „built in the open“ ist. Der alltägliche Fortschritt der Technik lässt sich nun im öffentlichen Repository verfolgen.9
Entwicklerinnen und Entwickler, die die Generationswechsel von WinForms zu WPF zu UWP zu WinUI verfolgt haben, empfinden natürlich „das Framework ändert sich schon wieder?“. Aber die UI-Frameworks, die sich geändert haben, und das Fundament darunter müssen getrennt betrachtet werden. Win32 und COM und seit 2012 das WinRT-ABI sind am selben Ort geblieben.
Auch WinUI-Fenster werden von einem HWND getragen
WinUI ist ein Satz WinRT-APIs, bereitgestellt als Teil des Windows App SDK.923 Sein Microsoft.UI.Xaml.Window ist ein von einem HWND getragenes Fenster, das das CoreWindow-basierte Fenstermodell der UWP-Generation ersetzt. Auch die offizielle Interop-Anleitung beginnt damit, den Fensterhandle zu holen.24
Mit anderen Worten: Eine WinUI-App ist eine Win32-App, in der auf einem HWND-Fenster ein Objektbaum läuft, der dem IInspectable-Vertrag folgt. Das über COM erworbene Wissen zu QueryInterface, Referenzzählung und Apartments und das über Win32 erworbene Wissen zu HWNDs und Nachrichtenschleifen greifen beide unmittelbar bei der Fehlersuche in WinUI.
flowchart TB
accTitle: Generationswechsel der UI-Frameworks und das unveränderte Fundament
accDescr: Die UI-Frameworks WinForms, WPF, UWP-XAML und WinUI haben Generation um Generation durchlaufen, aber WinForms und WPF sitzen direkt auf dem Fundament von Win32 und COM, während UWP-XAML und WinUI über das WinRT-ABI auf demselben Fundament von Win32 und COM sitzen. Was die Generationen gewechselt hat, ist die obere Schicht; der Vertrag darunter hat sich nicht geändert
gen["Generationswechsel der UI-Frameworks"]
gen --> f1["WinForms, WPF"]
gen --> f2["UWP-XAML"]
gen --> f3["WinUI (aktuell)"]
f2 --> abi3["WinRT-ABI (seit 2012)"]
f3 --> abi3
f1 --> stable["Unverändertes Fundament (Win32 + COM)"]
abi3 --> stable
Abbildung 14: Was auf- und abgestiegen ist, war die Framework-Schicht. WinForms und WPF sitzen direkt auf Win32 + COM; UWP und WinUI sitzen über das WinRT-ABI auf demselben Fundament.
flowchart TB
accTitle: Die Schichten, die eine WinUI-App tragen
accDescr: XAML und Steuerelemente von WinUI werden als Teil des Windows App SDK bereitgestellt, laufen auf dem WinRT-ABI, also dem IInspectable-Vertrag, und darunter liegt das Fundament von COM und dem HWND von Win32. Unter den Generationswechseln der UI-Frameworks hat sich dieser darunterliegende Vertrag nicht geändert
ui["WinUI (XAML, Steuerelemente)"]
sdk["Windows App SDK"]
abi2["WinRT-ABI (IInspectable)"]
base2["COM + Win32 (HWND)"]
ui --> sdk
sdk --> abi2
abi2 --> base2
Abbildung 15: Unter WinUI liegt das WinRT-ABI, und darunter liegen klassisches COM und Win32. Nur die Stapelung hat sich geändert; das Fundament ist dasselbe.
Mischen mit XAML Islands: die Einschränkungen jeder Generation prüfen
Die Strategie, „nur WinUI-Steuerelemente in bestehende WPF/WinForms-Bildschirme zu mischen“, muss für jede Generation von XAML Islands getrennt bewertet werden.
| Generation | Lage bei Nutzung aus WPF/WinForms |
|---|---|
| XAML Islands der UWP-Generation | Wrapper-Steuerelemente aus dem Windows Community Toolkit gibt es. Aber die WPF/WinForms-Versionen endeten bei der Generation .NET Core 3.x und werden auf aktuellem .NET nicht unterstützt25 |
| WinUI-3-Generation | Lässt sich aus WPF, WinForms und Win32 mit DesktopWindowXamlSource des Windows App SDK hosten. Aber es gibt keine bequemen Wrapper-Steuerelemente wie die der UWP-Generation, und der Aufwand für Implementierung und Prüfung, die Hosting-API direkt zu behandeln, fällt bei Ihnen an26 |
Wenn Sie schrittweises Mischen planen, ist es sicherer, nicht allein von steuerelementweisem Mischen auszugehen. Den Plan um funktionsweise Nutzung von WinRT-APIs (Abschnitt 6) oder Trennung auf Bildschirm- oder Prozessebene zu ordnen, ist zum Stand 2026 der solidere Ansatz.
8. Folgerungen für Geschäftsanwendungen — vollständige Migration und gezielte Nutzung sind getrennte Probleme
„WinRT ist eine neue, getrennte Welt, also bedeutet die Nutzung, bestehende Assets wegzuwerfen und neu zu bauen.“ Dieses Missverständnis, das in der Auftragsentwicklung auftritt, löst sich, sobald Sie es in zwei teilen.
Bestehende COM-Assets und WinRT können koexistieren
Einer WPF-App, die Excel-COM-Automatisierung nutzt, ActiveX-Steuerelemente hostet und interne COM-Komponenten aufruft, können WinRT-APIs hinzugefügt werden. Das ist keine besondere Akrobatik, weil Sie Funktionen auf derselben COM-Grundlage kombinieren.
Für Toastbenachrichtigungen etwa setzen Sie das TFM, um die API zu referenzieren, und erfüllen die Registrierungsbedingungen für die Anzeige. Damit Letzteres nicht vergessen wird, legt Abschnitt 9 es pfadweise dar. In C++/WinRT lassen sich WinRT- und klassische COM-Schnittstellen mit denselben Mechanismen behandeln, winrt::com_ptr und winrt::implements.21
UI-Erneuerung und Funktionsergänzung getrennt schätzen
„Die UI vollständig nach WinUI migrieren?“ und „WinRT-APIs nur dort nutzen, wo sie gebraucht werden?“ sind Entscheidungen, die sich in Umfang, Dauer und Risiko unterscheiden.
Eine vollständige UI-Migration ist ein Problem der Frameworkwahl, das von Bildschirmassets, Drittanbietersteuerelementen und der Entwicklungsorganisation abhängt. Diese Entscheidung haben wir in Wie Sie zwischen WinForms, WPF und WinUI wählen behandelt. Die gezielte Nutzung von WinRT-APIs dagegen ist eine kleine Verbesserung, die Sie heute in einer bestehenden App beginnen können.
Für ein Projekt, das nur Toastbenachrichtigungen will, braucht es keine Schätzung einer vollständigen UI-Migration. Umgekehrt braucht es keinen Aufschub der Nutzung von WinRT-APIs „weil wir nicht nach WinUI migrieren“.
flowchart TB
accTitle: Vollständige Migration und gezielte Nutzung sind getrennte Entscheidungen
accDescr: Eine vollständige UI-Migration nach WinUI ist eine große Entscheidung der Frameworkwahl, die von Bildschirmassets und Organisation abhängt, während die gezielte Nutzung von WinRT-APIs eine kleine Entscheidung ist, die sich einer bestehenden WPF- oder WinForms-App heute mit einer TFM-Einstellung oder ähnlich hinzufügen lässt; betrachten Sie die beiden getrennt, ohne sie zu verwechseln
goal["Neue Windows-Funktionen nutzen wollen"]
goal --> big["Vollständige UI-Migration (große Entscheidung)"]
goal --> small["Gezielte WinRT-API-Nutzung (kleine Entscheidung)"]
big -.-> dep["Hängt von Bildschirmassets und Organisation ab"]
small -.-> today["Kann der bestehenden App heute hinzugefügt werden"]
Abbildung 16: Es gibt zwei Wege zu „neuen Funktionen“, und sie zu verwechseln wirft Schätzung und Entscheidung aus der Bahn.
9. Entscheidungstabelle — die WinRT-Fassung von Behalten, Kapseln, Ersetzen
Nur die Änderungen wählen, die jede Lage braucht
Als Erweiterung der ActiveX-Entscheidungstabelle folgt hier ein lageweiser Entscheidungsleitfaden auf der WinRT-Seite.
| Lage | Empfehlung | Grund |
|---|---|---|
| WinRT-APIs wie Toast, Freigabe oder Bluetooth aus WPF/WinForms nutzen wollen | Gezielte Nutzung über eine TFM-Einstellung (oder das Hinzufügen von C++/WinRT) | Heute ohne UI-Migration aufrufbar. Aber die Freigabe-UI geht über IDataTransferManagerInterop (Abschnitt 6), und für Toast siehe die Ergänzung unter der Tabelle106 |
| Ausnahme oder stilles Fehlschlagen in einem Picker oder Dialog | Einen HWND über IInitializeWithWindow übergeben. Für neuen Code die neuen WindowId-basierten Picker (erfordert das Hinzufügen des Windows App SDK) |
Die offizielle Praxis, den CoreWindow-basierten Entwurf mit einem HWND zu füllen619 |
| Benachrichtigungsverlauf, Sprunglisten und Ähnliches funktionieren nicht | Paketidentität mit MSIX oder einem Paket mit externem Speicherort verleihen | Identitätspflichtige APIs setzen Paketierung voraus720 |
| Bestehende COM/ActiveX/OLE-Assets | Nicht verwerfen. Behalten, kapseln oder ersetzen je Asset entscheiden | Nicht ausschließend zu WinRT; sie koexistieren auf derselben Grundlage (Abschnitt 8) |
| UI für eine neue Desktop-App | WinUI als ersten Kandidaten bewerten (WPF ist weiterhin aktuell) | Die Entwicklung in der Öffentlichkeit hat die Investitionsrichtung geklärt. Darunter liegt das WinRT-ABI229 |
| WinUI-Steuerelemente in bestehende WPF/WinForms-Bildschirme mischen | Vorsichtig bewerten und den Implementierungsaufwand fehlender Wrapper einplanen | Islands der UWP-Generation endeten bei .NET Core 3.x; die WinUI-3-Generation bietet nur die Hosting-API2526 |
| Ein Plan, der „WinRT endete zusammen mit UWP“ voraussetzt | Die Voraussetzung korrigieren | WinRT ist die aktuelle API-Grundlage, aufrufbar vom Desktop5 |
Toastbenachrichtigungen erscheinen nicht mit einer TFM-Einstellung allein
Die Einstellung, die die API aufrufbar macht, und die Registrierung, die eine Benachrichtigung erscheinen lässt, sind zwei verschiedene Dinge. Wenn „der Build gelingt, aber keine Benachrichtigung erscheint“, prüfen Sie nicht nur den Aufrufcode, sondern den verwendeten Pfad, die Paketierungsform und ob der Prozess erhöht ist.
Bei Nutzung des klassischen ToastNotificationManager
Für eine nicht paketierte App ohne Paketidentität ist die Voraussetzung, eine Startmenü-Verknüpfung mit zugewiesener AppUserModelID (AUMID) zu registrieren. Ohne sie lassen sich Toasts nicht anzeigen.27
Eine mit MSIX oder ähnlich paketierte App braucht diese manuelle Registrierung nicht, weil die Paketidentität die AUMID liefert.
Bei Nutzung von AppNotificationManager des Windows App SDK
Auf diesem derzeit empfohlenen Pfad sind das Hinzufügen des Windows App SDK und der Aufruf von Register() beim Start erforderlich. Darüber hinaus verzweigen sich die Bedingungen nach Paketierungsform.28
| Paketierungsform | Was zusätzlich zu prüfen ist |
|---|---|
| Nicht paketiert | Die Windows-App-SDK-Laufzeit muss auf jedem Ziel-PC bereitgestellt sein. Register() führt die COM-Server-Registrierung aus |
| Mit MSIX paketiert | Die automatische Registrierung durch Register() greift nicht. Deklarieren Sie einen COM-Aktivator in Package.appxmanifest |
Ferner sind auf dem Windows-App-SDK-Pfad Benachrichtigungen aus einem zum Administrator erhöhten Prozess nicht unterstützt. Show scheitert still ohne Ausnahme. In einer App, die Erhöhung braucht, erwägen Sie, Benachrichtigungen in einen nicht erhöhten Prozess auszulagern.28
Die Implementierungsdetails rund um die Registrierung behandelt der Leitfaden zur Implementierung von Infobereich und Benachrichtigungen.
flowchart TB
accTitle: Die zwei Pfade für Toastbenachrichtigungen und die Registrierung, die jeder braucht
accDescr: Um eine Toastbenachrichtigung aus einer Desktop-App anzuzeigen, verzweigt der klassische ToastNotificationManager-Pfad danach, ob die App paketiert ist: eine nicht paketierte App muss über die Registrierung einer Startmenü-Verknüpfung mit zugewiesener AppUserModelID gehen, während für eine paketierte App die Paketidentität die AppUserModelID liefert. Auf dem AppNotificationManager-Pfad des Windows App SDK muss zusätzlich zum Hinzufügen des SDK und zum Aufruf von Register beim Start eine nicht paketierte App die Laufzeit auf jedem Ziel-PC bereitstellen und eine mit MSIX paketierte App einen COM-Aktivator im Manifest deklarieren, bevor es weitergeht. Der Windows-App-SDK-Pfad verzweigt ferner danach, ob der Prozess erhöht ist: Benachrichtigungen aus einem zum Administrator erhöhten Prozess sind nicht unterstützt und Show scheitert still ohne Ausnahme, daher wird auf diesem Pfad eine Benachrichtigung nur für einen nicht erhöhten Prozess angezeigt, und eine App, die Erhöhung braucht, lagert Benachrichtigungen in einen nicht erhöhten Prozess aus
want["Einen Toast anzeigen wollen"]
want --> c1["Klassisch: ToastNotificationManager"]
want --> c2["WASDK: AppNotificationManager"]
c1 --> q1{"Paketiert?"}
q1 -->|"Nein"| s1["Eine AUMID-Verknüpfung registrieren"]
q1 -->|"Ja"| s2["Identität liefert die AUMID"]
c2 --> r2["SDK hinzufügen + Register()"]
r2 --> q2{"Paketiert?"}
q2 -->|"Nein"| s3["Die Laufzeit bereitstellen"]
q2 -->|"Ja"| s4["COM im Manifest deklarieren"]
s1 --> shown["Benachrichtigung wird angezeigt"]
s2 --> shown
s3 --> elev{"Erhöhter Prozess?"}
s4 --> elev
elev -->|"Nein"| shown
elev -->|"Ja"| fail["Nicht unterstützt: Show scheitert still"]
fail -.-> comp["Benachrichtigungen in einen nicht erhöhten Prozess auslagern"]
Abbildung 17: Auf beiden Pfaden erscheint die Benachrichtigung erst, nachdem die Voraussetzungen der Paketierungsform erfüllt sind. Auf dem Windows-App-SDK-Pfad wird selbst mit allen Voraussetzungen von einem erhöhten Prozess nichts angezeigt.
Schließlich zurück zu Behalten, Kapseln, Ersetzen
Brauchen Sie eine neue Funktion, oder wollen Sie die UI selbst erneuern? Die Rückkehr zu dieser Frage lässt Sie über die Nutzung von WinRT und über das Ersetzen bestehender Assets getrennt entscheiden.
flowchart TB
accTitle: Entscheidungsfluss, wie bestehende Assets und WinRT zusammenpassen
accDescr: Ausgehend von einer bestehenden Desktop-App ein schrittweiser Entscheidungsfluss: wenn keine neue Windows-Funktion nötig ist, behalten; wenn eine Funktion nötig ist, mit gezielter Nutzung von WinRT-APIs kapseln (die Stolperstellen aus Abschnitt 6 zu HWND, Paketidentität und Threadinitialisierung beachten); und nur wenn die UI selbst erneuert werden muss, das Ersetzen durch WinUI erwägen
start["Bestehende Desktop-App"] --> q2{"Was wird gebraucht?"}
q2 -->|"Der aktuelle Stand reicht"| keep2["Behalten (unverändert warten)"]
q2 -->|"Eine neue Funktion"| wrap2["Kapseln (gezielte WinRT-API-Nutzung)"]
q2 -->|"UI-Erneuerung"| rep["Ersetzen (WinUI bewerten)"]
wrap2 -.-> note2["HWND, Identität, Initialisierung beachten (Abschnitt 6)"]
Abbildung 18: Dieselbe Struktur „behalten, kapseln, ersetzen“ wie die ActiveX-Entscheidungstabelle greift unmittelbar auf der WinRT-Seite.
10. Zusammenfassung
WinRT ist keine neue, von COM abgeschnittene Ausführungsumgebung. Es ist eine API-Grundlage, die den COM-Binärvertrag mit Metadaten und Projektionen in jede Sprache verbindet.
| Element | Seine Rolle, wie in diesem Artikel behandelt |
|---|---|
IUnknown und IInspectable |
Auf QueryInterface und Referenzzählung aufgebaut, mit drei Methoden, die den Typnamen und mehr zurückgeben |
.winmd |
Der von jeder Sprache geteilte Vertrag, von dem ein Typname zu einer Definition führt. Leiht das ECMA-335-Format, aber die systemseitig bereitgestellten enthalten keinen ausführbaren Code |
| C++/WinRT und C#/WinRT | Erzeugen eine API für jede Sprache aus dem Vertrag. Seit .NET 5 ist die C#-Projektion eine von der Laufzeit unabhängige Toolchain |
Auch wenn die Oberfläche eine natürliche C#- oder C++-API ist, liegen darunter COM-Aufrufe über vtables und HRESULTs. Deshalb macht das Verstehen der HWND-Übergabe auf dem Desktop, der Paketidentität und von STA/MTA mit Threadinitialisierung WinRT-Störungen leichter eingrenzbar.
Die Bemühung, die WinUI-Hauptentwicklung in die Öffentlichkeit zu verlegen, wurde im Sommer 2025 als stufenweises Vorgehen angekündigt. Zum Veröffentlichungszeitpunkt dieses Artikels sagt auch die offizielle Dokumentation „built in the open“, aber der Vertrag darunter, IUnknown → IInspectable, hat sich nicht geändert.229
Die Schlussfolgerung für Geschäftsanwendungen ist dieselbe. Bestehende COM/ActiveX-Assets und WinRT können koexistieren. Eine vollständige UI-Migration nicht mit der gezielten Nutzung von WinRT-APIs zu verwechseln schützt die Genauigkeit von Schätzungen und Entscheidungen.
Die Verbunddokumente der 1990er-Jahre aus dem OLE-Artikel und das heutige WinUI stehen auf demselben IUnknown. COM zu kennen heißt nicht bloß „sich in Legacy auszukennen“. Es heißt, das Fundament des heutigen Windows lesen zu können.
Verwandte Artikel
- Was ist COM? – Warum das Design von Windows COM auch heute noch schön ist
- Was sind COM / ActiveX / OCX? – Unterschiede und Zusammenhänge im Überblick
- Grundlagenwissen zu COM STA/MTA – Threadmodelle und wie man Hänger vermeidet
- ActiveX / OCX heute behandeln - Entscheidungstabelle: Behalten, Kapseln, Ersetzen
- Wie Sie zwischen WinForms, WPF und WinUI wählen - Entscheidungstabelle für die Praxis
- What Is an OLE Object? — How Embedding and Linking Work, and the Pitfalls in Business Documents
- .NET 8-DLL typisiert aus VBA verwenden - COM-Freigabe und dscom-TLB
Verwandte Beratungsbereiche
KomuraSoft LLC übernimmt die Entwicklung von COM-Komponenten sowie Wartung, Änderung und Ersatz von Windows-Geschäftsanwendungen, die COM-Assets enthalten. Sie können uns ab dem Stadium beraten, in dem der Inhalt dieses Artikels genau das vorliegende Thema ist: „wir wollen Toastbenachrichtigungen und Picker, während wir bei WPF bleiben“, „der Aufruf einer WinRT-API ist mit einer Ausnahme stehen geblieben“, „wir wollen entscheiden, ob wir nach WinUI migrieren oder bestehende Assets nutzen“.
- Windows-App-Entwicklung
- Entwicklung von COM-Komponenten
- Technische Beratung und Design-Review
- Kontakt
Referenzen
-
Microsoft Learn, Consume COM components with C++/WinRT. Dazu, in COM über Schnittstellen statt über Objekte zu programmieren; dass dies auch hinter den Kulissen der WinRT-APIs gilt, die „an evolution of COM“ sind; und dass sich WinRT und klassisches COM im selben Stil mit dem COM-Smart-Pointer winrt::com_ptr behandeln lassen. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Windows Metadata (WinMD) files. Dazu, dass WinRT-APIs in maschinenlesbaren Metadaten namens .winmd beschrieben werden, genutzt von Werkzeugen und Sprachprojektionen; dass Windows die Metadaten jeder systemseitig bereitgestellten WinRT-API mitliefert und Auflösungs-APIs bereitstellt; dass Dritte mit demselben Format an der Sprachprojektion teilnehmen können; und dass das physische Format die ECMA-335-Spezifikation ist (dieselbe wie CLR-Assemblys), wobei die systemseitig bereitgestellten WinMD-Dateien reine Metadaten sind. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Windows Runtime (WinRT) language projections. Dazu, dass Sprachprojektionen WinRT-APIs im Idiom jeder Sprache offenlegen; dass .winmd die WinRT-APIs definiert und Projektionen sie lesen; und dass die zwei von Microsoft unterstützten Projektionen C++/WinRT (C++17 oder höher) und C#/WinRT (.NET) sind. ↩ ↩2 ↩3
-
Microsoft Learn, WinRT APIs callable from a desktop app. Dazu, dass die meisten WinRT-APIs aus .NET- und nativen C++-Desktop-Apps nutzbar sind, mit Klassen, die eigens für UWP entworfen sind, etwa CoreDispatcher, CoreWindow und ApplicationView, als Ausnahmen. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Display WinRT UI objects that depend on CoreWindow. Dazu, dass einige Picker, Popups und Dialoge von CoreWindow abhängen; CoreWindow in Desktop-Apps nicht unterstützt wird; Klassen, die IInitializeWithWindow (oder das entsprechende IDataTransferManagerInterop) implementieren, den HWND des Besitzerfensters vor der Anzeige setzen lassen; und die Schritte für WinUI 3, WPF und WinForms jeweils. ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Microsoft Learn, WinRT APIs not supported in desktop apps. Zu den zwei Familien von WinRT-APIs, die in Desktop-Apps unbenutzbar sind, jenen, die von UWP-only-UI-Funktionen abhängen, und jenen, die eine Paketidentität verlangen (etwa ToastNotificationHistory und JumpList), und dazu, dass Letztere nur in mit MSIX paketierten Apps unterstützt werden. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, RoInitialize function (roapi.h). Dazu, dass RoInitialize den aktuellen Thread für die Windows Runtime mit dem angegebenen Concurrency-Modell (RO_INIT_SINGLETHREADED/RO_INIT_MULTITHREADED) initialisiert; jeder Thread, der WinRT-Objekte aktiviert und bedient, eine vorherige Initialisierung braucht; und eine widersprüchliche Angabe auf einem bereits als MTA initialisierten Thread RPC_E_CHANGED_MODE ergibt. ↩ ↩2
-
Microsoft Learn, WinUI 3. Dazu, dass WinUI das empfohlene native UI-Framework für neue Windows-Desktop-Apps ist, als Teil des Windows App SDK bereitgestellt wird, auf Windows 10 Version 1809 und später läuft und in der Öffentlichkeit entwickelt wird. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Call Windows Runtime APIs in desktop apps. Dazu, dass die Angabe eines TFM mit Windows-OS-Version (etwa net10.0-windows10.0.22621.0) ab .NET 6 das Windows-SDK-Targeting-Paket referenziert, sodass WinRT-APIs aufrufbar sind, und dass C++ C++/WinRT mit dem NuGet-Paket Microsoft.Windows.CppWinRT und C++17 oder höher nutzt. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Introduction to C++/WinRT. Dazu, dass C++/WinRT eine Sprachprojektion in vollständig standardmäßigem, modernem C++17 ist, implementiert als headerdateibasierte Bibliothek; der empfohlene Nachfolger von C++/CX und WRL; dass WinRT auf COM-APIs beruht und für den Zugriff über Sprachprojektionen entworfen ist; dass Projektionen die Details von COM verbergen; und dass cppwinrt.exe Projektionsheader aus .winmd erzeugt. ↩ ↩2 ↩3
-
Microsoft Learn, The Windows Runtime (WinRT) type system. Dazu, dass jede WinRT-Schnittstelle implizit IInspectable fordert und IInspectable IUnknown fordert; dass IUnknown QueryInterface, AddRef und Release definiert; die drei Methoden, die IInspectable hinzufügt, GetIids, GetRuntimeClassName und GetTrustLevel; dass GetRuntimeClassName einen über Metadaten auflösbaren Typnamen zurückgibt, was Sprachprojektion ermöglicht; und dass Vererbung zwischen benutzerdefinierten Schnittstellen im WinRT-Typsystem fehlt und stattdessen mit requires ausgedrückt wird. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, IInspectable interface (inspectable.h). Dazu, dass IInspectable Funktionalität bereitstellt, die jede WinRT-Klasse braucht, von IUnknown erbt und die drei Methoden GetIids, GetRuntimeClassName und GetTrustLevel hat. ↩
-
Microsoft Learn, Introduction to Microsoft Interface Definition Language 3.0. Dazu, dass MIDL 3.0 eine knappe, moderne Syntax zur Deklaration von WinRT-Typen ist und WinRT-Verträge weiterhin in IDL geschrieben werden, wobei der MIDL-Compiler Windows Metadata (.winmd) erzeugt. ↩
-
Microsoft Learn, C#/WinRT. Dazu, dass cswinrt.exe, enthalten im C#/WinRT-NuGet-Paket, .winmd verarbeitet, um C#-Code zu erzeugen und ihn zu einer Interop-Assembly zu kompilieren, und dass dies analog dazu eingeordnet ist, wie C++/WinRT Header für C++ erzeugt. ↩
-
Microsoft Learn, Built-in support for WinRT is removed from .NET. Dazu, dass die eingebaute Unterstützung für die Windows Runtime in .NET 5 aus .NET entfernt und zur CsWinRT-Toolchain verschoben wurde. ↩ ↩2
-
Microsoft Learn, IInitializeWithWindow interface (shobjidl_core.h). Dazu, dass dies die Schnittstelle ist, um WinRT-Objekten, die in Desktop-Apps genutzt werden, ein Besitzerfenster bereitzustellen, von IUnknown erbt und eine Methode Initialize(HWND) hat. ↩
-
Microsoft Learn, Use WinRT COM interop classes in .NET. Dazu, dass einige WinRT-Objekte, etwa Dateipicker und Dialoge, einen HWND brauchen, bevor sie in einer Desktop-App funktionieren, und dass die typsicheren C#-Klassen WinRT.Interop.WindowNative und WinRT.Interop.InitializeWithWindow die Initialisierung ohne handgeschriebene QueryInterface-Aufrufe erlauben. ↩ ↩2
-
Microsoft Learn, Tutorial: Open files and folders with pickers in WinUI. Dazu, dass die klassischen Windows.Storage.Pickers vor der Anzeige mit einem HWND initialisiert werden müssen, wenn sie in einer Desktop-(WinUI-3-)App genutzt werden, sonst werfen oder still scheitern; WinUI-3-Desktop-Apps kein CoreWindow haben; und die neuen Picker des Windows App SDK (Microsoft.Windows.Storage.Pickers) eine WindowId im Konstruktor entgegennehmen, sodass das InitializeWithWindow-Muster unnötig ist. ↩ ↩2 ↩3
-
Microsoft Learn, Features that require package identity. Dazu, dass einige Windows-Funktionen und WinRT-APIs zur Laufzeit eine Paketidentität verlangen, und dass eine Identität nicht nur durch Verteilung als MSIX-Paket, sondern auch mit einem Paket mit externem Speicherort erhältlich ist. ↩ ↩2
-
Microsoft Learn, CoInitialize function (objbase.h). Dazu, dass CoInitialize die COM-Bibliothek als STA initialisiert; neue Apps CoInitializeEx aufrufen sollen; und bei Nutzung der Windows Runtime stattdessen RoInitialize oder Windows::Foundation::Initialize aufgerufen werden muss. ↩
-
GitHub, WinUI: Now Developing in the Open (microsoft/microsoft-ui-xaml Discussion #10700). Die offizielle Ankündigung Ende Juli 2025. Zum stufenweisen Vorgehen für die Öffnung des WinUI-Repositorys (Erhöhung der Spiegel-Aktualisierungsfrequenz, Ermöglichen lokaler Builds, Annahme von Communitybeiträgen, sobald Tests stehen, und schließlich GitHub zum hauptsächlichen Entwicklungsstandort machen). ↩ ↩2 ↩3
-
Microsoft Learn, Windows App SDK. Dazu, dass das Windows App SDK der aktuelle Satz von Bibliotheken zur Windows-App-Entwicklung ist, der WinUI enthält. ↩
-
Microsoft Learn, Walkthrough: WinUI 3 app with Win32 interop. Dazu, dass die WinUI-Window-Klasse zur Unterstützung von Desktop-Fenstern erweitert wurde, und dass Window in einer WinUI-3-Desktop-App von einem Win32-Fensterhandle (HWND) getragen wird, sodass der Handle geholt und mit Win32-APIs bedient werden kann. ↩
-
Microsoft Learn, Host UWP XAML controls in desktop apps (UWP XAML Islands). Dazu, dass XAML Islands der UWP-Generation der Mechanismus sind, UWP-XAML-Steuerelemente in WPF-, WinForms- und C++-Desktop-Apps zu hosten, und dass die Nutzung aus WPF/WinForms auf Apps beschränkt ist, die .NET Core 3.x als Ziel haben, ununterstützt auf aktuellem .NET und .NET Framework. ↩ ↩2
-
Microsoft Learn, DesktopWindowXamlSource Class (Microsoft.UI.Xaml.Hosting). Dazu, dass dies die Kernklasse der XAML-Hosting-API des Windows App SDK ist, WinUI-Steuerelemente in jedem mit einem HWND verbundenen UI-Element hosten kann und aus Desktop-Apps nutzbar ist, die mit WPF, Windows Forms und Win32 (Windows API) gebaut sind. ↩ ↩2
-
Microsoft Learn, Quickstart: Sending a toast notification from the desktop. Dazu, dass das Senden eines Toasts aus einer Desktop-App eine Startmenü-Verknüpfung mit gesetztem System.AppUserModel.ID voraussetzt, und dass diese AppUserModelID an den CreateToastNotifier-Aufruf übergeben werden muss, ohne die der Toast nicht angezeigt wird. ↩
-
Microsoft Learn, Use app notifications with a .NET app. Dazu, dass die Nutzung von AppNotificationManager des Windows App SDK in einer WPF/WinForms-App nach der Registrierung des NotificationInvoked-Handlers einen Aufruf von Register() erfordert; Register() für nicht paketierte Apps automatisch die COM-Server-Registrierung ausführt, die die App beim Klick auf eine Benachrichtigung startet; und die Voraussetzungen das Hinzufügen des Windows App SDK und das Einrichten von WinRT-API-Aufrufen sind. ↩ ↩2
Verwandte Artikel
Aktuelle Artikel mit denselben Schlagwörtern führen zu verwandten Themen weiter.
Windows-App-Outsourcing und Auftragsentwicklung: Was Sie vor der Beauftragung klären sollten
Bevor Sie die Entwicklung einer Windows-App outsourcen oder in Auftrag geben, sollten Sie folgende Punkte klären: Überarbeitung bestehend...
Was ist ein OLE-Objekt? — Einbetten, Verknüpfen und die Fallstricke in Geschäftsdokumenten
Die Funktion, mit der sich eine Excel-Tabelle in Word einbetten lässt, ist in Wirklichkeit ein OLE-Objekt. Der Artikel erklärt praxisnah ...
Wie Zwischenablage und Drag-and-Drop funktionieren — OLE-Datenübertragung in Geschäftsanwendungen richtig behandeln
Eine Excel-Tabelle fällt beim Einfügen auseinander, und nach dem Schließen der Quelle lässt sich nichts mehr einfügen: Ursache ist die Zw...
Windows-Shell-Integration heute ── Kontextmenüs, Dateizuordnungen und was sich unter Windows 11 geändert hat
Warum das Windows-11-Kontextmenü Einträge hinter „Weitere Optionen anzeigen“ verbirgt, erklärt von der Zuordnungsgrundlage Erweiterung → ...
Die seltsame Liebe eines Entwicklers, oder: Wie ich lernte, mir keine Sorgen mehr zu machen, und Windows lieben lernte
Windows ist umständlich. Aber diese Umständlichkeit ist auch die Umständlichkeit eines Betriebssystems, das jahrzehntelang reale Geschäft...
Verwandte Themen
Diese Seiten ordnen den Artikel in einen größeren Leistungs- und Entscheidungskontext ein.
Technische Windows-Themen
Portal zu Windows-Entwicklung, Fehleranalyse und der Nutzung bestehender Assets.
ActiveX-Migration
Entscheidungen zum Beibehalten, Kapseln oder Ersetzen von COM / ActiveX / OCX.
Leistungen zu diesem Thema
Dieser Artikel ist direkt mit den folgenden Leistungen verbunden.
Windows-App-Entwicklung
Geschäftsanwendungen, Geräteintegration und Kommunikationstools von den Anforderungen bis zur Umsetzung.
Nutzung und Migration bestehender Assets
Wiederverwendung und Migration von COM / ActiveX / OCX sowie 32-/64-Bit-Abhängigkeiten.
Häufige Fragen
Fragen, die in Beratungen zu diesem Artikelthema häufig gestellt werden.
- Ist WinRT eine verwaltete Laufzeit wie .NET?
- Nein. WinRT (Windows Runtime) ist keine Ausführungsumgebung mit virtueller Maschine oder Garbage Collector, sondern ein auf COM aufgebautes ABI (ein Binärvertrag). Microsofts eigene Dokumentation hält fest: "The Windows Runtime is based on COM". Jede WinRT-Schnittstelle fordert IInspectable, das von IUnknown erbt. Jeder Aufruf bleibt ein COM-Aufruf über eine vtable, gestützt auf Referenzzählung (AddRef/Release) und QueryInterface. Der Name ".winmd" und die enge Passung zu .NET lassen WinRT leicht für eine verwaltete Umgebung halten, aber eine .winmd ist eine Metadatendatei, die dasselbe physische Format wie ECMA-335 leiht, und die systemseitig bereitgestellten .winmd-Dateien enthalten keinen ausführbaren Code. Dass C# so natürlich aufrufen kann, liegt daran, dass eine Sprachprojektion aus diesen Metadaten eine C#-Sicht erzeugt.
- UWP gilt nicht mehr als Mainstream. Lohnt es sich trotzdem, WinRT zu lernen?
- Ja. UWP, das App-Modell, und WinRT, die API-Grundlage, sind zwei verschiedene Dinge. Auch nach dem Zurückfahren von UWP werden die meisten WinRT-APIs weiterhin so bereitgestellt, dass WPF-, WinForms- und Win32-Desktop-Apps sie aufrufen können, und viele Fähigkeiten des heutigen Windows — Toastbenachrichtigungen, Freigabe, Bluetooth, OCR — sind als WinRT-APIs veröffentlicht. Darüber hinaus steht WinUI (Windows App SDK), das native UI-Framework, das Microsoft derzeit empfiehlt, auf dem WinRT-ABI. Mit anderen Worten: Die Mechanik von WinRT (IInspectable, .winmd, Sprachprojektionen) ist kein UWP-Relikt, sondern genau das Fundament der aktuellen Windows-App-Entwicklung.
- Kann eine WPF- oder WinForms-App WinRT-APIs aufrufen?
- Ja. Ab .NET 6 reicht es, das TargetFramework des Projekts auf ein TFM mit Windows-OS-Version zu setzen, etwa net8.0-windows10.0.19041.0; dann werden die Projektionsassemblys des Windows SDK referenziert, und die WinRT-APIs in den Windows.*-Namespaces lassen sich direkt aus C# aufrufen. In C++ fügen Sie das NuGet-Paket Microsoft.Windows.CppWinRT hinzu und nutzen C++/WinRT mit C++17 oder höher. Es gibt jedoch drei Stolperstellen. Erstens brauchen UI-Klassen, die ein CoreWindow voraussetzen, etwa Picker und Dialoge, vor der Anzeige den HWND des Besitzerfensters über IInitializeWithWindow (die Ausnahme ist DataTransferManager der Freigabe-UI: statt IInitializeWithWindow nutzt es das eigene IDataTransferManagerInterop, einen getrennten Pfad, der den HWND an ShowShareUIForWindow übergibt). Zweitens verlangen einige APIs, etwa der Benachrichtigungsverlauf und Sprunglisten, eine Paketidentität (MSIX-Paketierung oder ein Paket mit externem Speicherort). Drittens muss ein Thread, der WinRT-Objekte behandelt, zuerst initialisiert werden. Im nativen Code legen Sie das Concurrency-Modell STA/MTA mit winrt::init_apartment oder RoInitialize fest (in C#-WPF/WinForms-Apps übernimmt das in der Regel die Laufzeit). APIs, die von CoreWindow oder ApplicationView selbst abhängen, lassen sich aus Desktop-Apps überhaupt nicht nutzen.
- Der Aufruf eines Pickers wie FolderPicker aus einer Desktop-App löst eine Ausnahme aus. Warum?
- Weil einige WinRT-Picker- und Dialogklassen darauf ausgelegt sind, auf einem UWP-CoreWindow zu erscheinen. Eine Desktop-App hat kein CoreWindow, daher muss das Besitzerfenster vor der Anzeige ausdrücklich mitgeteilt werden. Konkret holen Sie zuerst den HWND des Besitzerfensters (WinRT.Interop.WindowNative.GetWindowHandle für ein WinUI-Window, WindowInteropHelper für WPF, die Handle-Eigenschaft des Formulars für WinForms) und übergeben ihn in C# mit WinRT.Interop.InitializeWithWindow.Initialize an den Picker. In C++/WinRT führen Sie QueryInterface auf IInitializeWithWindow aus (as<IInitializeWithWindow>()) und rufen Initialize(hwnd) auf. Ohne diese Initialisierung wirft der Aufruf oder scheitert still. Die neueren Picker des Windows App SDK (Microsoft.Windows.Storage.Pickers) sind so umgestaltet, dass sie eine WindowId im Konstruktor entgegennehmen, wodurch dieses Initialisierungsmuster entfällt (weil es Windows-App-SDK-APIs sind, reicht ein TFM-Setzen allein nicht: das SDK muss hinzugefügt werden, und für eine nicht paketierte App müssen Laufzeit auf den Zielrechnern bereitgestellt und initialisiert werden).
- Die WinUI-Entwicklung soll auf GitHub geöffnet worden sein. Sollte man bestehende WPF/WinForms-Apps wegwerfen?
- Es besteht kein Grund zur Eile. Die Öffnung der WinUI-Hauptentwicklung ist eine Richtungsaussage, dass Microsoft ernsthaft in sein natives Framework investiert, keine Kündigung der bestehenden Frameworks. WPF und WinForms werden heute weiterhin als Teil von .NET unterstützt. Teilen Sie die Entscheidung in zwei. Die eine ist, ob Sie das UI-Framework migrieren — eine große Entscheidung, die von Umfang der Bildschirmassets, Drittanbietersteuerelementen und der Entwicklungsorganisation abhängt. Die andere ist, ob Sie WinRT-APIs gezielt aus der bestehenden App nutzen; das kann heute mit einer TFM-Einstellung beginnen. Beachten Sie, dass das TFM die APIs nur aufrufbar macht; Toastbenachrichtigungen etwa brauchen zusätzlich zur Aufrufbarkeit eine Registrierung (auf dem klassischen Pfad muss eine nicht paketierte App eine Verknüpfung mit AppUserModelID registrieren — eine paketierte App nicht, weil die Paketidentität die AppUserModelID liefert; auf dem Windows-App-SDK-Pfad muss das SDK hinzugefügt werden — und für eine nicht paketierte App muss die Windows-App-SDK-Laufzeit auf jedem Ziel-PC installiert sein — und Register() von AppNotificationManager aufgerufen werden, während bei einer mit MSIX paketierten App die automatische Registrierung durch Register() nicht greift und zusätzlich ein COM-Aktivator in Package.appxmanifest deklariert werden muss). Auf dem Windows-App-SDK-Pfad sind Benachrichtigungen aus einem zum Administrator erhöhten Prozess außerdem nicht unterstützt, und Show scheitert still ohne Ausnahme — eine App, die Erhöhung braucht, sollte erwägen, Benachrichtigungen in einen nicht erhöhten Prozess auszulagern. Trotzdem: Wer nur Toastbenachrichtigungen will, muss nicht nach WinUI migrieren. Das Mischen von WinUI-Steuerelementen in bestehende WPF/WinForms-Bildschirme (XAML Islands) erfordert eine Unterscheidung der Generationen. Die Islands der UWP-Generation endeten für WPF/WinForms bei .NET Core 3.x, und für die WinUI-3-Generation ist die XAML-Hosting-API des Windows App SDK (DesktopWindowXamlSource) aus WPF/WinForms nutzbar, aber es gibt keine bequemen Wrapper-Steuerelemente und der Implementierungsaufwand ist hoch, daher ist derzeit eine vorsichtige Bewertung der sichere Weg.
Autorenprofil
Profilseite des Artikelautors.
Go Komura
Geschäftsführer von KomuraSoft LLC
Spezialisiert auf Windows-Softwareentwicklung, technische Beratung und Fehleranalyse, insbesondere bei bestehenden Systemen und schwer reproduzierbaren Störungen.