Embed a Windows manifest in your Rust program
Tags: rust, windows
Published: 2022-08-21 00:21:44

---
title: Embed a Windows manifest in your Rust program
published: true
description: Several ways to embed a Windows application manifest in a Rust program, even when cross-compiling. 
tags: rust, windows
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/unk72gi23xs8st6azaig.jpg
---

If you’re distributing a standalone program for Windows, you should include an XML application manifest, but Cargo and Rust don’t provide an easy way to do this. In this post I’ll show you how you can do this yourself.

I’m using the manifest below, which unlocks compatibility with Windows versions 7 to 11, so that Windows doesn’t lie to your program that it’s running on Vista; sets the code page to UTF-8 so that you can pass Rust strings directly to API’s like `MessageBoxA`; and enables long path names if you configure them in the registry, letting your current directory be very long.

```xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" manifestVersion="1.0">
    <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
        <application>
            <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
            <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
            <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
            <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
        </application>
    </compatibility>
    <asmv3:application>
        <asmv3:windowsSettings>
            <activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
            <longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
        </asmv3:windowsSettings>
    </asmv3:application>
    <asmv3:trustInfo>
        <asmv3:security>
            <asmv3:requestedPrivileges>
                <asmv3:requestedExecutionLevel level="asInvoker" uiAccess="false"/>
            </asmv3:requestedPrivileges>
        </asmv3:security>
    </asmv3:trustInfo>
</assembly>
```

## The Visual Studio Build Tools way

If you only ever compile programs for Windows, on Windows, using the Visual Studio Build Tools, you can use a build script to add your Windows manifest by passing a couple of extra arguments to `LINK.EXE`:

```rust
use std::{env, path::Path};

fn main() {
    if env::var("TARGET").expect("target").ends_with("windows-msvc") {
        let manifest = Path::new("hello.exe.manifest").canonicalize().unwrap();
        println!("cargo:rustc-link-arg-bins=/MANIFEST:EMBED");
        println!("cargo:rustc-link-arg-bins=/MANIFESTINPUT:{}", manifest.display());
        println!("cargo:rerun-if-changed=hello.exe.manifest");
    }
    println!("cargo:rerun-if-changed=build.rs");
}
```

This is [what `rustc` does in release 1.63](https://github.com/rust-lang/rust/pull/96737/).

## The “hold my beer” way

If you are compiling or cross-compiling with the MinGW tools, you can embed the manifest resource using inline assembly:

```rust
#![windows_subsystem = "windows"]

use std::ffi::c_void;
use std::ptr::null;

#[link(name = "kernel32")]
extern "system" {
    fn GetVersion() -> u32;
}

#[link(name = "user32")]
extern "system" {
    fn MessageBoxA(hwnd: *const c_void, lpText: *const u8, lpCaption: *const u8, uType: u32) -> i32;
}

fn main() {
    let version = unsafe { GetVersion() };
    let major_version = version & 0x0f;
    let minor_version = (version & 0xf0) >> 8;
    let build = if version < 0x80000000 { version >> 16 } else { 0 };
    let message = format!(
        "It’s raining 🐈s and 🐕s.\n\nI think this is Windows {}.{} ({}).\0",
        major_version, minor_version, build
    );
    unsafe {
        MessageBoxA(null(), message.as_ptr(), "Manifest Test\0".as_ptr(), 0x40);
    }
}

#[cfg(all(windows, not(target_env = "msvc")))]
mod manifest {
    use std::arch::global_asm;

    global_asm!(
        r#".section .rsrc$01,"dw""#,
        ".p2align 2",
        "2:",
        ".zero 14",
        ".short 1",
        ".long 24",
        ".long (3f - 2b) | 0x80000000",
        "3:",
        ".zero 14",
        ".short 1",
        ".long 1",
        ".long (4f - 2b) | 0x80000000",
        "4:",
        ".zero 14",
        ".short 1",
        ".long 1033",
        ".long 5f - 2b",
        "5:",
        ".long MANIFEST@imgrel",
        ".long 1207",
        ".zero 8",
        ".p2align 2",
    );

    #[no_mangle]
    #[link_section = ".rsrc$02"]
    static mut MANIFEST: [u8; 1207] = *br#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" manifestVersion="1.0">
    <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
        <application>
            <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
            <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
            <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
            <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
        </application>
    </compatibility>
    <asmv3:application>
        <asmv3:windowsSettings>
            <activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
            <longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
        </asmv3:windowsSettings>
    </asmv3:application>
    <asmv3:trustInfo>
        <asmv3:security>
            <asmv3:requestedPrivileges>
                <asmv3:requestedExecutionLevel level="asInvoker" uiAccess="false"/>
            </asmv3:requestedPrivileges>
        </asmv3:security>
    </asmv3:trustInfo>
</assembly>"#;
}
```

The inline assembly goes in a COFF section named `.rsrc$01`, and the manifest string goes in a section named `.rsrc$02`. The linker combines these into a single `.rsrc` section in the executable, with `.long MANIFEST@imgrel` in the header being turned into a relocatable reference to the manifest string.

You can combine these two approaches to work with any of the `msvc`, `gnu` and `gnullvm` target environments.

## The easy way

Self-promotion moment: I’ve written a crate called [embed-manifest](https://lib.rs/crates/embed-manifest) that will use the MSVC approach, or generate an object file containing the manifest data in a `.rsrc` section and link against it, without needing to know as much about what you’re doing:

```rust
use embed_manifest::{embed_manifest, new_manifest};

fn main() {
    if std::env::var_os("CARGO_CFG_WINDOWS").is_some() {
        embed_manifest(new_manifest("Contoso.Sample"))
            .expect("unable to embed manifest file");
    }
    println!("cargo:rerun-if-changed=build.rs");
}
```

It has no external dependencies so it won’t slow your build down much at all.