diff --git a/Cargo.lock b/Cargo.lock index aea6d723e8..1e80a494ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9867,6 +9867,18 @@ dependencies = [ "serde", ] +[[package]] +name = "toml" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.19.15", +] + [[package]] name = "toml" version = "0.8.10" @@ -9895,6 +9907,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap 2.0.0", + "serde", + "serde_spanned", "toml_datetime", "winnow 0.5.15", ] @@ -12030,6 +12044,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "winresource" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e2aaaf8cfa92078c0c0375423d631f82f2f57979c2884fdd5f604a11e45329" +dependencies = [ + "toml 0.7.8", + "version_check", +] + [[package]] name = "winx" version = "0.36.3" @@ -12584,6 +12608,7 @@ dependencies = [ "uuid", "vim", "welcome", + "winresource", "workspace", "zed_actions", ] diff --git a/Cargo.toml b/Cargo.toml index 1678c3e21f..9da214d4e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -356,6 +356,7 @@ features = [ "Win32_Security", "Win32_Security_Credentials", "Win32_Storage_FileSystem", + "Win32_System_LibraryLoader", "Win32_System_Com", "Win32_System_Com_StructuredStorage", "Win32_System_DataExchange", diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index 18b3fae844..472bfee12c 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -30,6 +30,7 @@ use windows::{ Graphics::Gdi::*, Media::*, Security::Credentials::*, + Storage::FileSystem::*, System::{Com::*, LibraryLoader::*, Ole::*, SystemInformation::*, Threading::*, Time::*}, UI::{Input::KeyboardAndMouse::*, Shell::*, WindowsAndMessaging::*}, }, @@ -520,11 +521,97 @@ impl Platform for WindowsPlatform { } fn app_version(&self) -> Result { - Ok(SemanticVersion { - major: 1, - minor: 0, - patch: 0, - }) + let mut file_name_buffer = vec![0u16; MAX_PATH as usize]; + let file_name = { + let mut file_name_buffer_capacity = MAX_PATH as usize; + let mut file_name_length; + loop { + file_name_length = + unsafe { GetModuleFileNameW(None, &mut file_name_buffer) } as usize; + if file_name_length < file_name_buffer_capacity { + break; + } + // buffer too small + file_name_buffer_capacity *= 2; + file_name_buffer = vec![0u16; file_name_buffer_capacity]; + } + PCWSTR::from_raw(file_name_buffer[0..(file_name_length + 1)].as_ptr()) + }; + + let version_info_block = { + let mut version_handle = 0; + let version_info_size = + unsafe { GetFileVersionInfoSizeW(file_name, Some(&mut version_handle)) } as usize; + if version_info_size == 0 { + log::error!( + "unable to get version info size: {}", + std::io::Error::last_os_error() + ); + return Err(anyhow!("unable to get version info size")); + } + let mut version_data = vec![0u8; version_info_size + 2]; + unsafe { + GetFileVersionInfoW( + file_name, + version_handle, + version_info_size as u32, + version_data.as_mut_ptr() as _, + ) + } + .inspect_err(|_| { + log::error!( + "unable to retrieve version info: {}", + std::io::Error::last_os_error() + ) + })?; + version_data + }; + + let version_info_raw = { + let mut buffer = unsafe { std::mem::zeroed() }; + let mut size = 0; + let entry = "\\".encode_utf16().chain(Some(0)).collect_vec(); + if !unsafe { + VerQueryValueW( + version_info_block.as_ptr() as _, + PCWSTR::from_raw(entry.as_ptr()), + &mut buffer, + &mut size, + ) + } + .as_bool() + { + log::error!( + "unable to query version info data: {}", + std::io::Error::last_os_error() + ); + return Err(anyhow!("the specified resource is not valid")); + } + if size == 0 { + log::error!( + "unable to query version info data: {}", + std::io::Error::last_os_error() + ); + return Err(anyhow!("no value is available for the specified name")); + } + buffer + }; + + let version_info = unsafe { &*(version_info_raw as *mut VS_FIXEDFILEINFO) }; + // https://learn.microsoft.com/en-us/windows/win32/api/verrsrc/ns-verrsrc-vs_fixedfileinfo + if version_info.dwSignature == 0xFEEF04BD { + return Ok(SemanticVersion { + major: ((version_info.dwProductVersionMS >> 16) & 0xFFFF) as usize, + minor: (version_info.dwProductVersionMS & 0xFFFF) as usize, + patch: ((version_info.dwProductVersionLS >> 16) & 0xFFFF) as usize, + }); + } else { + log::error!( + "no version info present: {}", + std::io::Error::last_os_error() + ); + return Err(anyhow!("no version info present")); + } } // todo(windows) diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 21c3b8dd99..328e984c61 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -89,6 +89,9 @@ welcome.workspace = true workspace.workspace = true zed_actions.workspace = true +[target.'cfg(target_os = "windows")'.build-dependencies] +winresource = "0.1" + [dev-dependencies] call = { workspace = true, features = ["test-support"] } editor = { workspace = true, features = ["test-support"] } diff --git a/crates/zed/build.rs b/crates/zed/build.rs index d05237f294..c40c15737d 100644 --- a/crates/zed/build.rs +++ b/crates/zed/build.rs @@ -44,7 +44,8 @@ fn main() { } } - if std::env::var("CARGO_CFG_TARGET_ENV").ok() == Some("msvc".to_string()) { + #[cfg(target_os = "windows")] + { // todo(windows): This is to avoid stack overflow. Remove it when solved. println!("cargo:rustc-link-arg=/stack:{}", 8 * 1024 * 1024); @@ -56,5 +57,11 @@ fn main() { "cargo:rustc-link-arg-bins=/MANIFESTINPUT:{}", manifest.canonicalize().unwrap().display() ); + + let res = winresource::WindowsResource::new(); + if let Err(e) = res.compile() { + eprintln!("{}", e); + std::process::exit(1); + } } }