From 0b3a34acd4a1a94a9004743e8e007fd8b7bfb90c Mon Sep 17 00:00:00 2001 From: Toby Fleming Date: Sat, 26 Jul 2025 12:19:42 -0700 Subject: [PATCH] Use OutputDebugStringW by default --- CHANGELOG.md | 1 + crates/export-check/src/main.rs | 6 ++-- crates/zipfixup/build.rs | 1 + crates/zipfixup/src/dbg.rs | 55 ++++++++++++++++++++------------- 4 files changed, 39 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0042af6..70fb773 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - Fixup: Specify exports via [Module-Definition (.Def) file](https://learn.microsoft.com/en-us/cpp/build/reference/module-definition-dot-def-files). - Fixup: Now builds using either `i686-pc-windows-gnu` or `i686-pc-windows-msvc`. +- Fixup: `output!` macro uses Unicode/`OutputDebugStringW` by default. - Project: Update Rust version to 1.88.0 and edition to 2024. This moves off nightly, since everything we need is now stabilised, and should help with diff --git a/crates/export-check/src/main.rs b/crates/export-check/src/main.rs index 538337d..c8604fc 100644 --- a/crates/export-check/src/main.rs +++ b/crates/export-check/src/main.rs @@ -8,7 +8,7 @@ fn main() -> Result<(), Box> { let (expected_exports, expected_forwards) = parse_def_file()?; for path in std::env::args().skip(1) { - println!("=== {} ===", path); + println!("=== {path} ==="); let contents = std::fs::read(path)?; let data = contents.as_slice(); @@ -115,11 +115,11 @@ fn validate_exports( exports.sort(); forwards.sort(); - for name in exports.iter().copied() { + for name in exports { println!("{name}"); } - for forward in forwards.iter().copied() { + for forward in forwards { println!("{forward}"); } diff --git a/crates/zipfixup/build.rs b/crates/zipfixup/build.rs index 55c1fa4..d02acc3 100644 --- a/crates/zipfixup/build.rs +++ b/crates/zipfixup/build.rs @@ -10,6 +10,7 @@ fn main() { println!("cargo::warning={path}"); println!("cargo::rerun-if-changed={path}"); + #[allow(clippy::wildcard_in_or_patterns)] match env.as_str() { "gnu" => { println!("cargo::rustc-link-arg-cdylib={path}"); diff --git a/crates/zipfixup/src/dbg.rs b/crates/zipfixup/src/dbg.rs index b578f02..d1d4d8b 100644 --- a/crates/zipfixup/src/dbg.rs +++ b/crates/zipfixup/src/dbg.rs @@ -1,7 +1,18 @@ use ::winapi::um::debugapi::{OutputDebugStringA, OutputDebugStringW}; -#[expect(dead_code, reason = "test me!")] -pub(crate) fn encode_unicode(msg: &str) { +/// Output a Unicode debug string. +/// +/// OutputDebugStringW is... weird/standard Microsoft: +/// > `OutputDebugStringW` converts the specified string based on the current +/// > system locale information and passes it to `OutputDebugStringA` to be +/// > displayed. As a result, some Unicode characters may not be displayed +/// > correctly. +/// +/// See . +/// +/// Although you shouldn't log a lot of stuff, if you need to, the ASCII +/// version may be slightly faster. +pub(crate) fn output_debug_string_w(msg: &str) { let now = time::OffsetDateTime::now_utc(); let s = format!( "[ZF {:04}-{:02}-{:02}T{:02}:{:02}:{:02}.{:03}Z] {msg}\0", @@ -16,19 +27,27 @@ pub(crate) fn encode_unicode(msg: &str) { let v: Vec = s.encode_utf16().collect(); let p: *const u16 = v.as_ptr(); - // OutputDebugStringW is... weird/standard Microsoft: - // > `OutputDebugStringW` converts the specified string based on the current - // > system locale information and passes it to `OutputDebugStringA` to be - // > displayed. As a result, some Unicode characters may not be displayed - // > correctly. - // https://learn.microsoft.com/en-us/windows/win32/api/debugapi/nf-debugapi-outputdebugstringw - // Therefore, we may be better off just using OutputDebugStringA... unsafe { OutputDebugStringW(p) }; // paranoia: ensure `v` is valid until after `OutputDebugStringW` drop(v); } -pub(crate) fn encode_ascii(msg: &str) { +fn encode_ascii(s: &str) -> Vec { + s.chars() + .map(|c| { + let b = if c.is_ascii() { c as u8 } else { b'?' }; + b as i8 + }) + .collect() +} + +/// Output an ASCII debug string. +/// +/// Non-ASCII characters are replaced by `?`. This version may be slightly +/// faster than the Unicode version, as it avoids extra translation (due to +/// Microsoft Unicode ineptness). +#[allow(dead_code, reason = "Use Unicode version by default")] +pub(crate) fn output_debug_string_a(msg: &str) { let now = time::OffsetDateTime::now_utc(); let s = format!( "[ZF {:04}-{:02}-{:02}T{:02}:{:02}:{:02}.{:03}Z] {msg}\0", @@ -41,13 +60,7 @@ pub(crate) fn encode_ascii(msg: &str) { now.millisecond(), ); - let v: Vec = s - .chars() - .map(|c| { - let b = if c.is_ascii() { c as u8 } else { b'?' }; - b as i8 - }) - .collect(); + let v: Vec = encode_ascii(&s); let p: *const i8 = v.as_ptr(); unsafe { OutputDebugStringA(p) }; // paranoia: ensure `s` is valid until after `OutputDebugStringA` @@ -55,13 +68,13 @@ pub(crate) fn encode_ascii(msg: &str) { } macro_rules! output { - ($fmt:literal $(, $args:expr)* $(,)?) => {{ + (a $fmt:literal $(, $args:expr)* $(,)?) => {{ let msg: String = format!($fmt $(, $args)*); - $crate::dbg::encode_ascii(&msg); + $crate::dbg::output_debug_string_a(&msg); }}; - (u $fmt:literal $(, $args:expr)* $(,)?) => {{ + ($fmt:literal $(, $args:expr)* $(,)?) => {{ let msg: String = format!($fmt $(, $args)*); - $crate::dbg::encode_unicode(&msg); + $crate::dbg::output_debug_string_w(&msg); }}; } pub(crate) use output;