use windows::Win32::{
Foundation::HANDLE,
System::Diagnostics::ToolHelp::{
CreateToolhelp32Snapshot, Process32FirstW, Process32NextW, PROCESSENTRY32W,
TH32CS_SNAPPROCESS,
},
};
#[derive(Debug, PartialEq)]
pub struct SnapshotState {
pub process_id: u32,
pub thread_count: u32,
pub parent_process_id: u32,
pub base_priority_level: i32,
file_name_buffer: [u16; 260],
_snapshot: HANDLE,
}
impl SnapshotState {
pub fn iter() -> Self {
Self {
process_id: 0,
thread_count: 0,
parent_process_id: 0,
base_priority_level: 0,
file_name_buffer: [0; 260],
_snapshot: HANDLE(0 as _),
}
}
pub fn get_name(&self) -> String {
let null_pos = self
.file_name_buffer
.iter()
.position(|&c| c == 0)
.unwrap_or(self.file_name_buffer.len());
let string_data = &self.file_name_buffer[0..null_pos];
String::from_utf16_lossy(string_data)
}
}
impl Iterator for SnapshotState {
type Item = Self;
fn next(&mut self) -> Option<Self::Item> {
let mut process_info = PROCESSENTRY32W::default();
process_info.dwSize = std::mem::size_of::<PROCESSENTRY32W>() as _;
unsafe {
if self._snapshot == HANDLE(0 as _) {
self._snapshot = match CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) {
Ok(handle) => handle,
Err(_) => return None,
};
let _ = Process32FirstW(self._snapshot, &mut process_info);
} else {
if (!Process32NextW(self._snapshot, &mut process_info).is_ok()).into() {
return None;
}
}
}
Some(Self {
process_id: process_info.th32ProcessID,
thread_count: process_info.cntThreads,
parent_process_id: process_info.th32ParentProcessID,
base_priority_level: process_info.pcPriClassBase,
file_name_buffer: process_info.szExeFile,
_snapshot: HANDLE(0 as _),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
use windows::Win32::System::Threading::GetCurrentProcessId;
#[test]
fn find_current_process() -> () {
let current_pid = unsafe { GetCurrentProcessId() };
let target = SnapshotState::iter().find(|p| p.process_id as u32 == current_pid);
assert_eq!(target.is_some(), true);
}
}