From 0c162b8913df8d28699e1be7b887d5955e61e2bc Mon Sep 17 00:00:00 2001 From: Xuanwo Date: Thu, 25 Jul 2024 21:23:19 +0800 Subject: [PATCH] refactor: Use windows instead of winapi Signed-off-by: Xuanwo --- Cargo.lock | 127 +++++++++++++++++++++++++++++++++---------- Cargo.toml | 17 +++--- src/commands.rs | 49 ++++++++--------- src/compiler/msvc.rs | 127 +++++++++++++++++++++++++++++-------------- src/util.rs | 50 ++++++++++------- 5 files changed, 244 insertions(+), 126 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fc255b955..2ba89aeaa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -381,7 +381,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.0", + "windows-targets 0.52.6", ] [[package]] @@ -1252,7 +1252,7 @@ dependencies = [ "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core", + "windows-core 0.52.0", ] [[package]] @@ -2605,7 +2605,7 @@ dependencies = [ "version-compare", "walkdir", "which", - "winapi", + "windows", "zip", "zstd", ] @@ -3732,13 +3732,77 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core 0.58.0", + "windows-targets 0.52.6", +] + [[package]] name = "windows-core" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", ] [[package]] @@ -3756,7 +3820,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.6", ] [[package]] @@ -3776,17 +3840,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -3797,9 +3862,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -3809,9 +3874,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -3821,9 +3886,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -3833,9 +3904,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -3845,9 +3916,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -3857,9 +3928,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -3869,9 +3940,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" diff --git a/Cargo.toml b/Cargo.toml index 47f1090ab..86fe42a74 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -140,16 +140,17 @@ daemonize = "0.5" optional = true version = "0.1.15" -[target.'cfg(windows)'.dependencies.winapi] +[target.'cfg(windows)'.dependencies.windows] features = [ - "fileapi", - "handleapi", - "stringapiset", - "winnls", - "processenv", - "std", + "Win32_System_SystemServices", + "Win32_Foundation", + "Win32_Globalization", + "Win32_Storage_FileSystem", + "Win32_System_WindowsProgramming", + "Win32_System_Threading", + "Win32_System_Console", ] -version = "0.3" +version = "0.58" [features] all = [ diff --git a/src/commands.rs b/src/commands.rs index ab740582e..652b9a9fd 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -133,8 +133,8 @@ fn redirect_stderr(f: File) { #[cfg(windows)] fn redirect_stderr(f: File) { use std::os::windows::io::IntoRawHandle; - use winapi::um::processenv::SetStdHandle; - use winapi::um::winbase::STD_ERROR_HANDLE; + use windows::Win32::System::Console::{SetStdHandle, STD_ERROR_HANDLE}; + // Ignore errors here. unsafe { SetStdHandle(STD_ERROR_HANDLE, f.into_raw_handle()); @@ -176,11 +176,10 @@ fn run_server_process(startup_timeout: Option) -> Result) -> Result() as DWORD; - if unsafe { + let mut pi = PROCESS_INFORMATION::default(); + let mut si = STARTUPINFOW::default(); + si.cb = mem::size_of::() as u32; + let result = unsafe { CreateProcessW( - exe.as_mut_ptr(), - ptr::null_mut(), - ptr::null_mut(), - ptr::null_mut(), - FALSE, + windows::core::PCWSTR(exe.as_mut_ptr()), + windows::core::PWSTR::null(), + None, + None, + BOOL::from(false), CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW, - envp.as_mut_ptr() as LPVOID, - workdir.as_ptr(), + Some(envp.as_mut_ptr() as *mut _), + windows::core::PCWSTR(workdir.as_ptr()), &mut si, &mut pi, - ) == TRUE - } { + ) + }; + if result.as_bool() { unsafe { - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); + CloseHandle(HANDLE(pi.hProcess)); + CloseHandle(HANDLE(pi.hThread)); } } else { return Err(io::Error::last_os_error().into()); diff --git a/src/compiler/msvc.rs b/src/compiler/msvc.rs index 4ec7bf155..f402e76a7 100644 --- a/src/compiler/msvc.rs +++ b/src/compiler/msvc.rs @@ -112,8 +112,14 @@ fn from_local_codepage(multi_byte_str: &[u8]) -> io::Result { #[cfg(windows)] pub fn from_local_codepage(multi_byte_str: &[u8]) -> io::Result { - let codepage = winapi::um::winnls::CP_OEMCP; - let flags = winapi::um::winnls::MB_ERR_INVALID_CHARS; + use windows::{ + core::PWSTR, + Win32::Globalization::{GetACP, GetOEMCP, WideCharToMultiByte}, + Win32::System::SystemServices::{CP_ACP, CP_OEMCP}, + }; + + let codepage = unsafe { CP_OEMCP }; + let flags = 0; // Empty string if multi_byte_str.is_empty() { @@ -121,33 +127,38 @@ pub fn from_local_codepage(multi_byte_str: &[u8]) -> io::Result { } unsafe { // Get length of UTF-16 string - let len = winapi::um::stringapiset::MultiByteToWideChar( + let len = WideCharToMultiByte( codepage, flags, - multi_byte_str.as_ptr() as _, - multi_byte_str.len() as i32, - std::ptr::null_mut(), + PWSTR(wide_char_str.as_ptr() as _), + wide_char_str.len() as i32, + None, 0, + None, + None, ); if len > 0 { // Convert to UTF-16 - let mut wstr: Vec = Vec::with_capacity(len as usize); - let len = winapi::um::stringapiset::MultiByteToWideChar( + let mut wstr: Vec = vec![0u8; len as usize]; + let len = WideCharToMultiByte( codepage, flags, - multi_byte_str.as_ptr() as _, - multi_byte_str.len() as i32, - wstr.as_mut_ptr() as _, + PWSTR(wide_char_str.as_ptr() as _), + wide_char_str.len() as i32, + Some(buffer.as_mut_slice()), len, + None, + None, ); - if len > 0 { - // wstr's contents have now been initialized - wstr.set_len(len as usize); - return String::from_utf16(&wstr[0..(len as usize)]) - .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e)); + if result > 0 { + buffer.truncate(result as usize); + Ok(buffer) + } else { + Err(std::io::Error::last_os_error()) } + } else { + Err(io::Error::last_os_error()) } - Err(io::Error::last_os_error()) } } @@ -829,32 +840,64 @@ pub fn parse_arguments( #[cfg(windows)] fn normpath(path: &str) -> String { - use std::os::windows::ffi::OsStringExt; - use std::os::windows::io::AsRawHandle; - use std::ptr; - use winapi::um::fileapi::GetFinalPathNameByHandleW; - File::open(path) - .and_then(|f| { - let handle = f.as_raw_handle(); - let size = unsafe { GetFinalPathNameByHandleW(handle, ptr::null_mut(), 0, 0) }; - if size == 0 { - return Err(io::Error::last_os_error()); + use windows::{ + core::PWSTR, + Win32::Foundation::HANDLE, + Win32::Storage::FileSystem::{ + CreateFileW, GetFinalPathNameByHandleW, FILE_GENERIC_READ, FILE_SHARE_READ, + OPEN_EXISTING, + }, + Win32::System::WindowsProgramming::FILE_NAME_NORMALIZED, + }; + + let path_wide: Vec = Path::new(path) + .as_os_str() + .encode_wide() + .chain(Some(0)) + .collect(); + + unsafe { + let handle = CreateFileW( + PWSTR(path_wide.as_ptr() as _), + FILE_GENERIC_READ, + FILE_SHARE_READ, + None, + OPEN_EXISTING, + 0, + HANDLE::default(), + ); + + if handle.is_invalid() { + return path.replace('\\', "/"); + } + + let mut buffer = vec![0u16; 260]; // MAX_PATH + let mut size = buffer.len() as u32; + + loop { + let result = GetFinalPathNameByHandleW( + handle, + PWSTR(buffer.as_mut_ptr()), + size, + FILE_NAME_NORMALIZED.0, + ); + + if result == 0 { + return path.replace('\\', "/"); } - let mut wchars = vec![0; size as usize]; - if unsafe { - GetFinalPathNameByHandleW(handle, wchars.as_mut_ptr(), wchars.len() as u32, 0) - } == 0 - { - return Err(io::Error::last_os_error()); + + if result < size { + buffer.truncate(result as usize); + break; } - // The return value of GetFinalPathNameByHandleW uses the - // '\\?\' prefix. - let o = OsString::from_wide(&wchars[4..wchars.len() - 1]); - o.into_string() - .map(|s| s.replace('\\', "/")) - .map_err(|_| io::Error::new(io::ErrorKind::Other, "Error converting string")) - }) - .unwrap_or_else(|_| path.replace('\\', "/")) + + size = result + 1; + buffer.resize(size as usize, 0); + } + + String::from_utf16_lossy(&buffer[4..]) // Remove '\\?\' prefix + .replace('\\', "/") + } } #[cfg(not(windows))] @@ -2582,7 +2625,7 @@ mod test { #[cfg(windows)] fn local_oem_codepage_conversions() { use crate::util::wide_char_to_multi_byte; - use winapi::um::winnls::GetOEMCP; + use windows::Win32::Globalization::GetOEMCP; let current_oemcp = unsafe { GetOEMCP() }; // We don't control the local OEM codepage so test only if it is one of: diff --git a/src/util.rs b/src/util.rs index 4fc45af2e..b6f652367 100644 --- a/src/util.rs +++ b/src/util.rs @@ -636,15 +636,20 @@ pub fn decode_path(bytes: &[u8]) -> std::io::Result { #[cfg(windows)] pub fn decode_path(bytes: &[u8]) -> std::io::Result { - let codepage = winapi::um::winnls::CP_OEMCP; - let flags = winapi::um::winnls::MB_ERR_INVALID_CHARS; + use windows::Win32::Globalization::{CP_OEMCP, MB_ERR_INVALID_CHARS}; + + let codepage = CP_OEMCP; + let flags = MB_ERR_INVALID_CHARS; Ok(OsString::from_wide(&multi_byte_to_wide_char(codepage, flags, bytes)?).into()) } #[cfg(windows)] pub fn wide_char_to_multi_byte(wide_char_str: &[u16]) -> std::io::Result> { - let codepage = winapi::um::winnls::CP_OEMCP; + use windows::core::PCWSTR; + use windows::Win32::Globalization::{WideCharToMultiByte, CP_OEMCP}; + + let codepage = CP_OEMCP; let flags = 0; // Empty string if wide_char_str.is_empty() { @@ -652,29 +657,29 @@ pub fn wide_char_to_multi_byte(wide_char_str: &[u16]) -> std::io::Result } unsafe { // Get length of multibyte string - let len = winapi::um::stringapiset::WideCharToMultiByte( + let len = WideCharToMultiByte( codepage, flags, - wide_char_str.as_ptr(), + PCWSTR(wide_char_str.as_ptr()), wide_char_str.len() as i32, - std::ptr::null_mut(), + None, 0, - std::ptr::null(), - std::ptr::null_mut(), + None, + None, ); if len > 0 { // Convert from UTF-16 to multibyte let mut astr: Vec = Vec::with_capacity(len as usize); - let len = winapi::um::stringapiset::WideCharToMultiByte( + let len = WideCharToMultiByte( codepage, flags, - wide_char_str.as_ptr(), + PCWSTR(wide_char_str.as_ptr()), wide_char_str.len() as i32, - astr.as_mut_ptr() as _, + Some(astr.as_mut_ptr() as _), len, - std::ptr::null(), - std::ptr::null_mut(), + None, + None, ); if len > 0 { astr.set_len(len as usize); @@ -695,32 +700,35 @@ pub fn wide_char_to_multi_byte(wide_char_str: &[u16]) -> std::io::Result /// See https://msdn.microsoft.com/en-us/library/windows/desktop/dd319072(v=vs.85).aspx /// for more details. pub fn multi_byte_to_wide_char( - codepage: winapi::shared::minwindef::DWORD, - flags: winapi::shared::minwindef::DWORD, + codepage: u32, + flags: u32, multi_byte_str: &[u8], ) -> std::io::Result> { + use windows::core::PCSTR; + use windows::Win32::Globalization::MultiByteToWideChar; + if multi_byte_str.is_empty() { return Ok(vec![]); } unsafe { // Get length of UTF-16 string - let len = winapi::um::stringapiset::MultiByteToWideChar( + let len = MultiByteToWideChar( codepage, flags, - multi_byte_str.as_ptr() as winapi::um::winnt::LPSTR, + PCSTR(multi_byte_str.as_ptr()), multi_byte_str.len() as i32, - std::ptr::null_mut(), + None, 0, ); if len > 0 { // Convert to UTF-16 let mut wstr: Vec = Vec::with_capacity(len as usize); - let len = winapi::um::stringapiset::MultiByteToWideChar( + let len = MultiByteToWideChar( codepage, flags, - multi_byte_str.as_ptr() as winapi::um::winnt::LPSTR, + PCSTR(multi_byte_str.as_ptr()), multi_byte_str.len() as i32, - wstr.as_mut_ptr(), + Some(wstr.as_mut_ptr()), len, ); wstr.set_len(len as usize);