Skip to content

Instantly share code, notes, and snippets.

@amoeba
Created September 9, 2025 00:48
Show Gist options
  • Save amoeba/b523c9d2ed10210aa21d7bc135957c6e to your computer and use it in GitHub Desktop.
Save amoeba/b523c9d2ed10210aa21d7bc135957c6e to your computer and use it in GitHub Desktop.
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
extern "C" {
fn _wgetenv_s(
pReturnValue: *mut usize,
buffer: *mut u16,
numberOfElements: usize,
varname: *const u16,
) -> i32;
}
fn get_env_var_wgetenv_s(var_name: &str) -> Result<String, String> {
// Convert the variable name to wide string (UTF-16)
let wide_name: Vec<u16> = var_name.encode_utf16().chain(std::iter::once(0)).collect();
let mut required_size: usize = 0;
// First call to get the required buffer size
let result = unsafe {
_wgetenv_s(
&mut required_size,
std::ptr::null_mut(),
0,
wide_name.as_ptr(),
)
};
if result != 0 {
return Err(format!("Failed to get buffer size, error code: {}", result));
}
if required_size == 0 {
return Err("Environment variable not found".to_string());
}
// Allocate buffer and get the actual value
let mut buffer: Vec<u16> = vec![0; required_size];
let mut actual_size: usize = 0;
let result = unsafe {
_wgetenv_s(
&mut actual_size,
buffer.as_mut_ptr(),
required_size,
wide_name.as_ptr(),
)
};
if result != 0 {
return Err(format!("Failed to get environment variable, error code: {}", result));
}
// Convert wide string back to Rust String
// Remove the null terminator
buffer.truncate(actual_size.saturating_sub(1));
let os_string = OsString::from_wide(&buffer);
os_string.into_string().map_err(|_| "Invalid UTF-8 in environment variable".to_string())
}
fn main() {
match get_env_var_wgetenv_s("PATH") {
Ok(value) => println!("PATH: {}", value),
Err(e) => println!("Error: {}", e),
}
match get_env_var_wgetenv_s("NONEXISTENT_VAR") {
Ok(value) => println!("Found: {}", value),
Err(e) => println!("Error: {}", e),
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment