Well yes as a user I prefer native apps for their performance. It's clearly a mess to develop native apps as the article shows. But as a user I don't see that problem. I do see ever worsening apps though. Like the total mess that is new outlook and teams.
It's another example of how they have completely abandoned any attempt at providing a good user experience across their products
And if you set a native theme for TTK in your code (literal two lines), your software will stop looking Motif-Industrial, the widgets will have the classic Win32 themes. It will look native from XP and up.
Recently had to add a new feature to and old program that was last updated in the XP era and two things to note:
1. The program did not need to be updated to run on Vista, 7, 10 and 11, shit just kept working throughout the years.
2. I loaded the project into Visual Studio 2022, it converted from VC6 and compiled without problems, added the feature, shipped a new .exe to the customer, and it just worked.
What other platform has that backwards and forwards compatibility success story?
Such is the benefit and the curse, I guess, of having the Windows API being locked in the distant past for backwards compatibility.
I've always been surprised that Microsoft didn't do a full operating system refactor and provide a compatibility layer for running old binaries. Perhaps they figure it would be better to just transition everything to software as a service using web tech? But I just don't see how that strategy is gonna work long-term.
Running with html/css/js has benefits it really is open and free development based on international standards and not locked into any single big tech.
They'd lose too much enterprise software that's not being maintained any longer but still is business critical.
You can still run most programs from the Windows 95 era unmodified on a modern Windows 11 machine and a lot of things is relying on that under the hood.
Just keeping a legacy system in working order is different skillset than writing a new system from scratch.
So you need a new team. Nothing from Windows maintenance transfers.
Maybe would require hiring someone who knows how to design an OS.
It would be a major undertaking, needing protection by CEO (and if it would not succeed CEO would loose a lot of prestige).
I'm not saying MS does not have the existing talent base. I don't _know_.
But I've been inside a house maintaining a monstrous legacy codebase.
I can tell you - it requires surprisingly little deep understanding just to keep an existing system going.
Open? You wish.
>and not locked into any single big tech.
DRM and propietary cody tells me otherwise.
Well, if I remember correctly, the Godot editor is written in Godot.
CRUD apps are non-trivial.
If Unity were to ship platform native replacement for WPF equivalent (hell or even winforms) it would become a really enticing app development platform.
I originally had ATL in there, but my proofreading squad (Claude and ChatGPT) told me that ATL was a more niche thing for COM, and looking at the Wikipedia article I was convinced they were right.
But WTL was what I was thinking of---the step between the MFC and .NET that I forgot.
lol at them still bekng the best option. so much wasted effort trying to replace them
If you want something more custom, subclass NSControl and you’re off to the races.
And if Obj-C isn’t your cup of tea, one can use Swift instead, even in a codebase that had been only Obj-C prior.
But in case you want to read yourself: https://blogs.windows.com/windows-insider/2026/03/20/our-com...
I'm glad people still care about stuff like this. It drives me insane that the simplest form-based software that I build and compile ends up being 50-100 MiB; several times video games from the 80s that I grew up with that did much more complex work, graphically and computationally, on a tenth of the space.
The last time I had to do Windows development was about 15 years ago. I used a library called WTL (I think a couple comments here mention it). I couldn’t use any of the newer stuff that Windows 8-10 were pushing because it needed backward compatibility. It seemed way less bloated than MFC, but not as annoying to use as ATL or rawdogging Win32 APIs.
Ironically, I was developing a Win32 app to build a cloud bridge to a Rails app (talking to Quickbooks COM API which was hell on Earth, with XML and XML definitions) on Mac, using VMware on Mac to talk to Quickbooks Windows. I was so annoyed with Win32 development I used the Chrome Embedded Framework library to build the UI for the Win32 app so I wouldn’t have to wrestle WTL for UI and just have browser-based views to drive UI.
I think it was very tempting to drop C/C++ development for .NET code, but I didn’t want to drop off user adoption by requesting users to download a huge .NET runtime if their computer didn’t already have it.
This was when I was building Levion, a Quickbooks Windows to Cloud Rails app…
Clearly this is not an option for those who are just starting up with Windows GUI work, but with little experience it is really a matter of 2-3 weeks of ground work and then you have full control over all nuances of the UI, yours to extend and mend as you wish.
If there's one thing that Microsoft is really good at, it's ensuring deep backward compatibility. So anything that's based on Win32 API is going to be stable. If it works now, it will work later.
I have some examples from 10+ years of development updates accumulated here - https://bvckup2.com/wip
The lessons I've learnt building and shipping a few a Windows apps at scale are basically:
(1) Learn Win32 and use those ancient APIs if possible, they're extraordinarily stable and you'll probably need to reach for them anyway. They're not that scary.
(2) Don't use any Microsoft-owned UI toolkit, you'll get burnt. Literally anything is better. Ideally choose a toolkit that doesn't prevent layering in Win32 tweaks on top, otherwise you'll end up hitting cases the toolkit developers didn't think of and you can't fix. You're going to need a custom WindowProc eventually. You need to have access to the underlying Win32 window lifecycle and handles.
I first investigated the Windows native options and was pretty bamboozled; I wanted to use the "mainstream" "up to date" option (presumably c# and some framework) but as TFA describes, it wasn't at all clear which that was.
I ended up doing it in python with pyqt then finding out a clean deployment was a pain, so revisited the .Net options and remembered why I'd discarded them in the first place...
It is indeed a complete mess (at least coming in anew) and a very strange situation for the world's main desktop environment to be in.
But imgui is a breeze of fresh air for internal stuff
1. Wow you have great knowledge of windows. Congratulations
2. Boy windows API is a mess.
Wine is better at it than Windows itself. Especially for really old programs.
My first thought was MFC. Basic, fast, well understood.
But then maybe WxWindows so we can cross-compile it (from Linux) and use the same UI on other platforms? It could probably be compiled statically although I've not tested it.
Or Mono, but that needs a runtime?
Edit: Some comments mention Qt which could also work although how large is the runtime? Can it be compiled statically?
You dont have to use MVVM or AXML for example Uno allows for C# Markup[3] to be used instead or MVUX instead of MVVM.
I personally hate MVVM and AXML but you are not forced to use them.
For Avalonia I dabbled in creating my own replacement[4] for MVVM and AXML using Flecs.Net.
In Avalonia I created a tray icon for the trash bin. So I can see how big it is and clear/open it with a small menu[5].
Both Avalonia and Uno should at least be looked at when judging which framework to use. They are both quite mature and have many great controls and features built in.
[1] https://avaloniaui.net/ [2] https://platform.uno/ [3] https://platform.uno/docs/articles/external/uno.extensions/d... [4] https://github.com/AyanamiKaine/Ayanami-sTower/blob/main/Ava... [5] https://github.com/AyanamiKaine/Ayanami-sTower/blob/main/App...
Hobby projects should not be built on a platform that is constantly changing underneath.
On top of this, there are a small handful of system UIs that do support dark mode and make your program look inconsistent with dark mode regardless. Message boxes will switch to dark mode, and so will file dialogs -- which is a problem if you've used the Vista-style customization, as any syslinks will appear in a color of blue that's hard to read against the dark mode background.
Microsoft released it open source later on. Looking at the repository, looks like it has been kept up and maintained, up to version 10 now.
This is 100% true for all of their techs produced within the past ~20 years, but WPF and Winforms are extremely stable with no real issues.
It's so weird too because most of everything they've done in the past 20 years has basically just been incomplete remixes of WPF. If they just stuck with WPF and extended it onward, something like a UI toolkit equivalent of C#, it would 100% be the gold standard for Windows development today, and perhaps even UI development in general if they open source/standarded it.
WTL delivers very small and efficient code, very close in size and speed to SDK programs, while presenting a more logical, object oriented model to a programmer.
Plus the whole thing is meant to work on ancient Windows versions (like, Vista and WS2008 ancient), so that ultimately defines the minimal common UI denominator.
For years we loaded up libraries and abstractions to minimize boilerplate. These hid the actual underlying mechanisms and often made specific customisations harder to do since you were taken away from the raw functionality.
These days AI is extremely good at writing boilerplate and in my opinion explicitly typed out boilerplate code is much easier to reason about than a library that abstracts things away to a one line annotation or similar.
A good example is that i've recently been leaning back to the raw Android apis for things like recyclerviews etc. It used to be 10+ files to changed to create an efficient scrolling view on Android with various resources and adapters required. So a whole bunch of libraries came out to try to abstract the complexity away. You know what though? I don't care about that anymore. I'm going back to the raw GUI APIs where possible because it's so explicit and clear even if it's 10x more code.
Stable, but many issues. Stay away if you value your sanity and do anything nontrivial.
Second, win32 is designed with the ability to change all the default colors and you used to be able to do this by right clicking the desktop and selecting "properties". If dark mode doesn't follow this - just another symptom of Microsoft's siloing incompetence. The team that wrote dark mode may not have been aware that this feature existed because parts of the platform are so disconnected from other parts.
Use self-contained to have everything together.
https://learn.microsoft.com/en-us/dotnet/core/deploying/sing...
MFC, wx, Qt .. it's all overcomplex pointless bloat for this task imo.
You need a commercial license for that, but yes you could. But since applications are typically distributed with install bundles that put into application-local program files directories, it's not super-important as long as you only cherry-pick the Qt libraries you need.
- Windows 11 Hardening utility - made it because all existing ones are not updated to handle all the new AI telemetry + new updates + I made it differently and more powerful than anything that exists currently
- Windows Admin/ Security / Networking Utility built for my needs
- Windows 11 Anti Virus Nuker - Completely shuts off windows defender without disrupting system performance or zombie files
- and more
And the gap's going to keep growing - doing the upgrade now means future upgrades can be more frequent and incremental, rather than trying to move 4.8 to .NET 20 in a decade.
I think programmers started wanting "real" languages (notice the quotes), and henceforth got more complexity and things take longer, although with GenAI, we may be back to the "draw as screen and do this" that we were with VB6. Just now the source generated should be considered the object code, and the prompt is the new source (at least for those types of apps)
Win32 controls ignoring system colors goes much farther back than dark mode being introduced in Windows 10. The theming engine that broke a lot of that functionality was introduced in Windows XP. Beyond that, there were always a few hardcoded colors like disabled gray text going back to Windows 95.
Dark mode ignoring Win32 system colors is not incompetence. It was _intentional_. Dark mode was introduced by the UWP side, which intentionally did not extend it to Win32. To this day, there is not even a Win32 API for desktop apps to query whether dark mode is even enabled. The official recommendation is to compute the luminance of the UWP foreground color setting:
https://learn.microsoft.com/en-us/windows/apps/desktop/moder...
Basically the kind of customers that were affected by the breaking changes, between Framework and Core, decided to keep the old stuff running in Framework, and consider other alternatives going forward.
Not sure how much these kind of customers matter to the .NET team's upper management in customer acquisition, but they surely lost a few along the way.
And now there is even CoPilot based migration tooling on VS 2026, because most likely there aren't that few that are still chugging along with Framework.
I've observed many people spreading this misinformation about only being able to dynamically link with the LGPL version of Qt. Please stop this.
[1] https://www.gnu.org/licenses/gpl-faq.html#LGPLStaticVsDynami...
Also, modern compilers make this method much harder to use. It is much harder to stably relink object files like that than to just use the normal dynamic link method.
>Dark mode is used by 81.9% of 2,500 Android users on their phones, in apps, and in other situations. 9.9% alternate between the light and dark
So it's the other way around. Only a very small minority of users actually care about light mode.
I’m a Windows guy; I always have been. One of my first programming books was Beginning Visual C++ 6, which crucially came with a trial version of Visual C++ that my ten-year-old self could install on my parents’ computer. I remember being on a family vacation when .NET 1.0 came out, working my way through a C# tome and gearing up to rewrite my Neopets cheating programs from MFC into Windows Forms. Even my very first job after university was at a .NET shop, although I worked mostly on the frontend.
While I followed the Windows development ecosystem from the sidelines, my professional work never involved writing native Windows apps. (Chromium is technically a native app, but is more like its own operating system.) And for my hobby projects, the web was always a better choice. But, spurred on by fond childhood memories, I thought writing a fun little Windows utility program might be a good retirement project.
Well. I am here to report that the scene is a complete mess. I totally understand why nobody writes native Windows applications these days, and instead people turn to Electron.
The utility I built, Display Blackout, scratched an itch for me: when playing games on my three-monitor setup, I wanted to black out my left and right displays. Turning them off will cause Windows to spasm for several seconds and throw all your current window positioning out of whack. But for OLED monitors, throwing up a black overlay will turn off all the pixels, which is just as good.
To be clear, this is not an original idea. I was originally using an AutoHotkey script, which upon writing this post I found out has since morphed into a full Windows application. Other | incarnations of the idea are even available on the Microsoft Store. But, I thought I could create a slightly nicer and more modern UI, and anyway, the point was to learn, not to create a commercial product.
For our purposes, what’s interesting about this app is the sort of capabilities it needs:
Let’s keep those in mind going forward.

Look at this beautiful UI that I made. Surely you will agree that it is better than all other software in this space.
In the beginning, there was the Win32 API, in C. Unfortunately, this API is still highly relevant today, including for my program.
Over time, a series of abstractions on top of this emerged. The main pre-.NET one was the MFC C++ library, which used modern-at-the-time language features like classes and templates to add some object-orientation on top of the raw C functions.
The abstraction train really got going with the introduction of .NET. .NET was many things, but for our purposes the most important part was the introduction of a new programming language, C#, that ran as JITed bytecode on a new virtual machine, in the same style as Java. This brought automatic memory management (and thus memory safety) to Windows programming, and generally gave Microsoft a more modern foundation for their ecosystem. Additionally, the .NET libraries included a whole new set of APIs for interacting with Windows. On the UI side in particular, .NET 1.0 (2002) started out with Windows Forms. Similar to MFC, it was largely a wrapper around the Win32 windowing and control APIs.
With .NET 3.0 (2006), Microsoft introduced WPF. Now, instead of creating all controls as C# objects, there was a separate markup language, XAML: more like the HTML + JavaScript relationship. This also was the first time they redrew controls from scratch, on the GPU, instead of wrapping the Win32 API controls that shipped with the OS. At the time, this felt like a fresh start, and a good foundation for the foreseeable future of Windows apps.
The next big pivot was with the release of Windows 8 (2012) and the introduction of WinRT. Similar to .NET, it was an attempt to create new APIs for all of the functionality needed to write Windows applications. If developers stayed inside the lines of WinRT, their apps would meet the modern standard of sandboxed apps, such as those on Android and iOS, and be deployable across Windows desktops, tablets, and phones. It was still XAML-based on the UI side, but with everything slightly different than it was in WPF, to support the more constrained cross-device targets.
This strategy got a do-over in Windows 10 (2015) with UWP, with some sandboxing restrictions lifted to allow for more capable desktop/phone/Xbox/HoloLens apps, but still not quite the same power as full .NET apps with WPF. At the same time, with both WinRT and UWP, certain new OS-level features and integrations (such as push notifications, live tiles, or publication in the Microsoft Store) were only granted to apps that used these frameworks. This led to awkward architectures where applications like Chrome or Microsoft Office would have WinRT/UWP bridge apps around old-school cores, communicating over IPC or similar.
With Windows 11 (2021), Microsoft finally gave up on the attempts to move everyone to some more-sandboxed and more-modern platform. The Windows App SDK exposes all the formerly WinRT/UWP-exclusive features to all Windows apps, whether written in standard C++ (no more C++/CLI) or written in .NET. The SDK includes WinUI 3, yet another XAML-based, drawn-from-scratch control library.
So did you catch all that? Just looking at the UI framework evolution, we have:
Win32 C APIs → MFC → WinForms → WPF → WinRT XAML → UWP XAML → WinUI 3
In the spirit of this being a learning project, I knew I wanted to use the latest and greatest first-party foundation. That meant writing a WinUI 3 app, using the Windows App SDK. There ends up being three ways to go about this:
This is a painful choice. C++ will produce lean apps, runtime-linked against the Windows APP SDK libraries, with easy interop down into any Win32 C APIs that I might need. But, in 2026, writing a greenfield application in a memory-unsafe language like C++ is a crime.
What would be ideal is if I could use the system’s .NET, and just distribute the C# bytecode, similar to how all web apps share the same web platform provided by the browser. This is called “framework-dependent deployment”. However, for no reason I can understand, Microsoft has decided that even the latest versions of Windows 11 only get .NET 4.8.1 preinstalled. (The current version of .NET is 10.) So distributing an app this way incurs a tragedy of the commons, where the first app to need modern .NET will cause Windows to show a dialog prompting the user to download and install the .NET libraries. This is not the optimal user experience!
That leaves .NET AOT. Yes, I am compiling the entire .NET runtime—including the virtual machine, garbage collector, standard library, etc.—into my binary. The compiler tries to trim out unused code, but the result is still a solid 9 MiB for an app that blacks out some monitors.
(“What about Rust?” I hear you ask. A Microsoft-adjacent effort to maintain Rust bindings for the Windows App SDK was tried, but they gave up.)
There’s a similar painful choice when it comes to distribution. Although Windows is happy to support hand-rolled or third-party-tool-generated setup.exe installers, the Microsoft-recommended path for a modern app with containerized install/uninstall is MSIX. But this format relies heavily on code signing certificates, which seem to cost around $200–300/year for non-US residents. The unsigned sideloading experience is terrible, requiring a cryptic PowerShell command only usable from an admin terminal. I could avoid sideloading if Microsoft would just accept my app into their store, but they rejected it for not offering “unique lasting value”.
The tragedy here is that this all seems so unnecessary. .NET could be distributed via Windows Update, so the latest version is always present, making framework-dependent deployment viable. Or at least there could be a MSIX package for .NET available, so that other MSIX packages could declare a dependency on it. Unsigned MSIX sideloads use the same crowd-sourced reputation system that EXE installers get. Windows code signing certs could cost $100/year, instead of $200+, like the equivalent costs for the Apple ecosystem. But like everything else about modern Windows development, it’s all just … half-assed.
It turns out that it’s a lot of work to recreate one’s OS and UI APIs every few years. Coupled with the intermittent attempts at sandboxing and deprecating “too powerful” functionality, the result is that each new layer has gaps, where you can’t do certain things which were possible in the previous framework.
This is not a new problem. Even back with MFC, you would often find yourself needing to drop down to Win32 APIs. And .NET has had P/Invoke since 1.0. So, especially now that Microsoft is no longer requiring that you only use the latest framework in exchange for new capabilities, having to drop down to a previous layer is not the end of the world. But it’s frustrating: what is the point of using Microsoft’s latest and greatest, if half your code is just interop goop to get at the old APIs? What’s the point of programming in C#, if you have to wrap a bunch of C APIs?
Let’s revisit the list of things my app needs to do, and compare them to what you can do using the Windows App SDK:
Enumerating the machine’s displays and their bounds: can enumerate, as long as you use a for loop instead of a foreach loop. But watching for changes requires P/Invoke, because the modern API doesn’t actually work.
Placing borderless, titlebar-less, non-activating black windows: much of this is doable, but non-activating needs P/Invoke.
Intercepting a global keyboard shortcut: nope, needs P/Invoke.
Optionally running at startup: can do, with a nice system-settings-integrated off-by-default API.
Storing some persistent settings: can do.
Displaying a tray icon with a few menu items: not available. Not only does the tray icon itself need P/Invoke, the concept of menus for tray icons is not standardized, so depending on which wrapper package you pick, you’ll get one of several different context menu styles.
But these are just the headline features. Even something as simple as automatically sizing your app window to its contents was lost somewhere along the way from WPF to WinUI 3.
Given how often you need to call back down to Win32 C APIs, it doesn’t help that the interop technology is itself undergoing a transition. The modern way appears to be something called CsWin32, which is supposed to take some of the pain out of P/Invoke. But it can’t even correctly wrap strings inside of structs. To my eyes, it appears to be one of those underfunded, perpetually pre-1.0 projects with uninspiring changelogs, on track to get abandoned after a couple years.
And CsWin32’s problems aren’t just implementation gaps: some of them trace back to missing features in C# itself. The documentation contains this darkly hilarious passage:
Some parameters in win32 are
[optional, out]or[optional, in, out]. C# does not have an idiomatic way to represent this concept, so for any method that has such parameters, CsWin32 will generate two versions: one with allreforoutparameters included, and one with all such parameters omitted.
The C# language doesn’t have a way to specify a foundational parameter type of the Win32 API? One which is a linear combination of two existing supported parameter types? One might think that an advantage of controlling C# would be that Microsoft has carefully shaped and coevolved it to be the perfect programming language for Windows APIs. This does not appear to be the case.
Indeed, it’s not just in interop with old Win32 APIs where C# falls short of its target platform’s needs. When WPF first came out in 2006, with its emphasis on two-way data binding, everyone quickly realized that the boilerplate involved in creating classes that could bind to UI was unsustainable. Essentially, every property needs to become a getter/setter pair, with the setter having a same-value guard and a call to fire an event. (And firing an event is full of ceremony in C#.) People tried various solutions to paper over this, from base classes to code generators. But the real solution here is to put something in the language, like JavaScript has done with decorators and proxies.
So when I went to work on my app, I was astonished to find that twenty years after the release of WPF, the boilerplate had barely changed. (The sole improvement is that C# got a feature that lets you omit the name of the property when firing the event.) What has the C# language team been doing for twenty years, that creating native observable classes never became a priority?
Honestly, the whole project of native Windows app development feels like it’s not a priority for Microsoft. The relevant issue trackers are full of developers encountering painful bugs and gaps, and getting little-to-no response from Microsoft engineers. The Windows App SDK changelog is mostly about them adding new machine learning APIs. And famously, many first-party apps, from Visual Studio Code to Outlook to the Start menu itself, are written using web technologies.
This is probably why large parts of the community have decided to go their own way, investing in third-party UI frameworks like Avalonia and Uno Platform. From what I can tell browsing their landing pages and GitHub repositories, these are better-maintained, and written by people who loved WPF and wished WinUI were as capable. They also embrace cross-platform development, which certainly is important for some use cases.
But at that point: why not Electron? Seriously. C# and XAML are not that amazing, compared to, say, TypeScript/React/CSS. As we saw from my list above, to do most anything beyond the basics, you’re going to need to reach down into Win32 interop anyway. If you use something like Tauri, you don’t even need to bundle a whole Chromium binary: you can use the system webview. Ironically, the system webview receives updates every 4 weeks (soon to be 2?), whereas the system .NET is perpetually stuck at version 4.8.1!
It’s still possible for Microsoft to turn this around. The Windows App SDK approach does seem like an improvement over the long digression into WinRT and UWP. I’ve identified some low-hanging fruit around packaging and deployment above, which I’d love for them to act on. And their recent announcement of a focus on Windows quality includes a line about using WinUI 3 more throughout the OS, which could in theory trickle back into improving WinUI itself.
I’m not holding my breath. And from what I can tell, neither are most developers. The Hacker News commentariat loves to bemoan the death of native apps. But given what a mess the Windows app platform is, I’ll pick the web stack any day, with Electron or Tauri to bridge down to the relevant Win32 APIs for OS integration.