mirror of
https://github.com/astral-sh/uv
synced 2026-01-21 05:20:09 -05:00
Broadcast WM_SETTINGCHANGE on uv tool update-shell (#17404)
## Summary Closes https://github.com/astral-sh/uv/issues/17331 Certain applications on windows expect to be notified when environment variables change such as conhost.exe (traditional cmd.exe host). Without this notification conhost.exe will not pick up changes to environment variables regardless of how many times conhost.exe is re-launched after running `uv tool update-shell`. ## Test Plan Before this change 1. Removed `%USERPROFILE%\.local\bin` from environment variables via UI (which sends `WM_SETTINGCHANGE`) 2. Launched `%SYSTEMROOT%\System32\conhost.exe` and attempted to run any tool preivously installed. It fails to find any. 3. Ran `uv tool update-shell`. Confirmed `HKEY_CURRENT_USER\Environment\Path` was updated in registry. 4. Launched new `%SYSTEMROOT%\System32\conhost.exe` session. **Fails to find installed tools**. After this change 1. Removed `%USERPROFILE%\.local\bin` from environment variables via UI (which sends `WM_SETTINGCHANGE`) 2. Launched `%SYSTEMROOT%\System32\conhost.exe` and attempted to run any tool preivously installed. It fails to find any. 3. Ran `uv tool update-shell`. Confirmed `HKEY_CURRENT_USER\Environment\Path` was updated in registry. 4. Launched new `%SYSTEMROOT%\System32\conhost.exe` session. **Finds the installed tools**.
This commit is contained in:
@@ -196,7 +196,7 @@ uuid = { version = "1.16.0" }
|
||||
version-ranges = { version = "0.1.3", package = "astral-version-ranges" }
|
||||
walkdir = { version = "2.5.0" }
|
||||
which = { version = "8.0.0", features = ["regex"] }
|
||||
windows = { version = "0.59.0", features = ["std", "Win32_Globalization", "Win32_System_LibraryLoader", "Win32_System_Console", "Win32_System_Kernel", "Win32_System_Diagnostics_Debug", "Win32_Storage_FileSystem", "Win32_Security", "Win32_System_Registry", "Win32_System_IO", "Win32_System_Ioctl"] }
|
||||
windows = { version = "0.59.0", features = ["std", "Win32_Globalization", "Win32_Security", "Win32_Storage_FileSystem", "Win32_System_Console", "Win32_System_Diagnostics_Debug", "Win32_System_IO", "Win32_System_Ioctl", "Win32_System_Kernel", "Win32_System_LibraryLoader", "Win32_System_Registry", "Win32_UI_WindowsAndMessaging"] }
|
||||
windows-registry = { version = "0.5.0" }
|
||||
wiremock = { version = "0.6.4" }
|
||||
wmi = { version = "0.16.0", default-features = false }
|
||||
|
||||
@@ -8,8 +8,11 @@ use std::path::Path;
|
||||
|
||||
use anyhow::Context;
|
||||
use tracing::warn;
|
||||
use windows::Win32::Foundation::{ERROR_FILE_NOT_FOUND, ERROR_INVALID_DATA};
|
||||
use windows::core::HRESULT;
|
||||
use windows::Win32::Foundation::{ERROR_FILE_NOT_FOUND, ERROR_INVALID_DATA, LPARAM, WPARAM};
|
||||
use windows::Win32::UI::WindowsAndMessaging::{
|
||||
HWND_BROADCAST, SMTO_ABORTIFHUNG, SendMessageTimeoutW, WM_SETTINGCHANGE,
|
||||
};
|
||||
use windows::core::{HRESULT, w};
|
||||
use windows_registry::{CURRENT_USER, HSTRING};
|
||||
|
||||
use uv_static::EnvVars;
|
||||
@@ -46,9 +49,35 @@ fn apply_windows_path_var(path: &HSTRING) -> anyhow::Result<()> {
|
||||
environment.set_expand_hstring(EnvVars::PATH, path)?;
|
||||
}
|
||||
|
||||
// Notify WM_SETTINGCHANGE listeners
|
||||
broadcast_environment_changes();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Broadcast `WM_SETTINGCHANGE` to notify listeners about environment changes.
|
||||
///
|
||||
/// SAFETY: `SendMessageTimeoutW` is safe to call with these set of parameters.
|
||||
/// When modifying environment variables we need to broadcast a `WM_SETTINGCHANGE`
|
||||
/// message with lparam set to the string "Environment" to allow processes such
|
||||
/// as conhost.exe to pick up the changes made on new sessions.
|
||||
///
|
||||
/// See <https://learn.microsoft.com/en-us/windows/win32/procthread/environment-variables>
|
||||
#[allow(unsafe_code)]
|
||||
fn broadcast_environment_changes() {
|
||||
unsafe {
|
||||
SendMessageTimeoutW(
|
||||
HWND_BROADCAST,
|
||||
WM_SETTINGCHANGE,
|
||||
WPARAM(0),
|
||||
LPARAM(w!("Environment").as_ptr() as isize), // null terminated
|
||||
SMTO_ABORTIFHUNG,
|
||||
5000,
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieve the windows `PATH` variable from the registry.
|
||||
///
|
||||
/// Returns `Ok(None)` if the `PATH` variable is not a string.
|
||||
|
||||
Reference in New Issue
Block a user