Rust 프로그램에 Windows 매니페스트 포함
Windows 버전 7~11과의 호환성을 해제하는 아래 매니페스트를 사용하여 Windows가 Vista에서 실행 중인 프로그램에 대해 거짓말을 하지 않도록 합니다.
MessageBoxA
와 같이 Rust 문자열을 API에 직접 전달할 수 있도록 코드 페이지를 UTF-8로 설정합니다. 레지스트리에서 경로 이름을 구성하면 긴 경로 이름을 사용할 수 있으므로 현재 디렉토리가 매우 길어집니다.<?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>
Visual Studio 빌드 도구 방식
Windows에서 Visual Studio 빌드 도구를 사용하여 Windows용 프로그램만 컴파일하는 경우 빌드 스크립트를 사용하여 몇 가지 추가 인수를
LINK.EXE
에 전달하여 Windows 매니페스트를 추가할 수 있습니다.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");
}
이것은 what
rustc
does in release 1.63 입니다."맥주를 잡아라" 방식
MinGW 도구를 사용하여 컴파일하거나 크로스 컴파일하는 경우 인라인 어셈블리를 사용하여 매니페스트 리소스를 포함할 수 있습니다.
#![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>"#;
}
인라인 어셈블리는
.rsrc$01
라는 COFF 섹션으로 이동하고 매니페스트 문자열은 .rsrc$02
라는 섹션으로 이동합니다. 링커는 이를 실행 파일의 단일 .rsrc
섹션으로 결합하고 헤더의 .long MANIFEST@imgrel
는 매니페스트 문자열에 대한 재배치 가능한 참조로 변환됩니다.이 두 가지 접근 방식을 결합하여
msvc
, gnu
및 gnullvm
대상 환경에서 작업할 수 있습니다.쉬운 방법
자기 홍보 순간: MSVC 접근 방식을 사용하거나
.rsrc
섹션에 매니페스트 데이터가 포함된 개체 파일을 생성하고 그에 대한 링크를 생성하는 embed-manifest이라는 크레이트를 작성했습니다. 당신이 하고 있는 일: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");
}
외부 종속성이 없으므로 빌드 속도가 전혀 느려지지 않습니다.
Reference
이 문제에 관하여(Rust 프로그램에 Windows 매니페스트 포함), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/carey/embed-a-windows-manifest-in-your-rust-program-26j2텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)