Source code

Revision control

Copy as Markdown

Other Tools

//! A builder for Windows application manifest XML files.
//!
//! This module allows the construction of application manifests from code with the
//! [`ManifestBuilder`], for use from a Cargo build script. Once configured, the builder
//! should be passed to [`embed_manifest()`][crate::embed_manifest] to generate the
//! correct instructions for Cargo. For any other use, the builder will output the XML
//! when formatted for [`Display`], or with [`to_string()`][ToString]. For more
//! information about the different elements of an application manifest, see
//! [Application Manifests][1] in the Microsoft Windows App Development documentation.
//!
//!
//! To generate the manifest XML separately, the XML can be output with `write!` or
//! copied to a string with [`to_string()`][ToString]. To produce the manifest XML with
//! extra whitespace for formatting, format it with the ‘alternate’ flag:
//!
//! ```
//! # use embed_manifest::new_manifest;
//! let builder = new_manifest("Company.OrgUnit.Program");
//! assert_eq!(format!("{:#}", builder), r#"<?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">
//! <assemblyIdentity name="Company.OrgUnit.Program" type="win32" version="1.4.0.0"/>
//! <dependency>
//! <dependentAssembly>
//! <assemblyIdentity language="*" name="Microsoft.Windows.Common-Controls" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" type="win32" version="6.0.0.0"/>
//! </dependentAssembly>
//! </dependency>
//! <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
//! <application>
//! <maxversiontested Id="10.0.18362.1"/>
//! <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>
//! <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">permonitorv2</dpiAwareness>
//! <longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
//! <printerDriverIsolation xmlns="http://schemas.microsoft.com/SMI/2011/WindowsSettings">true</printerDriverIsolation>
//! </asmv3:windowsSettings>
//! </asmv3:application>
//! <asmv3:trustInfo>
//! <asmv3:security>
//! <asmv3:requestedPrivileges>
//! <asmv3:requestedExecutionLevel level="asInvoker" uiAccess="false"/>
//! </asmv3:requestedPrivileges>
//! </asmv3:security>
//! </asmv3:trustInfo>
//! </assembly>"#.replace("\n", "\r\n"))
//! ```
use std::fmt::{Display, Formatter};
use std::ops::RangeBounds;
use std::{env, fmt};
use crate::manifest::xml::XmlFormatter;
mod xml;
#[cfg(test)]
mod test;
/// An opaque container to describe the Windows application manifest for the
/// executable. A new instance with reasonable defaults is created with
/// [`new_manifest()`][crate::new_manifest].
#[derive(Debug)]
pub struct ManifestBuilder {
identity: Option<AssemblyIdentity>,
dependent_assemblies: Vec<AssemblyIdentity>,
compatibility: ApplicationCompatibility,
windows_settings: WindowsSettings,
requested_execution_level: Option<RequestedExecutionLevel>,
}
impl ManifestBuilder {
pub(crate) fn new(name: &str) -> Self {
ManifestBuilder {
identity: Some(AssemblyIdentity::application(name)),
dependent_assemblies: vec![AssemblyIdentity::new(
"Microsoft.Windows.Common-Controls",
[6, 0, 0, 0],
0x6595b64144ccf1df,
)],
compatibility: ApplicationCompatibility {
max_version_tested: Some(MaxVersionTested::Windows10Version1903),
supported_os: vec![
SupportedOS::Windows7,
SupportedOS::Windows8,
SupportedOS::Windows81,
SupportedOS::Windows10,
],
},
windows_settings: WindowsSettings::new(),
requested_execution_level: Some(RequestedExecutionLevel {
level: ExecutionLevel::AsInvoker,
ui_access: false,
}),
}
}
pub(crate) fn empty() -> Self {
ManifestBuilder {
identity: None,
dependent_assemblies: Vec::new(),
compatibility: ApplicationCompatibility {
max_version_tested: None,
supported_os: Vec::new(),
},
windows_settings: WindowsSettings::empty(),
requested_execution_level: None,
}
}
// Set the dot-separated [application name][identity] in the manifest.
//
pub fn name(mut self, name: &str) -> Self {
match self.identity {
Some(ref mut identity) => identity.name = name.to_string(),
None => self.identity = Some(AssemblyIdentity::application_version(name, 0, 0, 0, 0)),
}
self
}
/// Set the four-part application version number in the manifest.
pub fn version(mut self, major: u16, minor: u16, build: u16, revision: u16) -> Self {
match self.identity {
Some(ref mut identity) => identity.version = Version(major, minor, build, revision),
None => {
self.identity = Some(AssemblyIdentity::application_version("", major, minor, build, revision));
}
}
self
}
/// Add a dependency on a specific version of a side-by-side assembly
/// to the application manifest. For more information on side-by-side
/// assemblies, see [Using Side-by-side Assemblies][sxs].
///
pub fn dependency(mut self, identity: AssemblyIdentity) -> Self {
self.dependent_assemblies.push(identity);
self
}
/// Remove a dependency on a side-by-side assembly. This can be used to
/// remove the default dependency on Common Controls version 6:
///
/// ```
/// # use embed_manifest::new_manifest;
/// new_manifest("Company.OrgUnit.Program")
/// .remove_dependency("Microsoft.Windows.Common-Controls")
/// # ;
/// ```
pub fn remove_dependency(mut self, name: &str) -> Self {
self.dependent_assemblies.retain(|d| d.name != name);
self
}
/// Set the “maximum version tested” based on a Windows SDK version.
/// This compatibility setting enables the use of XAML Islands, as described in
/// [Host a standard WinRT XAML control in a C++ desktop (Win32) app][xaml].
///
pub fn max_version_tested(mut self, version: MaxVersionTested) -> Self {
self.compatibility.max_version_tested = Some(version);
self
}
/// Remove the “maximum version tested” from the application compatibility.
pub fn remove_max_version_tested(mut self) -> Self {
self.compatibility.max_version_tested = None;
self
}
/// Set the range of supported versions of Windows for application compatibility.
/// The default value declares compatibility with every version from
/// [Windows 7][SupportedOS::Windows7] to [Windows 10 and 11][SupportedOS::Windows10].
pub fn supported_os<R: RangeBounds<SupportedOS>>(mut self, os_range: R) -> Self {
use SupportedOS::*;
self.compatibility.supported_os.clear();
for os in [WindowsVista, Windows7, Windows8, Windows81, Windows10] {
if os_range.contains(&os) {
self.compatibility.supported_os.push(os);
}
}
self
}
/// Set the code page used for single-byte Windows API, starting from Windows 10
/// version 1903. The default setting of [UTF-8][`ActiveCodePage::Utf8`] makes Rust
/// strings work directly with APIs like `MessageBoxA`.
pub fn active_code_page(mut self, code_page: ActiveCodePage) -> Self {
self.windows_settings.active_code_page = code_page;
self
}
/// Configures how Windows should display this program on monitors where the
/// graphics need scaling, whether by the application drawing its user
/// interface at different sizes or by the Windows system rendering the graphics
/// to a bitmap then resizing that for display.
pub fn dpi_awareness(mut self, setting: DpiAwareness) -> Self {
self.windows_settings.dpi_awareness = setting;
self
}
/// Attempts to scale GDI primitives by the per-monitor scaling values,
/// from Windows 10 version 1703. It seems to be best to leave this disabled.
pub fn gdi_scaling(mut self, setting: Setting) -> Self {
self.windows_settings.gdi_scaling = setting.enabled();
self
}
/// Select the memory allocator use by the standard heap allocation APIs,
/// including the default Rust allocator. Selecting a different algorithm
/// may make performance and memory use better or worse, so any changes
/// should be carefully tested.
pub fn heap_type(mut self, setting: HeapType) -> Self {
self.windows_settings.heap_type = setting;
self
}
/// Enable paths longer than 260 characters with some wide-character Win32 APIs,
/// when also enabled in the Windows registry. For more details, see
/// [Maximum Path Length Limitation][1] in the Windows App Development
/// documentation.
///
/// As of Rust 1.58, the [Rust standard library bypasses this limitation][2] itself
/// by using Unicode paths beginning with `\\?\`.
///
pub fn long_path_aware(mut self, setting: Setting) -> Self {
self.windows_settings.long_path_aware = setting.enabled();
self
}
/// Enable printer driver isolation for the application, improving security and
/// stability when printing by loading the printer driver in a separate
/// application. This is poorly documented, but is described in a blog post,
/// “[Application-level Printer Driver Isolation][post]”.
///
pub fn printer_driver_isolation(mut self, setting: Setting) -> Self {
self.windows_settings.printer_driver_isolation = setting.enabled();
self
}
/// Configure whether the application should receive mouse wheel scroll events
/// with a minimum delta of 1, 40 or 120, as described in
/// [Windows precision touchpad devices][touchpad].
///
pub fn scrolling_awareness(mut self, setting: ScrollingAwareness) -> Self {
self.windows_settings.scrolling_awareness = setting;
self
}
/// Allows the application to disable the filtering that normally
/// removes UWP windows from the results of the `EnumWindows` API.
pub fn window_filtering(mut self, setting: Setting) -> Self {
self.windows_settings.disable_window_filtering = setting.disabled();
self
}
/// Selects the authorities to execute the program with, rather than
/// [guessing based on a filename][installer] like `setup.exe`,
/// `update.exe` or `patch.exe`.
///
pub fn requested_execution_level(mut self, level: ExecutionLevel) -> Self {
match self.requested_execution_level {
Some(ref mut requested_execution_level) => requested_execution_level.level = level,
None => self.requested_execution_level = Some(RequestedExecutionLevel { level, ui_access: false }),
}
self
}
/// Allows the application to access the user interface of applications
/// running with elevated permissions when this program does not, typically
/// for accessibility. The program must additionally be correctly signed
/// and installed in a trusted location like the Program Files directory.
pub fn ui_access(mut self, access: bool) -> Self {
match self.requested_execution_level {
Some(ref mut requested_execution_level) => requested_execution_level.ui_access = access,
None => {
self.requested_execution_level = Some(RequestedExecutionLevel {
level: ExecutionLevel::AsInvoker,
ui_access: access,
})
}
}
self
}
}
impl Display for ManifestBuilder {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
let mut w = XmlFormatter::new(f);
w.start_document()?;
let mut attrs = vec![("xmlns", "urn:schemas-microsoft-com:asm.v1")];
if !self.windows_settings.is_empty() || self.requested_execution_level.is_some() {
attrs.push(("xmlns:asmv3", "urn:schemas-microsoft-com:asm.v3"));
}
attrs.push(("manifestVersion", "1.0"));
w.start_element("assembly", &attrs)?;
if let Some(ref identity) = self.identity {
identity.xml_to(&mut w)?;
}
if !self.dependent_assemblies.is_empty() {
w.element("dependency", &[], |w| {
for d in self.dependent_assemblies.as_slice() {
w.element("dependentAssembly", &[], |w| d.xml_to(w))?;
}
Ok(())
})?;
}
if !self.compatibility.is_empty() {
self.compatibility.xml_to(&mut w)?;
}
if !self.windows_settings.is_empty() {
self.windows_settings.xml_to(&mut w)?;
}
if let Some(ref requested_execution_level) = self.requested_execution_level {
requested_execution_level.xml_to(&mut w)?;
}
w.end_element("assembly")
}
}
/// Identity of a side-by-side assembly dependency for the application.
#[derive(Debug)]
pub struct AssemblyIdentity {
r#type: AssemblyType,
name: String,
language: Option<String>,
processor_architecture: Option<AssemblyProcessorArchitecture>,
version: Version,
public_key_token: Option<PublicKeyToken>,
}
impl AssemblyIdentity {
fn application(name: &str) -> AssemblyIdentity {
let major = env::var("CARGO_PKG_VERSION_MAJOR").map_or(0, |s| s.parse().unwrap_or(0));
let minor = env::var("CARGO_PKG_VERSION_MINOR").map_or(0, |s| s.parse().unwrap_or(0));
let patch = env::var("CARGO_PKG_VERSION_PATCH").map_or(0, |s| s.parse().unwrap_or(0));
AssemblyIdentity {
r#type: AssemblyType::Win32,
name: name.to_string(),
language: None,
processor_architecture: None,
version: Version(major, minor, patch, 0),
public_key_token: None,
}
}
fn application_version(name: &str, major: u16, minor: u16, build: u16, revision: u16) -> AssemblyIdentity {
AssemblyIdentity {
r#type: AssemblyType::Win32,
name: name.to_string(),
language: None,
processor_architecture: None,
version: Version(major, minor, build, revision),
public_key_token: None,
}
}
/// Creates a new value for a [manifest dependency][ManifestBuilder::dependency],
/// with the `version` as an array of numbers like `[1, 0, 0, 0]` for 1.0.0.0,
/// and the public key token as a 64-bit number like `0x6595b64144ccf1df`.
pub fn new(name: &str, version: [u16; 4], public_key_token: u64) -> AssemblyIdentity {
AssemblyIdentity {
r#type: AssemblyType::Win32,
name: name.to_string(),
language: Some("*".to_string()),
processor_architecture: Some(AssemblyProcessorArchitecture::All),
version: Version(version[0], version[1], version[2], version[3]),
public_key_token: Some(PublicKeyToken(public_key_token)),
}
}
/// Change the language from `"*"` to the language code in `language`.
pub fn language(mut self, language: &str) -> Self {
self.language = Some(language.to_string());
self
}
/// Change the processor architecture from `"*"` to the architecture in `arch`.
pub fn processor_architecture(mut self, arch: AssemblyProcessorArchitecture) -> Self {
self.processor_architecture = Some(arch);
self
}
fn xml_to(&self, w: &mut XmlFormatter) -> fmt::Result {
let version = self.version.to_string();
let public_key_token = self.public_key_token.as_ref().map(|token| token.to_string());
let mut attrs: Vec<(&str, &str)> = Vec::with_capacity(6);
if let Some(ref language) = self.language {
attrs.push(("language", language));
}
attrs.push(("name", &self.name));
if let Some(ref arch) = self.processor_architecture {
attrs.push(("processorArchitecture", arch.as_str()))
}
if let Some(ref token) = public_key_token {
attrs.push(("publicKeyToken", token));
}
attrs.push(("type", self.r#type.as_str()));
attrs.push(("version", &version));
w.empty_element("assemblyIdentity", &attrs)
}
}
#[derive(Debug)]
struct Version(u16, u16, u16, u16);
impl fmt::Display for Version {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}.{}.{}.{}", self.0, self.1, self.2, self.3)
}
}
#[derive(Debug)]
struct PublicKeyToken(u64);
impl fmt::Display for PublicKeyToken {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{:016x}", self.0)
}
}
/// Processor architecture for an assembly identity.
#[derive(Debug)]
#[non_exhaustive]
pub enum AssemblyProcessorArchitecture {
/// Any processor architecture, as `"*"`.
All,
/// 32-bit x86 processors, as `"x86"`.
X86,
/// 64-bit x64 processors, as `"x64"`.
Amd64,
/// 32-bit ARM processors, as `"arm"`.
Arm,
/// 64-bit ARM processors, as `"arm64"`.
Arm64,
}
impl AssemblyProcessorArchitecture {
pub fn as_str(&self) -> &'static str {
match self {
Self::All => "*",
Self::X86 => "x86",
Self::Amd64 => "amd64",
Self::Arm => "arm",
Self::Arm64 => "arm64",
}
}
}
impl fmt::Display for AssemblyProcessorArchitecture {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.pad(self.as_str())
}
}
#[derive(Debug)]
#[non_exhaustive]
enum AssemblyType {
Win32,
}
impl AssemblyType {
fn as_str(&self) -> &'static str {
"win32"
}
}
#[derive(Debug)]
struct ApplicationCompatibility {
max_version_tested: Option<MaxVersionTested>,
supported_os: Vec<SupportedOS>,
}
impl ApplicationCompatibility {
fn is_empty(&self) -> bool {
self.supported_os.is_empty()
}
fn xml_to(&self, w: &mut XmlFormatter) -> fmt::Result {
w.element(
"compatibility",
&[("xmlns", "urn:schemas-microsoft-com:compatibility.v1")],
|w| {
w.element("application", &[], |w| {
if self.supported_os.contains(&SupportedOS::Windows10) {
if let Some(ref version) = self.max_version_tested {
w.empty_element("maxversiontested", &[("Id", version.as_str())])?;
}
}
for os in self.supported_os.iter() {
w.empty_element("supportedOS", &[("Id", os.as_str())])?
}
Ok(())
})
},
)
}
}
/// Windows build versions for [`max_version_tested()`][ManifestBuilder::max_version_tested]
#[derive(Debug)]
#[non_exhaustive]
pub enum MaxVersionTested {
/// Windows 10 version 1903, with build version 10.0.18362.0.
Windows10Version1903,
/// Windows 10 version 2004, with build version 10.0.19041.0.
Windows10Version2004,
/// Windows 10 version 2104, with build version 10.0.20348.0.
Windows10Version2104,
/// Windows 11, with build version 10.0.22000.194.
Windows11,
/// Windows 11 version 22H2, with build version 10.0.22621.1.
Windows11Version22H2,
}
impl MaxVersionTested {
/// Return the Windows version as a string.
pub fn as_str(&self) -> &'static str {
match self {
Self::Windows10Version1903 => "10.0.18362.1",
Self::Windows10Version2004 => "10.0.19041.0",
Self::Windows10Version2104 => "10.0.20348.0",
Self::Windows11 => "10.0.22000.194",
Self::Windows11Version22H2 => "10.0.22621.1",
}
}
}
impl Display for MaxVersionTested {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.pad(self.as_str())
}
}
/// Operating system versions for Windows compatibility.
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq)]
#[non_exhaustive]
pub enum SupportedOS {
/// Windows Vista and Windows Server 2008.
WindowsVista,
/// Windows 7 and Windows Server 2008 R2.
Windows7,
/// Windows 8 and Windows Server 2012.
Windows8,
/// Windows 8.1 and Windows Server 2012 R2.
Windows81,
/// Windows 10 and 11, and Windows Server 2016, 2019 and 2022.
Windows10,
}
impl SupportedOS {
/// Returns the GUID string for the Windows version.
pub fn as_str(&self) -> &'static str {
match self {
Self::WindowsVista => "{e2011457-1546-43c5-a5fe-008deee3d3f0}",
Self::Windows7 => "{35138b9a-5d96-4fbd-8e2d-a2440225f93a}",
Self::Windows8 => "{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}",
Self::Windows81 => "{1f676c76-80e1-4239-95bb-83d0f6d0da78}",
Self::Windows10 => "{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}",
}
}
}
impl Display for SupportedOS {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.pad(self.as_str())
}
}
static WS2005: (&str, &str) = ("xmlns", "http://schemas.microsoft.com/SMI/2005/WindowsSettings");
static WS2011: (&str, &str) = ("xmlns", "http://schemas.microsoft.com/SMI/2011/WindowsSettings");
static WS2013: (&str, &str) = ("xmlns", "http://schemas.microsoft.com/SMI/2013/WindowsSettings");
static WS2016: (&str, &str) = ("xmlns", "http://schemas.microsoft.com/SMI/2016/WindowsSettings");
static WS2017: (&str, &str) = ("xmlns", "http://schemas.microsoft.com/SMI/2017/WindowsSettings");
static WS2019: (&str, &str) = ("xmlns", "http://schemas.microsoft.com/SMI/2019/WindowsSettings");
static WS2020: (&str, &str) = ("xmlns", "http://schemas.microsoft.com/SMI/2020/WindowsSettings");
#[derive(Debug)]
struct WindowsSettings {
active_code_page: ActiveCodePage,
disable_window_filtering: bool,
dpi_awareness: DpiAwareness,
gdi_scaling: bool,
heap_type: HeapType,
long_path_aware: bool,
printer_driver_isolation: bool,
scrolling_awareness: ScrollingAwareness,
}
impl WindowsSettings {
fn new() -> Self {
Self {
active_code_page: ActiveCodePage::Utf8,
disable_window_filtering: false,
dpi_awareness: DpiAwareness::PerMonitorV2Only,
gdi_scaling: false,
heap_type: HeapType::LowFragmentationHeap,
long_path_aware: true,
printer_driver_isolation: true,
scrolling_awareness: ScrollingAwareness::UltraHighResolution,
}
}
fn empty() -> Self {
Self {
active_code_page: ActiveCodePage::System,
disable_window_filtering: false,
dpi_awareness: DpiAwareness::UnawareByDefault,
gdi_scaling: false,
heap_type: HeapType::LowFragmentationHeap,
long_path_aware: false,
printer_driver_isolation: false,
scrolling_awareness: ScrollingAwareness::UltraHighResolution,
}
}
fn is_empty(&self) -> bool {
matches!(
self,
Self {
active_code_page: ActiveCodePage::System,
disable_window_filtering: false,
dpi_awareness: DpiAwareness::UnawareByDefault,
gdi_scaling: false,
heap_type: HeapType::LowFragmentationHeap,
long_path_aware: false,
printer_driver_isolation: false,
scrolling_awareness: ScrollingAwareness::UltraHighResolution,
}
)
}
fn xml_to(&self, w: &mut XmlFormatter) -> fmt::Result {
w.element("asmv3:application", &[], |w| {
w.element("asmv3:windowsSettings", &[], |w| {
self.active_code_page.xml_to(w)?;
if self.disable_window_filtering {
w.element("disableWindowFiltering", &[WS2011], |w| w.text("true"))?;
}
self.dpi_awareness.xml_to(w)?;
if self.gdi_scaling {
w.element("gdiScaling", &[WS2017], |w| w.text("true"))?;
}
if matches!(self.heap_type, HeapType::SegmentHeap) {
w.element("heapType", &[WS2020], |w| w.text("SegmentHeap"))?;
}
if self.long_path_aware {
w.element("longPathAware", &[WS2016], |w| w.text("true"))?;
}
if self.printer_driver_isolation {
w.element("printerDriverIsolation", &[WS2011], |w| w.text("true"))?;
}
self.scrolling_awareness.xml_to(w)
})
})
}
}
/// Configure whether a Windows setting is enabled or disabled, avoiding confusion
/// over which of these options `true` and `false` represent.
#[derive(Debug)]
pub enum Setting {
Disabled = 0,
Enabled = 1,
}
impl Setting {
/// Returns `true` if the setting should be disabled.
fn disabled(&self) -> bool {
matches!(self, Setting::Disabled)
}
/// Returns `true` if the setting should be enabled.
fn enabled(&self) -> bool {
matches!(self, Setting::Enabled)
}
}
/// The code page used by single-byte APIs in the program.
#[derive(Debug)]
#[non_exhaustive]
pub enum ActiveCodePage {
/// Use the code page from the configured system locale, or UTF-8 if “Use Unicode UTF-8
/// for worldwide language support” is configured.
System,
/// Use UTF-8 from Windows 10 version 1903 and on Windows 11.
Utf8,
/// Use the code page from the configured system locale, even when “Use Unicode UTF-8
/// for worldwide language support” is configured.
Legacy,
/// Use the code page from the configured system locale on Windows 10, or from this
/// locale on Windows 11.
Locale(String),
}
impl ActiveCodePage {
pub fn as_str(&self) -> &str {
match self {
Self::System => "",
Self::Utf8 => "UTF-8",
Self::Legacy => "Legacy",
Self::Locale(s) => s,
}
}
fn xml_to(&self, w: &mut XmlFormatter) -> fmt::Result {
match self {
Self::System => Ok(()),
_ => w.element("activeCodePage", &[WS2019], |w| w.text(self.as_str())),
}
}
}
impl Display for ActiveCodePage {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.pad(self.as_str())
}
}
/// Options for how Windows will handle drawing on monitors when the graphics
/// need scaling to display at the correct size.
///
/// See [High DPI Desktop Application Development on Windows][dpi] for more details
/// about the impact of these options.
///
#[derive(Debug)]
#[non_exhaustive]
pub enum DpiAwareness {
/// DPI awareness is not configured, so Windows will scale the application unless
/// changed via the `SetProcessDpiAware` or `SetProcessDpiAwareness` API.
UnawareByDefault,
/// DPI awareness is not configured, with Windows 8.1, 10 and 11 not able
/// to change the setting via API.
Unaware,
/// The program uses the system DPI, or the DPI of the monitor they start on if
/// “Fix scaling for apps” is enabled. If the DPI does not match the current
/// monitor then Windows will scale the application.
System,
/// The program uses the system DPI on Windows Vista, 7 and 8, and version 1 of
/// per-monitor DPI awareness on Windows 8.1, 10 and 11. Using version 1 of the
/// API is not recommended.
PerMonitor,
/// The program uses the system DPI on Windows Vista, 7 and 8, version 1 of
/// per-monitor DPI awareness on Windows 8.1 and Windows 10 version 1507 and 1511,
/// and version 2 of per-monitor DPI awareness from Windows 10 version 1607.
PerMonitorV2,
/// The program uses the system DPI on Windows Vista, 7, 8, 8.1 and Windows 10
/// version 1507 and 1511, and version 2 of per-monitor DPI awareness from
/// Windows 10 version 1607.
PerMonitorV2Only,
}
impl DpiAwareness {
fn xml_to(&self, w: &mut XmlFormatter) -> fmt::Result {
let settings = match self {
Self::UnawareByDefault => (None, None),
Self::Unaware => (Some("false"), None),
Self::System => (Some("true"), None),
Self::PerMonitor => (Some("true/pm"), None),
Self::PerMonitorV2 => (Some("true/pm"), Some("permonitorv2,permonitor")),
Self::PerMonitorV2Only => (None, Some("permonitorv2")),
};
if let Some(dpi_aware) = settings.0 {
w.element("dpiAware", &[WS2005], |w| w.text(dpi_aware))?;
}
if let Some(dpi_awareness) = settings.1 {
w.element("dpiAwareness", &[WS2016], |w| w.text(dpi_awareness))?;
}
Ok(())
}
}
/// The heap type for the default memory allocator.
#[derive(Debug)]
#[non_exhaustive]
pub enum HeapType {
/// The default heap type since Windows Vista.
LowFragmentationHeap,
/// The modern segment heap, which may reduce total memory allocation in some programs.
/// This is supported since Windows 10 version 2004. See
/// [Improving Memory Usage in Microsoft Edge][edge].
///
SegmentHeap,
}
/// Whether the application supports scroll wheel events with a minimum delta
/// of 1, 40 or 120.
#[derive(Debug)]
#[non_exhaustive]
pub enum ScrollingAwareness {
/// The application can only handle scroll wheel events with the original delta of 120.
LowResolution,
/// The application can handle high precision scroll wheel events with a delta of 40.
HighResolution,
/// The application can handle ultra high precision scroll wheel events with a delta as low as 1.
UltraHighResolution,
}
impl ScrollingAwareness {
fn xml_to(&self, w: &mut XmlFormatter) -> fmt::Result {
match self {
Self::LowResolution => w.element("ultraHighResolutionScrollingAware", &[WS2013], |w| w.text("false")),
Self::HighResolution => w.element("highResolutionScrollingAware", &[WS2013], |w| w.text("true")),
Self::UltraHighResolution => Ok(()),
}
}
}
#[derive(Debug)]
struct RequestedExecutionLevel {
level: ExecutionLevel,
ui_access: bool,
}
impl RequestedExecutionLevel {
fn xml_to(&self, w: &mut XmlFormatter) -> fmt::Result {
w.element("asmv3:trustInfo", &[], |w| {
w.element("asmv3:security", &[], |w| {
w.element("asmv3:requestedPrivileges", &[], |w| {
w.empty_element(
"asmv3:requestedExecutionLevel",
&[
("level", self.level.as_str()),
("uiAccess", if self.ui_access { "true" } else { "false" }),
],
)
})
})
})
}
}
/// The requested execution level for the application when started.
///
/// The behaviour of each option is described in
/// [Designing UAC Applications for Windows Vista Step 6: Create and Embed an Application Manifest][step6].
///
#[derive(Debug)]
pub enum ExecutionLevel {
/// The application will always run with the same authorities as the program invoking it.
AsInvoker,
/// The program will run without special authorities for a standard user, but will try to
/// run with administrator authority if the user is an administrator. This is rarely used.
HighestAvailable,
/// The application will run as an administrator, prompting for elevation if necessary.
RequireAdministrator,
}
impl ExecutionLevel {
pub fn as_str(&self) -> &'static str {
match self {
Self::AsInvoker => "asInvoker",
Self::HighestAvailable => "highestAvailable",
Self::RequireAdministrator => "requireAdministrator",
}
}
}
impl Display for ExecutionLevel {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.pad(self.as_str())
}
}