use super::RAIIHandle;
use std::io;
use std::path::Path;
use winapi::shared::minwindef::TRUE;
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
use winapi::um::tlhelp32::{
CreateToolhelp32Snapshot, Process32First, Process32Next, PROCESSENTRY32, TH32CS_SNAPPROCESS,
};
pub fn for_each_process<F>(mut f: F) -> io::Result<()>
where
F: FnMut(u32, &Path),
{
let handle = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) };
debug!(
"Called CreateToolHelp32Snapshot with return value {}",
handle as usize
);
if handle == INVALID_HANDLE_VALUE {
let error = io::Error::last_os_error();
error!("CreateToolHelp32Snapshot failed with error {:?}", error);
return Err(error);
}
let _guard = RAIIHandle::new(handle);
debug!("Handle is {}", handle as usize);
let mut pe32: PROCESSENTRY32 = unsafe { std::mem::zeroed() };
pe32.dwSize = std::mem::size_of::<PROCESSENTRY32>() as u32;
debug!("dwSize is {}", pe32.dwSize);
let v = unsafe { Process32First(handle, &mut pe32) };
if v != TRUE {
let error = io::Error::last_os_error();
error!(
"Process32First returned {}, failed with error {:?}",
v, error
);
return Err(error);
}
match get_process_data(&pe32) {
Ok((id, name)) => f(id, name),
Err(_id) => warn!(
"The process with id {} didn't have an UTF8 valid name.",
_id
),
}
trace!("Cleaning back process name.");
pe32.szExeFile
.iter_mut()
.take_while(|c| **c != 0)
.for_each(|c| *c = 0);
while unsafe { Process32Next(handle, &mut pe32) } != 0 {
match get_process_data(&pe32) {
Ok((id, name)) => f(id, name),
Err(_id) => warn!(
"The process with id {} didn't have an UTF8 valid name.",
_id
),
}
trace!("Cleaning back process name.");
pe32.szExeFile
.iter_mut()
.take_while(|c| **c != 0)
.for_each(|c| *c = 0);
}
Ok(())
}
fn get_process_data(process: &PROCESSENTRY32) -> Result<(u32, &Path), u32> {
let id = process.th32ProcessID;
let name = super::get_winstring(&process.szExeFile).map_err(|_| id)?;
trace!("get_process_data: id = {}, name = {}", id, name);
Ok((id, Path::new(name)))
}