use windows::Win32::Foundation::{CloseHandle, ERROR_NO_MORE_FILES};
use windows::Win32::System::Diagnostics::ToolHelp::{
CreateToolhelp32Snapshot, TH32CS_SNAPTHREAD, THREADENTRY32, Thread32First, Thread32Next,
};
use super::processes::Process;
use super::types::{ProcessId, ThreadId, ThreadInfo};
use crate::error::{Error, ProcessError, ProcessOpenError, Result};
impl Process {
pub fn threads(&self) -> Result<Vec<ThreadInfo>> {
let mut buffer = Vec::with_capacity(256);
self.threads_with_buffer(&mut buffer)?;
Ok(buffer)
}
pub fn threads_with_buffer(&self, out_threads: &mut Vec<ThreadInfo>) -> Result<usize> {
self.threads_with_filter(out_threads, |_| true)
}
pub fn threads_with_filter<F>(
&self,
out_threads: &mut Vec<ThreadInfo>,
filter: F,
) -> Result<usize>
where
F: Fn(&ThreadInfo) -> bool,
{
out_threads.clear();
let snapshot = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0) }.map_err(|e| {
Error::Process(ProcessError::OpenFailed(ProcessOpenError::with_code(
self.id().as_u32(),
"Failed to create thread snapshot",
e.code().0,
)))
})?;
let mut entry = THREADENTRY32 {
dwSize: std::mem::size_of::<THREADENTRY32>() as u32,
..Default::default()
};
let process_id = self.id().as_u32();
if unsafe { Thread32First(snapshot, &mut entry) }.is_ok() {
loop {
if entry.th32OwnerProcessID == process_id {
let thread_info = ThreadInfo {
tid: ThreadId::new(entry.th32ThreadID),
pid: ProcessId::new(entry.th32OwnerProcessID),
base_priority: entry.tpBasePri,
};
if filter(&thread_info) {
out_threads.push(thread_info);
}
}
match unsafe { Thread32Next(snapshot, &mut entry) } {
Ok(_) => continue,
Err(e) if e.code() == ERROR_NO_MORE_FILES.into() => break,
Err(_) => break,
}
}
}
unsafe {
let _ = CloseHandle(snapshot);
}
Ok(out_threads.len())
}
}