//! 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. //! //! [1]: https://docs.microsoft.com/en-us/windows/win32/sbscs/application-manifests //! //! 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#" //! //! //! //! //! //! //! //! //! //! //! //! //! //! //! //! //! //! //! UTF-8 //! permonitorv2 //! true //! true //! //! //! //! //! //! //! //! //! //! "#.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, dependent_assemblies: Vec, compatibility: ApplicationCompatibility, windows_settings: WindowsSettings, requested_execution_level: Option, } 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. // // [identity]: https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests#assemblyIdentity 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]. /// /// [sxs]: https://docs.microsoft.com/en-us/windows/win32/sbscs/using-side-by-side-assemblies 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]. /// /// [xaml]: https://docs.microsoft.com/en-us/windows/apps/desktop/modernize/host-standard-control-with-xaml-islands-cpp 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>(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 `\\?\`. /// /// [1]: https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation /// [2]: https://github.com/rust-lang/rust/pull/89174 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]”. /// /// [post]: https://peteronprogramming.wordpress.com/2018/01/22/application-level-printer-driver-isolation/ 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]. /// /// [touchpad]: https://docs.microsoft.com/en-us/windows/win32/w8cookbook/windows-precision-touchpad-devices 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`. /// /// [installer]: https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/how-user-account-control-works#installer-detection-technology 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, processor_architecture: Option, version: Version, public_key_token: Option, } 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, supported_os: Vec, } 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] /// from the [Windows SDK archive](https://developer.microsoft.com/en-us/windows/downloads/sdk-archive/). #[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. /// /// [dpi]: https://docs.microsoft.com/en-us/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows #[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]. /// /// [edge]: https://blogs.windows.com/msedgedev/2020/06/17/improving-memory-usage/ 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]. /// /// [step6]: https://msdn.microsoft.com/en-us/library/bb756929.aspx #[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()) } }