BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News Microsoft Using Metadata to Enable Idiomatic Win32 Interop from Rust and Other Languages

Microsoft Using Metadata to Enable Idiomatic Win32 Interop from Rust and Other Languages

This item in japanese

In a move to make it easier to use Win32 APIs from any language, Microsoft has launched its Win32 Metadata project with the aim of generating complete Win32 language bindings through automated, idiomatic projections. The project includes initial projections for C#, C++, and Rust.

The main benefit provided by win32metadata is removing the need to manually redefine the Win32 APIs to make them accessible from a language other than those Microsoft officially supports, such as C# and F#. Collected metadata are then used to create on-the-fly bindings through language-specific projections.

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.

Previously, making the Win32 APIs accessible from a different language required tapping into .NET's Platform Invoke (PInvoke) and add signatures, user-defined types, and any other information required to call Win32 and other unmanaged APIs. While the open wiki Pinvoke.net provides developers all such definitions so they do not have to find them out perusing Win32 header files, the process to convert them to a different language was, and still is, cumbersome and error-prone.

This project uses ClangSharp to scrape Windows SDK headers into C# files. It uses libraries from the Windows SDK to figure out what the DLL imports are for each API function. The project is split into partitions that roughly translate into namespaces. ClangSharp creates a .cs file for each partition that it processes.

The generated metadata attempts to include additional information to make using the APIs easier. For example, it converts constants specified using non-specific types like uint into explicit enums. Additionally, opaque types like HANDLEs and GDI objects are represented through strongly-typed structs, also including how to properly dispose the corresponding resource.

As mentioned, the project provides three initial projections for C#, C++, and Rust, but Microsoft is envisioning additional projections for many languages. All projections are able to call Windows API using code that is generated on the fly from the metadata included with the program.

The C++ projection is particularly interesting to understand what possibilities win32metadata opens up. In fact, developers have been able to access Win32 headers from C++ for a long time but, as Microsoft highlights, those headers hamper the use of modern C++ features due to historical and compatibility constraints. The new C++ projection ensures better compliance with C++17 and newer, while also using higher-level abstractions to replace macros, enumerations, and so on.

As an example of how you can use Win32 APIs from Rust idiomatically, this is what a Rust snippet calling into Win32 could look like:

mod bindings {
    ::windows::include_bindings!();
}

use bindings::{
    windows::data::xml::dom::*,
    windows::win32::system_services::{CreateEventW, SetEvent, WaitForSingleObject},
    windows::win32::windows_programming::CloseHandle,
};

fn main() -> windows::Result<()> {

    let doc = XmlDocument::new()?;
    doc.load_xml("<html>hello world</html>")?;

    let root = doc.document_element()?;
    assert!(root.node_name()? == "html");
    assert!(root.inner_text()? == "hello world");

    unsafe {
        let event = CreateEventW(
            std::ptr::null_mut(),
            true.into(),
            false.into(),
            std::ptr::null(),
        );

        SetEvent(event).ok()?;
        WaitForSingleObject(event, 0);
        CloseHandle(event).ok()?;
    }

    Ok(())
}

While promising, the win32metadata project is not complete yet:

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.

In particular, Microsoft plans to release stable projections for C#, C++, and Rust by the end of 2021, along with .NET 5 TFM integration of the C# projection, while additional language projections will be published starting in 2022.

Rate this Article

Adoption
Style

BT