use crate::log_debug;
use std::path::PathBuf;
use windows::Win32::Foundation::{CloseHandle, INVALID_HANDLE_VALUE};
use windows::Win32::System::Diagnostics::ToolHelp::{
CreateToolhelp32Snapshot, PROCESSENTRY32W, Process32FirstW, Process32NextW,
TH32CS_SNAPPROCESS,
};
use windows::Win32::System::ProcessStatus::K32GetModuleBaseNameW;
use windows::Win32::System::Threading::{
GetCurrentProcessId, OpenProcess, PROCESS_QUERY_INFORMATION,
PROCESS_VM_READ,
};
pub fn is_interactive_parent(gui_shells: &[String]) -> bool {
let parent_pid = get_parent_pid().unwrap_or(0);
let parent_name = get_process_name(parent_pid);
let is_gui_shell = parent_name
.as_ref()
.map(|name| {
gui_shells
.iter()
.any(|shell| shell.eq_ignore_ascii_case(name))
})
.unwrap_or(false);
log_debug!(&format!("GUI Shells: {:?}", gui_shells));
log_debug!(&format!(
"Parent PID: {}, Parent Name: {:?}, Is GUI Shell: {}",
parent_pid, parent_name, is_gui_shell
));
is_gui_shell
}
fn get_parent_pid() -> Option<u32> {
unsafe {
let current_pid = GetCurrentProcessId();
let snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0).ok()?;
if snapshot == INVALID_HANDLE_VALUE {
return None;
}
let mut entry = PROCESSENTRY32W {
dwSize: std::mem::size_of::<PROCESSENTRY32W>() as u32,
..Default::default()
};
if Process32FirstW(snapshot, &mut entry).is_ok() {
loop {
if entry.th32ProcessID == current_pid {
let _ = CloseHandle(snapshot);
return Some(entry.th32ParentProcessID);
}
if Process32NextW(snapshot, &mut entry).is_err() {
break;
}
}
}
let _ = CloseHandle(snapshot);
None
}
}
fn get_process_name(pid: u32) -> Option<String> {
unsafe {
let h_process = OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
false,
pid,
)
.ok()?;
if h_process.is_invalid() {
return None;
}
let mut buffer = [0u16; 260];
let len = K32GetModuleBaseNameW(h_process, None, &mut buffer);
let _ = CloseHandle(h_process);
if len == 0 {
return None;
}
Some(String::from_utf16_lossy(&buffer[..len as usize]))
}
}
pub(crate) fn resolve_executable(executable: &str) -> Option<PathBuf> {
which::which(executable).ok()
}