diff --git a/ghost-core/Cargo.toml b/ghost-core/Cargo.toml new file mode 100644 index 0000000..d76efed --- /dev/null +++ b/ghost-core/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "ghost-core" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true + +[dependencies] +anyhow.workspace = true +thiserror.workspace = true +log.workspace = true + +[target.'cfg(windows)'.dependencies] +windows = { version = "0.58", features = [ + "Win32_Foundation", + "Win32_System_Diagnostics_ToolHelp", + "Win32_System_Threading", + "Win32_System_ProcessStatus", + "Win32_System_Memory", + "Win32_Security", +] } + +[target.'cfg(unix)'.dependencies] +libc = "0.2" diff --git a/ghost-core/src/lib.rs b/ghost-core/src/lib.rs new file mode 100644 index 0000000..c6ea6c3 --- /dev/null +++ b/ghost-core/src/lib.rs @@ -0,0 +1,3 @@ +pub mod process; + +pub use process::ProcessInfo; diff --git a/ghost-core/src/process.rs b/ghost-core/src/process.rs new file mode 100644 index 0000000..384b026 --- /dev/null +++ b/ghost-core/src/process.rs @@ -0,0 +1,80 @@ +use std::fmt; + +#[derive(Debug, Clone)] +pub struct ProcessInfo { + pub pid: u32, + pub name: String, + pub path: Option, +} + +impl fmt::Display for ProcessInfo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{}] {}", self.pid, self.name) + } +} + +#[cfg(windows)] +mod platform { + use super::ProcessInfo; + use anyhow::{Context, Result}; + use windows::Win32::Foundation::{CloseHandle, HANDLE}; + use windows::Win32::System::Diagnostics::ToolHelp::{ + CreateToolhelp32Snapshot, Process32FirstW, Process32NextW, PROCESSENTRY32W, + TH32CS_SNAPPROCESS, + }; + + pub fn enumerate_processes() -> Result> { + let mut processes = Vec::new(); + + unsafe { + let snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) + .context("Failed to create process snapshot")?; + + let mut entry = PROCESSENTRY32W { + dwSize: std::mem::size_of::() as u32, + ..Default::default() + }; + + if Process32FirstW(snapshot, &mut entry).is_ok() { + loop { + let name = String::from_utf16_lossy( + &entry.szExeFile[..entry + .szExeFile + .iter() + .position(|&c| c == 0) + .unwrap_or(entry.szExeFile.len())], + ); + + processes.push(ProcessInfo { + pid: entry.th32ProcessID, + name, + path: None, + }); + + if Process32NextW(snapshot, &mut entry).is_err() { + break; + } + } + } + + let _ = CloseHandle(snapshot); + } + + Ok(processes) + } +} + +#[cfg(not(windows))] +mod platform { + use super::ProcessInfo; + use anyhow::Result; + + pub fn enumerate_processes() -> Result> { + // TODO: Implement Linux/macOS enumeration + Ok(Vec::new()) + } +} + +pub fn enumerate_processes() -> anyhow::Result> { + platform::enumerate_processes() +}