Writing GUI apps for Windows is painful
Samuel Tulach discusses challenges in writing Windows GUI apps in C++, emphasizing requirements like Windows support, styling, and efficiency. He evaluates various frameworks, recommending Dear ImGui for its simplicity and lightweight design.
Read original articleSamuel Tulach discusses the challenges of writing GUI apps for Windows in C++. He outlines requirements for Windows support, commercial use, easy styling, a single .exe file under 40MB, and efficient GUI development. He evaluates WinUI 3, Win32/MFC, Qt, wxWidgets, hikogui, Sciter, and WinForms/WPF, highlighting issues like dependencies, styling limitations, and complexity. Despite drawbacks, he recommends Dear ImGui for simple apps due to its small size, no dependencies, and DirectX integration for smooth UI rendering. ImGui's example project showcases multi-viewports for creating straightforward GUI apps efficiently. With a compiled size of 500KB and no need for additional installations, ImGui stands out for lightweight and straightforward GUI development on Windows.
Related
X debut 40 years ago (1984)
Robert W. Scheifler introduced the X window system in June 1984 for the VS100 Unix server, offering improved performance over W. The system was stable, with the Laboratory for Computer Science already transitioning to X and developing applications. Scheifler encouraged experimentation and welcomed volunteers for documentation contributions.
Let's write a video game from scratch like it's 1987
Philippe Gaultier created Minesweeper in 1987 using X11 without libraries, resulting in a compact executable. The article explores X authentication, Odin language usage, and minimalistic GUI development, offering insights into X11 intricacies. Source code is on GitHub.
Is 2024 the year of Windows on the Desktop?
In 2024, the author reviews Windows 11, highlighting challenges like limited hardware support, lack of installation control, manual driver search, slow updates, and UI lag. They compare favorably to Linux distributions.
U++ – Cross-Platform App Development Framework
U++ is a C++ framework for rapid application development, featuring GUI and SQL libraries, TheIDE, and support for various compilers. It aims to enhance C++ productivity across multiple platforms.
Chris Titus Tech's Windows Utility – Install Programs, Tweaks, Fixes and Updates
A GitHub repository offers Chris Titus Tech's Windows Utility for Windows tasks optimization. Admin mode is required for system-wide changes. Features include program management, tweaks, issue fixing, and update control. Visit the repository for more.
Specifically, the requirement for completely custom GUI styling without writing his own render functions means it’s really a task of selecting easy, customizable GUI libraries rather than generic GUI work.
The requirements to be self-contained executables and under a 40MB limit also rule out a lot of options. The author admits that Qt could have met these requirements but the open-source licensing part wasn’t compatible with his goals and he didn’t want to pay for a license.
If you relax the requirements to tolerate some dependencies, allow larger download sizes, or to simply use built-in Windows GUI controls the situation is very different.
For writing a lightweight, completely custom GUI with no external dependencies and permissive licensing I could have guessed ImGui would be the answer before I started reading.
Also the single exe deployment, while convenient at times, is perhaps not worth the hassle in this scenario. Using a packager like Velopack (squirrel) makes it a single exe to distribute and as an added bonus makes it self updating. That it has two or more files on disk when installed seems like a good tradeoff.
Windows is the worst platform to develop desktop apps for, apart from all the others.
Author did not enable high-DPI support in his/her application. As simply as that...
Either in Visual Studio : https://sciter.com/wp-content/uploads/2024/06/high-dpi-aware...
Or by including proper manifest: https://gitlab.com/sciter-engine/sciter-js-sdk/-/blob/main/d...
That actually is explained in "Hello C++" tutorial: https://sciter.com/hello-cpp-tutorial/
> Writing GUI apps for Windows is painful when requirements are unrealistic
They should try to target .NET Framework 3.5 using WinForms. That is my best suggestion, as all recent versions of Windows will have this installed (at least).Go back in an emulator some time and try Visual Studio or even old Borland from the 1990s. Point, click, add code, set style, and the result was not bad at all. The whole UI looked consistent too with uniform controls, shortcuts, etc.
Today UI apps use 100X more memory, are slower, and are harder to use with little to show for it in terms of improved functionality. The whole desktop is a disaster of conflicting designs and accessibility or uniformity are practically gone.
Mobile is kind of shocking too. Here was a chance to dump cruft from desktop and do things better but the result really is just as much of a pain in the arse if not more. Consistency is a little better but the developer experience is awful and of course unlike desktop you really can’t develop on the actual device. That adds another layer of shit.
+ "portable" (single exe with no automatic unzipping of dlls or anything)
+ commercial and unwilling to redistribute compiled object files (which together with the "portable" requirement, means no LGPL)
+ dark mode
Windows GUI apps is painful. Drop any one of these requirements and there are good established options.
Specifically I think most "portable" applications use win32 because, usually, portable => small, simple application where functionality is more important than dark mode or other styling ability.
I don't understand why this is a rule. I mean, I don't know what the author is trying to build, but in general the GUI is the part that the users spends all of their time interacting with. I don't see why it would be a problem if a little more time was spent there.
It actually take s a lot of work. The boilerplate code is OK but I never realized that showing strings on Windows is such a PIA. I have deep respect for anyone who wrote Windows GUI apps back in the late 80s -> early 90s before RAD is a thing.
As a side note. I recently got a book about WinG game programming on Windows 3.X/95. I remember back in the day the game Fury3, a fascinating 3d flight shooter game, was developed in WinG. It could be an interesting archeology project to develop something serious with WinG, the predecessor of DirectX.
It's a feature.
Custom styling should be considered a hostile pattern in most cases, except in highly specialized software with workflows dependent on prior user experience, such as DAWs.
Apart from QT, there is Avalonia, which is full of bugs. Linux support is remarkably bad.
Also there is Kotlin/Compose Multiplatform. It lacks good documentation, advanced controls and still full of bugs.
I was unable to find any good controls library for JS/TS, even paid ones (like Telerik and others) are pretty messy. So, Electron, Capacitor, React Native - they all assume a non-trivial effort to be put into even a very basic app.
Flutter feels extremely immature, and the strange popularity of global singletons makes it extremely hard to navigate even small codebases.
This is a weird comment that shows the philosophy of old school win32 has not clicked for them. The key element in win32 is the wndproc. Most controls ask their parent what color they should be via a window message.
If you find this inconvenient, wrapping that in a small library to remove boiler plate is not a big deal.
I remember the half-baked transition from Windows Forms to WPF, which was then taken-over by the Windows Phone initiative, which was also extremely painful and half-baked.
There's a reason electron is so popular, despite all the complaints about it as a platform. Don't blame the electron devs, blame Microsoft for completely failing to support their own platform. That lack of long-term support and consistency extends to a ton of areas in the Windows world, not just GUI development.
If you use the legacy .NET 4 framework, the .NET runtime will come pre-installed on modern Windows. If you compile your C++ DLL with static C runtime, your C++ DLL won’t have any dependencies apart from OS components like kernel32.dll.
If you insist on having a single EXE you’ll need to bundle it and extract, but the additional code for the P/Invoke to work is like 4 lines of that code, call LoadLibraryW from kernel32.dll early on startup, before using any stuff with [DllImport] from that DLL.
I do not recommend C++ CLI. Write normal C++ which compiles into native code without any weird metadata. You can use C APIs, or COM interop with ATL, or check this library of mine https://github.com/Const-me/ComLightInterop/
If you start with this approach (as opposed to refactoring a C++ app you already have) you’ll find out that you need substantially less C++ than you expected. Essentially, C++ is only required for 2 things: CPU-bound number crunching, and code which consumes large C or C++ libraries (Windows SDK is huge and pieces like D3D or MediaFoundation require C++). It’s much easier to do everything else in C#, as the language and especially the standard library are just better.
More info here: https://learn.microsoft.com/en-us/windows/msix/desktop/deskt...
Full disclosure: I work at Microsoft.
I had the exact same issues with WinUI3, where each time I compiled and wanted to run the application I had to install it into Windows, with its own start menu entry and registry entries and all that stuff. Really inconvenient and not worth it unless you like and desire that "new app" look of the Settings etc.
Qt wasn't too bad but you still had to do a similar install step within CMake to make the necessary Qt DLLs available to your application to run it. It's also not the fastest system around for UI.
- Tried to wade through the mess of different frameworks. Some are abandoned, they all have different feature sets etc...
- I found that I could not have anything other than FullTrust (all permissions) if my app wanted to use the/live in the system tray.
- You can't set the size of the window to match the content. You can set a size, sort of, but the min is 500x500 AND it will remember what the user's last size was so if they e.g. maximize it will be the next time its opened regardless of the program settings. In order to do this simple thing I would have to write it as a WPF app with a installer (which as of 2023 can go on the Windows Store)
That's rarely a reasonable expectation. Good usability is hard work.
> I figured out that for simple apps there is simply nothing better suited than Dear ImGui.
If you hate your users, sure. For anything more than a toy please use a real GUI framework.
That's not a problem, it's a feature. I am absolutely bloody sick of apps that go out of their way to reinvent the standard UI controls in perplexing ways and behave unexpectedly. Following the system UI preferences is what you should do, and it irritates your users if you don't.
There is a “hidden” dark mode for Win32 controls used by Windows File Explorer that you can activate, but it covers only some of the controls and still doesn’t look good.
Don't do that. If you use the regular Win32 controls then they will automatically get the styling the user has set.
I've been writing Win32 apps for close to 30 years now. It's sad to see the regression in UIs over the years.
Until you discover Delphi/Lazarus.
Implementing a custom paint routine is how you do theming in many UI toolkits. I get the impression the author is looking for a toolkit with declarative theming, like CSS.
> The issue is that with bundling the .dll, it would still mean it being extracted somewhere and writing additional code for the P/Invoke to work, and C++/CLI gets compiled to .NET IL code, in other words, you can open the resulting app in dnSpy and see the C++ code translated to C# equivalent (which is not what I want, I want native code).
I don’t understand how that makes WPF a non-viable solution. The author seems to have pretty strong feeling that it should absolutely be native code, but it’s not clear why
Sadly the same applies to Lazarus/LCL too. Not only that, I had a nasty surprise recently when Fedora Budgie did not install GTK2 by default.
Win32 era was fun, for development and for reversing. But alas...
Computers come with a modern browser now. Instead of a .exe file, could it be, let's say, a single .html file with inlined image/css/javascript?
This is a great example of why. A small set of reasonable requirements and already almost all the options on what is probably the best-endowed OS for toolkits are almost all disqualified, and what did fit was an odd solution that won't work for a lot of other use cases. It isn't that these are unreasonable requests per se, it is that this is how this space works. Everybody has weird requirements of some sort, pretty much all the time, and getting even reasonable coverage is a huge, huge project.
I'm not saying C# is better than C++, but just that choosing one over the other does have an impact.
I'm starting to suspect that general-purpose languages just aren't flexible enough to keep up with changing fashions in UI development. Whenever somebody comes up with a new UI paradigm, you're not going to be able to take full advantage of it until somebody designs a new programming language with that paradigm in mind.
If so, this might explain why the Windows team keeps pushing new desktop UI libraries, only to abandon them within a few years - they just don't have the willingness or resources to migrate away from C# and C++, and so the quality of their UI libraries is stuck in 2006.
1. We can update the gui without the user installing an update.
2. Lots of great web ui libraries, designers, and developers to make it look great.
3. Relatively lightweight
There, fixed it for ya.
There are solutions if you're not hell-bent on using C++, be it .Net, Lazarus (FreePascal) or Delphi. We're using Delphi at work and for the most part it's super simple and easy.
GUIs are a lot of work. People should be more willing to pay for work like that. Wanting everything free is one reason Big Tech has so much control.
[1]: https://gavinhoward.com/2024/05/a-new-architecture-for-a-gui...
Yes, productivity is more important than squeezing out the last bit nowadays, but that the poster couldn't get his 40 MB limit satisfied shames the whole software industry. He should get a simple (i.e., half a dozen menus, dialogs, windows) GUI app done in 400 kB (it was possible in the past).
tkinter may not be the sexiest way to do things, but its definitely productive in terms of the code-compile-distribute methodology, and it is very easy to wire up to a generalized 'daemon'-style abstraction, where the app logic is implemented as a daemon, sent application commands over a well-greased socket.
With this architecture, I no longer care that its Windows underneath - this is just another platform target - and can easily use either MacOS or Linux as the development environment, needing only to test on Windows, ultimately.
Anything beyond the sphere offered by tkinter is just less appealing. If I have to start treating a platform target in any kind of 'special' way, I just lose interest in that target, as a whole - however, from a UI perspective, Windows tkinter support hasn't been that bad, and generally keeps up fine.
(Disclaimer: if I really need performance, I also use the JUCE framework for my needs - even though its an audio-centric framework, you can build GUI apps with it just as well, and its also a cross-platform way to do things in pure C++ ..)
Also, the inverse that really good software tools often don't see the light of day is also true. It really doesn't matter if some tool is good or bad for adoption. What matters is; does it have the backing of big tech? It shows that tech media is completely monopolized.
Hmm, this got me thinking about stuffing native code into CLR image. If you would just include additional executable code sections into PE, would loader map them normally? Or presence of IMAGE_DIRECTORY_ENTRY_COMHEADER would stop it from mapping native code? If so, maybe you could remove that header and manually do pre-XP style initialization, by calling _CorExeMain from imported mscoree.dll. Though you would need to somehow trick it into locating COMHEADER that we removed.
Or maybe I'm overthinking this and MS already supports that? https://learn.microsoft.com/en-us/cpp/dotnet/mixed-native-an...
Because Xaml Island is a "system component", you don't need to install or bundle anything. And unpackaged .exe is supported.
There's one problem, if you want to use Xaml Designer in Visual Studio: Because .xaml files are compiled and packaged into a "resources.pri" file. You have to ship this file with your .exe program. This can be solved by hooking system dll, see my project: https://github.com/ysc3839/SingleExeXamlIsland
One could imagine a framework that would absorb all this historical know-how and turn GUI app development into a zero marginal cost exercise (fast, functional, cheap and maybe even pleasant) but who would push for this and why?
Maybe its a case of somebody not learning a lesson when their economic interest depends on not learning it?The overview of existing frameworks (including browser/webview based) suggests there is a sort of stagnating stalemate that feels sub-par but probably works just fine for those who have any leverage over the status-quo.
I've used QT in the past decade for MWL (Mac/Win/Lin) and it is a bit clunky compared to the graphical fluidity of Electron. We just need a solid effort to make Electron smaller. Granted, one can build smaller variants, but even 100 MB is far too large.
I disagree with the entire aeticle.
There is simply no contest. MacOS 10.0 was far superior as an environment to develop desktop apps when released, than Microsoft Windows is today with any toolkit you might want to choose.
I can't stand this mentality. The GUI is your functionality. The rest as far as the user is concerned may as well be pixies and fairy dust. Treating UI as an afterthought is why we've ended up with so much nightmarish crap these days.
I'm all-on-board with look like the OS/platform but also, here's and example of custom styling done well.
It MUST be open spec. It MUST be free for all/any to implement. It MUST either be included or be in the primary vendor (MS, Apple, distro) software center.
A simple Hello World, click OK to exit the program application should be able to be cross-compiled for any platform, and the resulting binary MUST NOT require including / embedding DLL / library hell like everything today does. It SHOULD be a small entirely dynamic program; possibly a few hundred kilobytes at most but even that seems too large. After all, it would mostly be the basic boilerplate of setting up memory, calling the system library loader, and linking in the shared libraries.
Oh man, I wish. No such tool exists. Adding a GUI to anything almost always at minimum triples the complexity.
There is a small business option that is cheaper. But probably still not appropriate for this project.
B. And, if you had to write a cross platform app, which framework would you use?
Let me stop you right there. No.
Leave the OS to style controls how it does, for consistency. There is no reason to be inconsistent. This is not 1994 and you’re not writing a warez keygen
For myself I rarely write app. Most often I self-host programs. GUI is managed by a browser.
It's pretty much either paying for Qt or use the bloated Electron.js. Looks like the latter won the market.
I failed to see other practical options, flutter was an option, but its strength is not on desktop so far.
Build a web app and use Google V8 with your c++ code.
In recent years, I have used WPF/Avalonia and while they are good - can lead to a lot of bloat following MVVM.
In the last year, I remember needing an application that shows a map. I tried to find support for openstreetmap and, while they exist, did not support what I needed to do. I tried Avalonia, and then GTK, etc. To be honest, I really liked GTK.. it just didn't have the tools I needed, sadly.
I have leaned to immediate mode UIs these days. I like I can create something with minimal code. Sadly, no openstreetmap support from what I can see.
In the end, I created a web interface. openstreetmap (leaflet) did everything I needed.
I am writing this article while it’s 32°C inside my room.
It took a horrendous heat to make a programmer find the best GUI library, but it was worth it! 500KB for imgui? Seriously? I remember Inno Setup creator saying that we was compiling his 'boot' application (to reduce size, because it was glued as a prefix to a zip file) in Delphi 2...Is anything stopping the author from buying a heat pump?
Frankly I don’t see why C# targeting an old (3.5?) .NET framework version wouldn’t work for the author. There seems to be a tendency to fixate on how things should be vs where we are now. C++ native GUI dev is not a mainstay like it used to be.
Is 40MB a lot nowadays? Eg the argocd cli is 155MB, and that's just a relatively simple cli app that as far as I know just calls a remote api.
Welcome to bloatworld I guess.
Microsoft: Oh, yeah, to use it, you'll need to deploy it with the Microsoft Store.
Whenever an article is trying to compare several options, it is very important to know beforehand what the author is trying to achieve, and what the restrictions are. And in this blog, the author has clearly stated that the restrictions are to develop a GUI within 40MB and should be easy styling. No one should judge the author for the restrictions, as it may be from the author's specific needs, or directly come from the client's requirements. The clear restrictions are also very helpful for readers like me to understand the trade-offs the author has made, which is not something that I have to do myself, but I can definitely learn from the author's experience. If I am in a similar situation, or even with different restrictions and need to make a different trade-off, the author's experience can still be very helpful for me.
Just want to call out that it is not a fair ask for a blog post to exhaustively compare all the options, as it is very time-consuming for even a paying job. We learnt the specific restrictions that the author is facing to, and we learnt the author's experience with the options that the author has tried. That is already a lot of value that the author has provided to us, and I would like to thank the author for that.
Microsoft has developed VSCode with Electron.
>modern Windows components
I swear to God if I ever downloaded a piece of open source software from GitHub, opened it, and saw the deformed Windows 8 Metro UI gawping back at me, I would do everything in my power to wipe the blighted individual responsible from the face of the fucking Earth
Related
X debut 40 years ago (1984)
Robert W. Scheifler introduced the X window system in June 1984 for the VS100 Unix server, offering improved performance over W. The system was stable, with the Laboratory for Computer Science already transitioning to X and developing applications. Scheifler encouraged experimentation and welcomed volunteers for documentation contributions.
Let's write a video game from scratch like it's 1987
Philippe Gaultier created Minesweeper in 1987 using X11 without libraries, resulting in a compact executable. The article explores X authentication, Odin language usage, and minimalistic GUI development, offering insights into X11 intricacies. Source code is on GitHub.
Is 2024 the year of Windows on the Desktop?
In 2024, the author reviews Windows 11, highlighting challenges like limited hardware support, lack of installation control, manual driver search, slow updates, and UI lag. They compare favorably to Linux distributions.
U++ – Cross-Platform App Development Framework
U++ is a C++ framework for rapid application development, featuring GUI and SQL libraries, TheIDE, and support for various compilers. It aims to enhance C++ productivity across multiple platforms.
Chris Titus Tech's Windows Utility – Install Programs, Tweaks, Fixes and Updates
A GitHub repository offers Chris Titus Tech's Windows Utility for Windows tasks optimization. Admin mode is required for system-wide changes. Features include program management, tweaks, issue fixing, and update control. Visit the repository for more.