use std::ffi::{OsStr, OsString};
use std::os::windows::ffi::OsStrExt;
use windows::core::PCWSTR;
use windows::Win32::Foundation::HWND;
use windows::Win32::UI::Shell::{IsUserAnAdmin, ShellExecuteW};
use windows::Win32::UI::WindowsAndMessaging::SW_SHOWNORMAL;
use crate::error::{Error, Result};
fn to_wide_os(value: &OsStr) -> Vec<u16> {
value.encode_wide().chain(std::iter::once(0)).collect()
}
fn to_wide_str(value: &str) -> Vec<u16> {
OsStr::new(value)
.encode_wide()
.chain(std::iter::once(0))
.collect()
}
fn quote_arg(arg: &OsStr) -> String {
let text = arg.to_string_lossy().replace('"', "\\\"");
format!("\"{text}\"")
}
pub fn is_elevated() -> Result<bool> {
let is_admin = unsafe { IsUserAnAdmin() };
Ok(is_admin.as_bool())
}
pub fn restart_as_admin(args: &[OsString]) -> Result<()> {
let exe = std::env::current_exe()?;
let exe_w = to_wide_os(exe.as_os_str());
let verb_w = to_wide_str("runas");
let joined_args = args
.iter()
.map(|a| quote_arg(a.as_os_str()))
.collect::<Vec<_>>()
.join(" ");
let args_w = to_wide_str(&joined_args);
let result = unsafe {
ShellExecuteW(
Some(HWND::default()),
PCWSTR(verb_w.as_ptr()),
PCWSTR(exe_w.as_ptr()),
PCWSTR(args_w.as_ptr()),
PCWSTR::null(),
SW_SHOWNORMAL,
)
};
let code = result.0 as isize;
if code <= 32 {
Err(Error::WindowsApi {
context: "ShellExecuteW(runas)",
code: code as i32,
})
} else {
Ok(())
}
}