.NET maintenance hell, Rewriting it in Zig

I just merged my rewrite of win32jsongen from C# to Zig!

win32jsongen converts the binary WinMD format to JSON, which is then used to generate Zig bindings for the win32 API. See the talk for more details.

I originally wrote win32jsongen in C# because it has built-in support for parsing WinMD files. However, the C# version was burdensome to maintain:

  • Toolchain Fragility - installing the IDE/toolchain with the right compiler version and .NET runtime/packages was a recurring headache
  • Runtime Versioning - after I got the project to build, that didn’t mean it would run. You’ve also got to figure out how to install a runtime with the correct version that can run it.
  • Churn - old .NET versions get deprecated forcing rewrites

The .NET ecosystem is hard to keep up with. The original Windows-only .NET Framework competed with the open-source Mono framework, which was eventually superseded by .NET Core, which itself was rebranded to just “.NET”, now on version 9 and counting. I’m still not sure which one I was using and I gave up trying to keep up with or understand what was going on.

Back in 2022, I lost my motivation to maintain this project (see Josh’s talk on this subject if you haven’t) and that’s the last time I updated the C# code. This means the API data used to generate the zig bindings is now lagging years behind, but, I was determined to solve this technical debt rather than fall back to dealing with the old headaches.

I started the port to Zig a couple years ago, but it was not easy work writing a good library to handle the WinMD format. I’d lose motivation again and get sidetracked, but still feel the constant nagging that I needed to get back to it. I picked it up again last weekend and finally had a breakthrough in the winmd library that got me past the final hump to the finish line. I’m happy with the winmd library which ended up being about 2000 lines of zig code most of which is type definitions.

After finishing, I also noticed I was being hamstrung by some of the abstractions introduced by the equivalent C#/.NET reflection API. Using the zig library results in a better understanding of how the data is structured which helped me improve the conversion tool.

With these changes I’m hoping to get the metadata up-to-date soon. I’m also excited to explore generating new C/C++ headers for the win32 API and I have ideas for rewroking the Zig bindings as well.

5 Likes

Years ago I was a C#/.NET zealot, and still do have a soft-spot in my heart for those times, but my experience was very similar to yours, and I ended up abandoning my C# projects a few versions into the .NET Core transition. It simply became too much hassle juggling compatibility with .NET Standard (not sure if this is still a thing), .NET Core (this was the ~3.0 days), and .NET Framework/Mono.

I am often amazed that a verbose systems-level language like Zig is able to so easily accomplish high-level tasks with less fuss than a enterprise language like C# or Java can do it in.

2 Likes

Same. I think C# is a great “managed language”. I wrote a lot of C# when I was at HP (here’s some). It was really exciting when they announced the official cross-platfom .NET core but they never seemed to get it together. I’m pretty sure all windows versions still come with a compiler for the old 3.5 version along with the runtime, so maybe that’s the most viable target? I’d be nervous depending on even that though as they could drop support at any moment. Ultimately, it seems like if you just want your stuff to work without being rug pulled, it’s best to stay native. It’s too bad.

P.S. I also recently creating a scripting language for modding unity games that interfaces with .NET via the mono embedded runtime API (see blog post).