netsock 0.7.0

Cross-platform library for network sockets information
Documentation
use std::collections::HashMap;
use std::mem::size_of;
use std::mem::zeroed;

use windows_sys::Win32::Foundation::CloseHandle;
use windows_sys::Win32::Foundation::FALSE;
use windows_sys::Win32::Foundation::HANDLE;
use windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE;
use windows_sys::Win32::System::Diagnostics::ToolHelp::{
    CreateToolhelp32Snapshot, PROCESSENTRY32, Process32First, Process32Next, TH32CS_SNAPPROCESS,
};

fn process_entry_name(process: &PROCESSENTRY32) -> Result<String, Box<dyn std::error::Error>> {
    let name = process.szExeFile;
    let len = name
        .iter()
        .position(|&x| x == 0)
        .ok_or("Invalid process name")?;
    match String::from_utf8(name[0..len].iter().map(|e| *e as u8).collect()) {
        Ok(name) => Ok(name),
        Err(_) => Err("Invalid UTF sequence for process name".into()),
    }
}

pub fn get_process_names() -> Result<HashMap<u32, String>, Box<dyn std::error::Error>> {
    let h = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) };
    if h == INVALID_HANDLE_VALUE {
        return Err("Failed to create snapshot".into());
    }
    struct HandleGuard(HANDLE);
    impl Drop for HandleGuard {
        fn drop(&mut self) {
            unsafe {
                let _ = CloseHandle(self.0);
            }
        }
    }
    let _guard = HandleGuard(h);

    let mut process = unsafe { zeroed::<PROCESSENTRY32>() };
    process.dwSize = u32::try_from(size_of::<PROCESSENTRY32>())?;

    unsafe {
        if Process32First(h, &mut process) == FALSE {
            return Err("Failed to get first process".into());
        }
    }

    let mut processes = HashMap::new();
    loop {
        if let Ok(name) = process_entry_name(&process) {
            processes.insert(process.th32ProcessID, name);
        }

        unsafe {
            if Process32Next(h, &mut process) == FALSE {
                break;
            }
        }
    }

    Ok(processes)
}