use windows::Win32::Foundation::{CloseHandle, ERROR_NO_MORE_FILES};
use windows::Win32::System::Diagnostics::ToolHelp::{
CreateToolhelp32Snapshot, PROCESSENTRY32W, Process32FirstW, Process32NextW, TH32CS_SNAPPROCESS,
};
use super::processes::Process;
use super::types::{ProcessId, ProcessInfo};
use crate::error::{Error, ProcessError, ProcessOpenError, Result};
impl Process {
pub fn list() -> Result<Vec<ProcessInfo>> {
let mut buffer = Vec::with_capacity(128);
Self::list_with_buffer(&mut buffer)?;
Ok(buffer)
}
pub fn list_with_buffer(out_processes: &mut Vec<ProcessInfo>) -> Result<usize> {
Self::list_with_filter_impl(out_processes, |_| true)
}
pub fn list_with_filter<F>(out_processes: &mut Vec<ProcessInfo>, filter: F) -> Result<usize>
where
F: Fn(&ProcessInfo) -> bool,
{
Self::list_with_filter_impl(out_processes, filter)
}
fn list_with_filter_impl<F>(out_processes: &mut Vec<ProcessInfo>, filter: F) -> Result<usize>
where
F: Fn(&ProcessInfo) -> bool,
{
out_processes.clear();
let snapshot = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) }.map_err(|e| {
Error::Process(ProcessError::OpenFailed(ProcessOpenError::with_code(
0,
"Failed to create process snapshot",
e.code().0,
)))
})?;
let mut entry = PROCESSENTRY32W {
dwSize: std::mem::size_of::<PROCESSENTRY32W>() as u32,
..Default::default()
};
if unsafe { Process32FirstW(snapshot, &mut entry) }.is_ok() {
loop {
let name_end = entry
.szExeFile
.iter()
.position(|&c| c == 0)
.unwrap_or(entry.szExeFile.len());
let name = String::from_utf16_lossy(&entry.szExeFile[..name_end]);
let parent_pid = if entry.th32ParentProcessID == 0 {
None
} else {
Some(ProcessId::new(entry.th32ParentProcessID))
};
let process_info = ProcessInfo {
pid: ProcessId::new(entry.th32ProcessID),
parent_pid,
name,
thread_count: entry.cntThreads,
};
if filter(&process_info) {
out_processes.push(process_info);
}
match unsafe { Process32NextW(snapshot, &mut entry) } {
Ok(_) => continue,
Err(e) if e.code() == ERROR_NO_MORE_FILES.into() => break,
Err(_) => break,
}
}
}
unsafe {
let _ = CloseHandle(snapshot);
}
Ok(out_processes.len())
}
pub fn parent_id(&self) -> Result<Option<ProcessId>> {
let processes = Self::list()?;
for proc in processes {
if proc.pid == self.id() {
return Ok(proc.parent_pid);
}
}
Ok(None)
}
pub fn children(&self) -> Result<Vec<ProcessId>> {
let mut buffer = Vec::with_capacity(128);
self.children_with_buffer(&mut buffer)?;
Ok(buffer.into_iter().map(|p| p.pid).collect())
}
pub fn children_with_buffer(&self, buffer: &mut Vec<ProcessInfo>) -> Result<usize> {
let self_id = self.id();
Self::list_with_filter(buffer, |p| p.parent_pid == Some(self_id))
}
}