use std::io;
use std::str::from_utf8;
use winapi::shared::minwindef::TRUE;
use winapi::um::handleapi::{CloseHandle, INVALID_HANDLE_VALUE};
use winapi::um::tlhelp32::{
CreateToolhelp32Snapshot, Process32First, Process32Next, PROCESSENTRY32, TH32CS_SNAPPROCESS,
};
use winapi::um::winnt::HANDLE;
pub fn for_each_process<F>(mut f: F) -> io::Result<()>
where
F: FnMut(u32, &str),
{
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<'a>(process: &'a PROCESSENTRY32) -> Result<(u32, &'a str), u32> {
let id = process.th32ProcessID;
let name: &'a [u8] = unsafe {
std::slice::from_raw_parts(process.szExeFile.as_ptr().cast(), process.szExeFile.len())
};
let name = from_utf8(name).map_err(|_| id)?;
trace!("get_process_data: id = {}, name = {}", id, name);
Ok((id, name))
}
#[repr(transparent)]
struct RAIIHandle(pub HANDLE);
impl RAIIHandle {
pub fn new(handle: HANDLE) -> RAIIHandle {
RAIIHandle(handle)
}
}
impl Drop for RAIIHandle {
fn drop(&mut self) {
debug!("Calling CloseHandle from the RAIIHandle's drop.");
unsafe { CloseHandle(self.0) };
}
}