Yeah, static DCE is a limited optimization. I've personally given up on it. It's not useless, but it's a big lift for developers and the app size will keep growing anyway. These days I'm more interested in dynamic code paging systems as a way forward, but, at the moment I'm not able to work on that right now. Think about how "bloated" an app like Google Maps or Search is, yet it still feels fast because it downloads what it needs on demand. Everything should work that way.

The Conveyor installer is a native Win32 app written in C++. It's pretty trivial, it mostly just invokes some Windows APIs, works around bugs in those and ties the results to a progress bar. It's a classic app that uses HWNDs, window messages and the like. The bulk of the logic is in one file. Despite that it's about a 500kb EXE. Where do the bytes come from? Partly, it's C++. Native code is verbose and template instantiation creates a lot of it. You don't need to instantiate many std::vectors before suddenly binary size has crept up on you. The widespread adoption of C++ increased binary sizes significantly over C, because suddenly you were using value typed containers everywhere instead of a single shared linked list utility library.

GraalVM native executables start extremely fast, but they aren't small. Partly this is the mismatch problem again: operating systems don't provide stuff like built in garbage collectors, even though GC is a fundamental service nearly every app needs, so, programs ship their own. Partly it's because GraalVM makes apps start fast by pre-initializing the app, so the binaries come with a heap image that it just mmaps and starts using. But then you have to download and store the initial heap instead of recomputing it at startup. It's a disk space/startup time tradeoff. And partly it's because a static analysis must be inherently conservative. Anything that could potentially run has to be included, even if in reality it never does (think exception handlers, assert messages...)

So IMO the right fix is to just assume an always-on internet connection and then stream code in as it's needed, with pre-emptive paging in the background to get apps into a state where you can disconnect. The system would aggressively deduplicate data to avoid redownloading stuff you already have. A smarter version of what browsers do. This lets you have apps that are hundreds of gigabytes in size but they still start fast and sip resources on the client side where you're most constrained.

I think modern languages ignore Win32 partly because it sucks and partly because virtually no working developers have ever used it. Many modern devs won't even realize it's there. How many devs that slung window messages in the 90s are still coding? I think a lot have retired or moved into management roles, or were hired to work on Chrome. There are Microsoft security engineers, working on Edge, who announced in a blog post that they had no idea how to use COM and had to rely on AI to write the needed code for them! [1] And a lot of devs aren't developing on Windows, they're probably writing these Rust toolkits on macOS or Linux.

Anyway, Win32 UI is something I'd not recommend using. It's been unmaintained for decades. Conveyor uses it because, well, it's an installer that downloads the rest of the app, so size matters more than anything else, and the UI needs are simple. The moment you want table stakes stuff like High DPI support, responsive layout, dark mode, vector icon support, data binding etc, you end up needing big frameworks that sit on top and/or you end up in a nightmare of twisty barely documented APIs.

[1] https://microsoftedge.github.io/edgevr/posts/Escaping-the-sa...