General Win32 API
Lena is a pretty good, concrete example of most of the common API solutions. 90% of interacting with Win32 seems to consist of working around years of layered historical design; almost nothing makes sense, nor has an explicit interface for dealing with an explicit problem.
In fairness though, the Windows API is pretty concise. You can get a simple but functional platform layer up in around 3-400 lines of code.
Code Pages
So Windows' handling of text is and has always been a fucking nightmare. From their refusal to migrate from CRLF line endings or Western ISO encoding — and I mean properly migrate, not bury a beta setting for system-wide UTF-8 in a disused area of the Control Panel twenty years after the standard's adoption in all other major operating systems.
That setting, by the way, can be found by running —
intl.cpl— and going to the advanced tab.
Unfortunately, this setting can and will break software, especially 'older' programs that are Windows-native. It also breaks a bunch of modern stuff too. I don't recommend it.
The most relevant this will ever be to your life as a programmer is when your (or your user's) console code page is just... entirely wrong, even if you go through the effort to set up your system correctly. The only guaranteed way to have this work is to just call —
chcp 65001— on console startup through a batch file or an alias.
A number of modern languages (in testing, Go and Rust, but not Odin or Zig) will perform automatic conversion of strings to the local code page when you write out, which is an interesting, if inefficient solution.
Now if you're not writing in Go or Rust... well you can't expect your users to understand this if you just want the output of a CLI tool to be intact on their system. The average user won't realise this is happening — I'm a text-encoding pedant and I didn't realise this problem was affecting me until recently because I'd only been programming in modern languages.
Anyway, there's a far better solution. In any language that doesn't perform this conversion, it's wise to directly set the output for the lifetime of that program with —
SetConsoleOutputCP(CP_UTF8)