windows_erg/process/
threads.rs1use windows::Win32::Foundation::{CloseHandle, ERROR_NO_MORE_FILES};
4use windows::Win32::System::Diagnostics::ToolHelp::{
5 CreateToolhelp32Snapshot, TH32CS_SNAPTHREAD, THREADENTRY32, Thread32First, Thread32Next,
6};
7
8use super::processes::Process;
9use super::types::{ProcessId, ThreadId, ThreadInfo};
10use crate::error::{Error, ProcessError, ProcessOpenError, Result};
11
12impl Process {
13 pub fn threads(&self) -> Result<Vec<ThreadInfo>> {
15 let mut buffer = Vec::with_capacity(256);
16 self.threads_with_buffer(&mut buffer)?;
17 Ok(buffer)
18 }
19
20 pub fn threads_with_buffer(&self, out_threads: &mut Vec<ThreadInfo>) -> Result<usize> {
22 self.threads_with_filter(out_threads, |_| true)
23 }
24
25 pub fn threads_with_filter<F>(
33 &self,
34 out_threads: &mut Vec<ThreadInfo>,
35 filter: F,
36 ) -> Result<usize>
37 where
38 F: Fn(&ThreadInfo) -> bool,
39 {
40 out_threads.clear();
41
42 let snapshot = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0) }.map_err(|e| {
43 Error::Process(ProcessError::OpenFailed(ProcessOpenError::with_code(
44 self.id().as_u32(),
45 "Failed to create thread snapshot",
46 e.code().0,
47 )))
48 })?;
49
50 let mut entry = THREADENTRY32 {
51 dwSize: std::mem::size_of::<THREADENTRY32>() as u32,
52 ..Default::default()
53 };
54 let process_id = self.id().as_u32();
55
56 if unsafe { Thread32First(snapshot, &mut entry) }.is_ok() {
57 loop {
58 if entry.th32OwnerProcessID == process_id {
60 let thread_info = ThreadInfo {
61 tid: ThreadId::new(entry.th32ThreadID),
62 pid: ProcessId::new(entry.th32OwnerProcessID),
63 base_priority: entry.tpBasePri,
64 };
65
66 if filter(&thread_info) {
68 out_threads.push(thread_info);
69 }
70 }
71
72 match unsafe { Thread32Next(snapshot, &mut entry) } {
74 Ok(_) => continue,
75 Err(e) if e.code() == ERROR_NO_MORE_FILES.into() => break,
76 Err(_) => break,
77 }
78 }
79 }
80
81 unsafe {
82 let _ = CloseHandle(snapshot);
83 }
84 Ok(out_threads.len())
85 }
86}