Search code examples
rustrust-cargo

How to compile in Rust for Windows with a manifest?


I am currently developing a Rust application for Windows x86 that requires to be run as administrator. So I've written a Windows manifest that allows you to request administrator mode.

Here's the app.manifest (at the root of the project):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
        <security>
            <requestedPrivileges>
                <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
            </requestedPrivileges>
        </security>
    </trustInfo>
</assembly>

And here's the Cargo.toml file

[package]
name = "wrapper"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
named-lock = "0.3.0"
rand = "0.8.5"
reqwest = "0.11.24"
tokio = { version = "1.36.0", features = ["rt", "rt-multi-thread"] }
winapi = { version = "0.3.9", features = ["processthreadsapi", "securitybaseapi", "winnt", "fileapi", "minwinbase", "iphlpapi", "winsock2", "ws2def"] }
windows-service = "0.6.0"

[profile.release]
opt-level = 3

[package.metadata.win]
manifest = "app.manifest"

The problem is that when I compile via cargo (cargo build --release --target=i686-pc-windows-gnu), the manifest doesn't seem to be taken into account.


Solution

  • You can set the manifest during the build process using the following parameters:

    Build-Target:

    You have to use the build target i686-pc-windows-msvc or x86_64-pc-windows-msvc.

    Cargo.toml:

    [target.'cfg(target_os = "windows")'.build-dependencies]
    winres = "0.1.12"
    

    build.rs:

    #[cfg(all(target_os = "windows"))]
    fn main() {
        let mut res = winres::WindowsResource::new();
        res.set_manifest(
            r#"
    <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
        <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
            <security>
                <requestedPrivileges>
                    <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
                </requestedPrivileges>
            </security>
        </trustInfo>
    </assembly>
    "#,
        );
        if let Err(error) = res.compile() {
            eprint!("{error}");
            std::process::exit(1);
        }
    }
    

    Having a separate file is possible too, using winres::WindowsResource::set_manifest_file()