Skip to main content
January 21, 2021
Uncategorized

Making Win32 APIs More Accessible to More Languages

Introduction

Win32 APIs provide powerful functionality that let you get the most out of Windows in your applications. While these APIs are readily accessible to C and C++ developers, other languages like C# and Rust require wrappers or bindings in order to access these APIs. In C#, this is commonly known as platform invoking or P/Invoke.

Historically this has required developers to handcraft the wrappers or bindings, which is error prone and doesn’t scale to broad API coverage. In recent years, given the strong demand for calling Win32 APIs from various languages, several community projects have spawned to provide more strongly typed and idiomatic representations of these wrappers and bindings to provide an improved developer experience and spare developers the overhead of creating them themselves. Some notable projects include PInvoke for .NET and winapi-rs for Rust.

The main challenge with these projects is they are manually maintained, which makes broad and sustained API coverage difficult and costly, and their work doesn’t really benefit other languages.

As owners of the Windows SDK, we wanted to see where we could provide unique value here, take some of the burden off of the community, and make achieving broad and sustainable API coverage across languages a reality.

The result of this is our win32metadata project and corresponding Win32 language projections now in preview on GitHub!

Win32 Metadata

The goal of the win32metadata project is to provide a complete description of the Win32 API surface in metadata so that it can be projected to any language in an automated way, improving correctness and minimizing maintenance overhead. The output of this project is effectively an ECMA-335 compliant Windows metadata file (winmd) published to Nuget.org containing metadata describing the entire Win32 API surface.

Win32 APIs have existed for a long time, so accurately describing all of them will take some iteration. We will be developing this tooling in the open and welcome community contributions to ensure an accurate representation of the Win32 API surface that will benefit all languages.

For this metadata to enable developers to call Win32 APIs idiomatically from the language of their choice, we need language projections built on top of it. The first such language projection is C#/Win32.

C#/Win32

Built in partnership with Andrew Arnott, the owner of the PInvoke project for .NET, C#/Win32 parses the metadata and generates the P/Invoke wrappers required to call the APIs you care about.

Simply add a reference to the Microsoft.Windows.CsWin32 package from NuGet.org and add a file called NativeMethods.txt to the root of your project with a list of Win32 functions you want to call. The file can contain one function per line or even wildcards like BCrypt.* for including entire modules. Once populated, C#/Win32 will generate the P/Invoke wrappers for the functions you request and all of their dependencies.

You can see in the animation above, after adding CreateFile to NativeMethods.txt and a using statement for the Microsoft.Windows.Sdk namespace, CreateFile can be called via the PInvoke static class. C#/Win32 provides rich Intellisense, strong types for parameters, and also includes the relevant documentation from docs.microsoft.com, all dynamically generated from metadata based on the APIs you request! No additional dependencies are required, broad API coverage is achieved with improved correctness and minimal maintenance overhead, and the APIs are expressed idiomatically as C# developers would expect.

You can learn more about C#/Win32 and try it for yourself by visiting the repo.

C#/Win32 is just an early example of what’s possible with dynamically created projections of Win32 APIs. We envision projections like this for many languages, all expressing Win32 APIs in whatever idiomatic patterns developers of the language expect. The windows Rust crate is another example.

Rust

The Rust language projection follows in the tradition established by C++/WinRT of building language projections for Windows using standard languages and compilers, providing a natural and idiomatic way for Rust developers to call Windows APIs. The windows crate lets you call any Windows API using code generated on the fly directly from the metadata, enabling you to call the APIs as if they were just another Rust module. It does not attempt to partition Windows APIs by technology, instead providing a single way to call any Windows API regardless of the underlying technology. You can seamlessly make use of APIs based on C-style exports, COM interfaces, or WinRT types. 

Other Languages

In addition to C# and Rust, we are also working on a Modern C++ projection in the open on GitHub and welcome community contributions there. These projects are early previews and under active development so are subject to change significantly as we absorb feedback and make progress. We will work with the community to support other languages based on demand, partnering with existing community projects where appropriate.

Under the umbrella of the win32metadata project, we hope to advocate a set of principles that all language projections should follow for the best developer experience while providing flexibility for each projection to do what’s best for their community.

Conclusion

Making Win32 APIs more accessible to more languages will allow developers to make the most out of Windows regardless of their preferred language. We are excited to engage with the community to expand API coverage and language support and minimize the maintenance overhead of existing projects.

You can view our roadmap, FAQs, and other useful details in our repo.