#[cfg(all(feature = "winapi", target_os = "windows"))]
use windows::Win32::{
Foundation::CloseHandle,
System::Diagnostics::ToolHelp::{
CreateToolhelp32Snapshot, Process32FirstW, Process32NextW, PROCESSENTRY32W,
TH32CS_SNAPPROCESS,
},
};
#[cfg(all(feature = "winapi", target_os = "windows"))]
pub fn get_process_id_by_name(name: &str) -> Option<u32> {
unsafe {
let h_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
let Ok(h_snapshot) = h_snapshot else {
return None;
};
let mut pe = PROCESSENTRY32W {
dwSize: std::mem::size_of::<PROCESSENTRY32W>() as u32,
..Default::default()
};
let ret = Process32FirstW(h_snapshot, &mut pe);
loop {
if ret.is_err() {
break;
}
let end_pos = pe.szExeFile.iter().position(|p| *p == 0);
let Some(end_pos) = end_pos else {
break;
};
let process_name = String::from_utf16_lossy(&pe.szExeFile[0..end_pos]);
if process_name == name {
let _ = CloseHandle(h_snapshot);
return Some(pe.th32ProcessID);
}
let ret = Process32NextW(h_snapshot, &mut pe);
if ret.is_err() {
break;
}
}
let _ = CloseHandle(h_snapshot);
}
None
}
#[cfg(all(feature = "winapi", target_os = "windows"))]
#[derive(Debug)]
pub enum ServStatus {
Uninstalled,
Running,
Paused,
Stoped,
StartPending,
StopPending,
PausePending,
ContinuePending,
Unknow,
}
#[cfg(all(feature = "winapi", target_os = "windows"))]
pub fn sc_query(service_name: &str) -> Result<ServStatus, windows::core::Error> {
use windows::{
core::PWSTR,
Win32::System::Services::{
CloseServiceHandle, OpenSCManagerW, OpenServiceW, QueryServiceStatus,
SC_MANAGER_CONNECT, SERVICE_CONTINUE_PENDING, SERVICE_PAUSED, SERVICE_PAUSE_PENDING,
SERVICE_QUERY_STATUS, SERVICE_RUNNING, SERVICE_START_PENDING, SERVICE_STATUS,
SERVICE_STOPPED, SERVICE_STOP_PENDING,
},
};
unsafe {
let h_sc = OpenSCManagerW(None, None, SC_MANAGER_CONNECT)?;
let mut service_name: Vec<u16> = service_name.encode_utf16().chain([0]).collect();
let service_name = PWSTR::from_raw(service_name.as_mut_ptr());
let h_service = OpenServiceW(h_sc, service_name, SERVICE_QUERY_STATUS);
let Ok(h_service) = h_service else {
let err = h_service.unwrap_err();
if err.code().0 == 0x80070424u32 as i32 {
return Ok(ServStatus::Uninstalled);
}
return Err(err);
};
let mut s_status = SERVICE_STATUS::default();
QueryServiceStatus(h_service, &mut s_status)?;
let _ = CloseServiceHandle(h_service);
let _ = CloseServiceHandle(h_sc);
let status = match s_status.dwCurrentState {
SERVICE_RUNNING => ServStatus::Running,
SERVICE_PAUSED => ServStatus::Paused,
SERVICE_STOPPED => ServStatus::Stoped,
SERVICE_CONTINUE_PENDING => ServStatus::ContinuePending,
SERVICE_START_PENDING => ServStatus::StartPending,
SERVICE_PAUSE_PENDING => ServStatus::PausePending,
SERVICE_STOP_PENDING => ServStatus::StopPending,
_ => ServStatus::Unknow,
};
Ok(status)
}
}
#[cfg(all(feature = "winapi", target_os = "windows"))]
pub fn runas(
exe_path: &str,
args: Option<Vec<String>>,
wait: bool,
) -> Result<(), windows::core::Error> {
use windows::{
core::{w, PCWSTR},
Win32::{
System::{
Com::{
CoInitializeEx, CoUninitialize, COINIT_APARTMENTTHREADED,
COINIT_DISABLE_OLE1DDE,
},
Threading::{WaitForSingleObject, INFINITE},
},
UI::{
Shell::{
ShellExecuteExW, SEE_MASK_NOCLOSEPROCESS, SEE_MASK_UNICODE, SHELLEXECUTEINFOW,
},
WindowsAndMessaging::SW_SHOWNORMAL,
},
},
};
unsafe {
let _ = CoInitializeEx(None, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
let mut sei: SHELLEXECUTEINFOW = SHELLEXECUTEINFOW::default();
sei.cbSize = std::mem::size_of::<SHELLEXECUTEINFOW>() as u32;
sei.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_UNICODE;
sei.lpVerb = w!("runas");
sei.lpFile = PCWSTR::from_raw(w!("cmd.exe").as_ptr());
let shell_switch = "/C";
let script_path_quoted = format!("\"{}\"", exe_path);
let args_str = if let Some(args) = args {
args.into_iter()
.map(|arg| format!("\"{}\"", arg))
.collect::<Vec<_>>()
.join(" ")
} else {
String::new()
};
let params_str = format!("{} \"{} {}\"", shell_switch, script_path_quoted, args_str);
let mut params_w: Vec<u16> = params_str.encode_utf16().collect();
params_w.push(0);
sei.lpParameters = PCWSTR::from_raw(params_w.leak().as_mut_ptr());
sei.nShow = SW_SHOWNORMAL.0;
ShellExecuteExW(&mut sei)?;
if wait {
WaitForSingleObject(sei.hProcess, INFINITE);
}
CoUninitialize();
Ok(())
}
}
#[cfg(all(feature = "winapi", target_os = "windows"))]
pub fn current_is_admin() -> Result<bool, windows::core::Error> {
use windows::Win32::{
Foundation::HANDLE,
Security::{GetTokenInformation, TokenElevation, TOKEN_ELEVATION, TOKEN_QUERY},
System::Threading::{GetCurrentProcess, OpenProcessToken},
};
unsafe {
let mut token_handle = HANDLE::default();
OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut token_handle)?;
let mut token_info = TOKEN_ELEVATION::default();
let mut return_len = 0;
GetTokenInformation(
token_handle,
TokenElevation,
Some(&mut token_info as *mut _ as *mut std::ffi::c_void),
std::mem::size_of::<TOKEN_ELEVATION>() as u32,
&mut return_len,
)?;
CloseHandle(token_handle)?;
return Ok(token_info.TokenIsElevated == 1);
}
}
#[cfg(all(feature = "winapi", target_os = "windows"))]
pub fn enable_virtual_terminal() -> Result<(), windows::core::Error> {
use windows::Win32::System::Console::{
GetConsoleMode, GetStdHandle, SetConsoleMode, CONSOLE_MODE,
ENABLE_VIRTUAL_TERMINAL_PROCESSING, STD_OUTPUT_HANDLE,
};
unsafe {
let handle = GetStdHandle(STD_OUTPUT_HANDLE).unwrap();
let mut mode = CONSOLE_MODE::default();
let _ = GetConsoleMode(handle, &mut mode)?;
let _ = SetConsoleMode(handle, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)?;
Ok(())
}
}
#[cfg(all(feature = "winapi", target_os = "windows"))]
pub fn msi_install(path: &str, args: Option<&str>) -> Result<(), windows::core::Error> {
use windows::{
core::PCWSTR, Win32::System::ApplicationInstallationAndServicing::MsiInstallProductW,
};
let msi_path_wide: Vec<u16> = path.encode_utf16().chain([0]).collect();
let msi_args = if args.is_some() {
let args = args.unwrap();
let args: Vec<u16> = args.encode_utf16().chain([0]).collect();
args
} else {
Vec::new()
};
let msi_args = if msi_args.is_empty() {
PCWSTR::null()
} else {
PCWSTR::from_raw(msi_args.as_ptr())
};
let result = unsafe {
MsiInstallProductW(
PCWSTR(msi_path_wide.as_ptr()),
msi_args, )
};
if result != 0 {
return Err(windows::core::Error::from_win32());
}
Ok(())
}
#[cfg(all(feature = "winapi", target_os = "windows"))]
pub fn msi_get_version(name: &str) -> Result<String, windows::core::Error> {
use windows::{
core::{HRESULT, PWSTR},
Win32::System::ApplicationInstallationAndServicing::{
MsiEnumProductsW, MsiGetProductInfoW, INSTALLPROPERTY_PRODUCTNAME,
INSTALLPROPERTY_VERSIONSTRING,
},
};
unsafe {
let mut prod_code: Vec<u16> = Vec::new();
prod_code.resize(0xff, 0);
let prod_code = PWSTR::from_raw(prod_code.as_mut_ptr());
let mut idx = 0;
let mut ret = MsiEnumProductsW(idx, prod_code);
loop {
if ret != 0 {
break;
}
idx += 1;
let mut buf: Vec<u16> = Vec::new();
buf.resize(0xff, 0);
let prod_name = PWSTR::from_raw(buf.as_mut_ptr());
let mut len = 0xff;
let name_ret = MsiGetProductInfoW(
prod_code,
INSTALLPROPERTY_PRODUCTNAME,
Some(prod_name),
Some(&mut len),
);
if name_ret != 0 {
continue;
}
let prod_name = prod_name.to_string().unwrap_or_default();
if prod_name == name {
let mut buf: Vec<u16> = Vec::new();
buf.resize(0xff, 0);
let buf = PWSTR::from_raw(buf.as_mut_ptr());
let mut len = 0xff;
let ret = MsiGetProductInfoW(
prod_code,
INSTALLPROPERTY_VERSIONSTRING,
Some(buf),
Some(&mut len),
);
if ret != 0 {
return Err(windows::core::Error::from_win32());
}
let version = buf.to_string().unwrap_or_default();
return Ok(version);
}
ret = MsiEnumProductsW(idx, prod_code);
}
Err(windows::core::Error::from_hresult(HRESULT::from_win32(1)))
}
}
#[cfg(all(feature = "winapi", target_os = "windows"))]
pub fn get_system_proxy() -> Option<String> {
use std::ffi::c_void;
use windows::Win32::{
Foundation::{GlobalFree, HGLOBAL},
Networking::WinInet::{
InternetQueryOptionW, INTERNET_OPTION_PER_CONNECTION_OPTION,
INTERNET_PER_CONN_AUTOCONFIG_URL, INTERNET_PER_CONN_AUTODISCOVERY_FLAGS,
INTERNET_PER_CONN_FLAGS, INTERNET_PER_CONN_OPTIONW, INTERNET_PER_CONN_OPTION_LISTW,
INTERNET_PER_CONN_PROXY_BYPASS, INTERNET_PER_CONN_PROXY_SERVER, PROXY_TYPE_PROXY,
},
};
let mut list = INTERNET_PER_CONN_OPTION_LISTW::default();
list.dwSize = size_of::<INTERNET_PER_CONN_OPTION_LISTW>() as u32;
let mut options = [INTERNET_PER_CONN_OPTIONW::default(); 5];
options[0].dwOption = INTERNET_PER_CONN_AUTOCONFIG_URL;
options[1].dwOption = INTERNET_PER_CONN_AUTODISCOVERY_FLAGS;
options[2].dwOption = INTERNET_PER_CONN_FLAGS;
options[3].dwOption = INTERNET_PER_CONN_PROXY_BYPASS;
options[4].dwOption = INTERNET_PER_CONN_PROXY_SERVER;
list.dwOptionCount = 5;
list.dwOptionError = 0;
list.pOptions = &mut options as *mut INTERNET_PER_CONN_OPTIONW;
let mut n_size = size_of::<INTERNET_PER_CONN_OPTION_LISTW>() as u32;
let ret = unsafe {
InternetQueryOptionW(
None,
INTERNET_OPTION_PER_CONNECTION_OPTION,
Some(&mut list as *mut INTERNET_PER_CONN_OPTION_LISTW as *mut c_void),
&mut n_size,
)
};
if ret.is_err() {
println!("{:?}", ret.unwrap_err());
return None;
}
let enable = unsafe { options[2].Value.dwValue } & PROXY_TYPE_PROXY == PROXY_TYPE_PROXY;
let proxy_url = unsafe { options[4].Value.pszValue.to_string().unwrap() };
unsafe {
if !options[0].Value.pszValue.is_null() {
let mut mem = HGLOBAL::default();
mem.0 = options[0].Value.pszValue.as_ptr() as *mut c_void;
let _ = GlobalFree(Some(mem));
}
if !options[3].Value.pszValue.is_null() {
let mut mem = HGLOBAL::default();
mem.0 = options[3].Value.pszValue.as_ptr() as *mut c_void;
let _ = GlobalFree(Some(mem));
}
if !options[4].Value.pszValue.is_null() {
let mut mem = HGLOBAL::default();
mem.0 = options[4].Value.pszValue.as_ptr() as *mut c_void;
let _ = GlobalFree(Some(mem));
}
}
if enable {
Some(proxy_url)
} else {
None
}
}
#[test]
#[cfg(all(feature = "winapi", target_os = "windows"))]
fn test_get_process_id_by_name() {
let ret = get_process_id_by_name("Notepad.exe");
println!("{:?}", ret);
}
#[test]
#[cfg(all(feature = "winapi", target_os = "windows"))]
fn test_sc_query() {
let ret = sc_query("slmd");
println!("{:?}", ret);
}