tasklist/lib.rs
1//! # tasklist
2//!
3//!
4//! `tasklist` is a crate let you easily get tasklist and process information on windows.
5//! it based on [`windows-rs`](https://github.com/microsoft/windows-rs) crate.
6//!
7//! #### what information you can get
8//! 1. Process name, pid, parentID, threadsID
9//! 2. Process start_time, exit_time, and CPU_time (including kernel time and user time)
10//! 3. Process path and commandline parameters
11//! 4. Process SID and Domain/User information
12//! 5. Process IO counters (all `IO_COUNTERS` members)
13//! 6. Process memory information (all `PROCESS_MEMORY_COUNTERS` members)
14//! 7. Process handles count via `GetProcessHandleCount` API
15//! 8. Process file information via `GetFileVersionInfoExW` API
16//! 9. Detect WOW64 (Windows 32-bit on Windows 64-bit) environment and get architecture info
17//! 10. Full process iteration capabilities
18//! 11. Process termination functionality
19//! 12. Debug privilege elevation support
20//!
21//! _remember some infomation need higher privilege in some specific windows versions_
22//! ## example
23//! Get all process pid , process name and user .
24//! ```rust
25//! fn main(){
26//! unsafe{
27//! match tasklist::Tasklist::new(){
28//! Ok(tasks) => {
29//! for task in tasks{
30//! println!("pid: {} , name: {}", task.pid, task.pname);
31//! }
32//! },
33//! Err(e) => {
34//! println!("error: {}", e);
35//! }
36//! }
37//! }
38//! }
39//! ```
40//! Get all process name , pid , company name , file description.
41//! ```rust
42//!
43//! fn main(){
44//! for i in unsafe{tasklist::Tasklist::new().unwrap()}{
45//! let cpn = match i.get_file_info(){
46//! Ok(cpn) =>{
47//! println!("{:?}",cpn)
48//! },
49//! Err(_) => println!("not fonud"),
50//! };
51//! }
52//! }
53//!
54//! ```
55//!
56
57///find the process id by the name you gave , it return a `Result<Vec<u32>,String>`
58/// ```
59/// unsafe{
60/// let aid = tasklist::find_process_id_by_name("cmd.exe").unwrap();
61/// println!("{:#?}",aid);
62/// }
63/// ```
64#[cfg(any(windows, doc))]
65pub fn find_process_id_by_name(process_name: &str) -> Result<Vec<u32>,String> {
66 use std::mem::size_of;
67 use std::mem::zeroed;
68 use windows::Win32::System::Diagnostics::ToolHelp::{
69 CreateToolhelp32Snapshot, Process32FirstW, Process32NextW, PROCESSENTRY32W,
70 TH32CS_SNAPPROCESS,
71 };
72
73 let mut temp: Vec<u32> = vec![];
74 unsafe{
75 let h = match CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) {
76 Ok(h) => SnapshotHandle(h),
77 Err(e) => return Err(format!("Failed to create process snapshot: {}", e)),
78 };
79
80 let mut process = zeroed::<PROCESSENTRY32W>();
81 process.dwSize = size_of::<PROCESSENTRY32W>() as u32;
82
83 match Process32FirstW(h.0, &mut process) {
84 Ok(_) => {
85 loop {
86 if get_proc_name(&process.szExeFile) == process_name {
87 temp.push(process.th32ProcessID);
88 }
89 match Process32NextW(h.0, &mut process) {
90 Ok(_) => continue,
91 Err(_) => {
92 if temp.is_empty() {
93 return Err(format!("No process named '{}' found", process_name));
94 }
95 break;
96 }
97 }
98 }
99 },
100 Err(e) => return Err(format!("Failed to enumerate first process: {}", e)),
101 }
102 Ok(temp)
103 }
104}
105
106/// return the first process id by the name you gave , it return the `Result<u32,String>` , `u32` is the process id.
107/// ```
108/// let pid = tasklist::find_first_process_id_by_name("cmd.exe").unwrap();
109/// println!("{:#?}",pid);
110#[cfg(any(windows, doc))]
111pub fn find_first_process_id_by_name(process_name: &str) -> Result<u32,String> {
112 use std::mem::size_of;
113 use std::mem::zeroed;
114 use windows::Win32::System::Diagnostics::ToolHelp::{
115 CreateToolhelp32Snapshot, Process32FirstW, Process32NextW, PROCESSENTRY32W,
116 TH32CS_SNAPPROCESS,
117 };
118
119 unsafe {
120 let h = match CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) {
121 Ok(h) => SnapshotHandle(h),
122 Err(e) => return Err(format!("Failed to create process snapshot: {}", e)),
123 };
124
125 let mut process = zeroed::<PROCESSENTRY32W>();
126 process.dwSize = size_of::<PROCESSENTRY32W>() as u32;
127
128 match Process32FirstW(h.0, &mut process) {
129 Ok(_) => {
130 loop {
131 if get_proc_name(&process.szExeFile) == process_name {
132 return Ok(process.th32ProcessID);
133 }
134 match Process32NextW(h.0, &mut process) {
135 Ok(_) => continue,
136 Err(e) => return Err(format!("Process enumeration failed: {}", e)),
137 }
138 }
139 },
140 Err(e) => Err(format!("Failed to enumerate first process: {}", e)),
141 }
142 }
143}
144
145/// just like the name , this function will return a `Option<String>` by the id you gave, `String` is the name of process.
146/// ```
147/// unsafe{
148/// let pname = tasklist::find_process_name_by_id(9720);
149/// println!("{:#?}",pname);
150/// }
151///
152/// ```
153#[cfg(any(windows, doc))]
154pub fn find_process_name_by_id(process_id: u32) -> Option<String> {
155 use std::mem::size_of;
156 use std::mem::zeroed;
157 use windows::Win32::Foundation::CloseHandle;
158 use windows::Win32::System::Diagnostics::ToolHelp::{
159 CreateToolhelp32Snapshot, Process32FirstW, Process32NextW, PROCESSENTRY32W,
160 TH32CS_SNAPPROCESS,
161 };
162 unsafe{
163 let h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0).unwrap();
164
165 let mut process = zeroed::<PROCESSENTRY32W>();
166 process.dwSize = size_of::<PROCESSENTRY32W>() as u32;
167
168 match Process32FirstW(h, &mut process){
169 Ok(_)=>{
170 loop {
171 match Process32NextW(h, &mut process){
172 Ok(_)=>{
173 let id: u32 = process.th32ProcessID;
174 if id == process_id {
175 break;
176 }
177 },
178 Err(_)=>{
179 return None;
180 }
181 }
182 }
183 },
184 Err(_)=>return None
185 }
186
187 let _ = CloseHandle(h);
188
189 Some(get_proc_name(&process.szExeFile))
190 }
191}
192
193/// Retrieves a snapshot of all running processes in the system.
194///
195/// This function creates a snapshot of all processes using the Windows ToolHelp API.
196/// If successful, it returns a `Tasklist` struct containing process information.
197/// If any error occurs during snapshot creation or process enumeration,
198/// it returns an error message as a string.
199///
200/// # Examples
201/// ```rust
202/// use tasklist;
203/// match tasklist::tasklist() {
204/// Ok(tasklist) => println!("{:?}", tasklist),
205/// Err(e) => eprintln!("Error: {}", e),
206/// }
207/// ```
208///
209/// # Returns
210/// - `Ok(Tasklist)`: A Tasklist iterator containing process information
211/// - `Err(String)`: An error message indicating the reason for the failure
212#[cfg(any(windows, doc))]
213pub fn tasklist() -> Result<Tasklist, String> {
214 Tasklist::new()
215}
216
217///get the proc name by windows `[CHAR;260]` , retun the `String` name for human.
218#[cfg(any(windows, doc))]
219fn get_proc_name(name: &[u16]) -> String {
220 let s = String::from_utf16_lossy(name);
221 // remove the \0 and space
222 s.trim_end_matches(|c: char| c == '\0' || c.is_whitespace()).to_string()
223}
224
225#[cfg(test)]
226mod tests {
227 use super::*;
228
229 #[test]
230 fn test_get_proc_name_basic() {
231 let input = [99u16, 109u16, 100u16, 46u16, 101u16, 120u16, 101u16, 0u16]; // "cmd.exe\0"
232 assert_eq!(get_proc_name(&input), "cmd.exe");
233 }
234
235 #[test]
236 fn test_get_proc_name_with_spaces() {
237 let input = [110u16, 111u16, 116u16, 101u16, 112u16, 97u16, 100u16, 46u16, 101u16, 120u16, 101u16, 0u16, 32u16]; // "notepad.exe\0 "
238 assert_eq!(get_proc_name(&input), "notepad.exe");
239 }
240}
241
242/// enbale the debug privilege for your program , it return a `bool` to show if it success.
243/// ```
244/// println!("open the debug priv{:?}",tasklist::enable_debug_priv());
245/// ```
246pub fn enable_debug_priv() -> bool {
247 use std::mem::size_of;
248 use std::ptr::null_mut;
249 use windows::core::PCSTR;
250 use windows::Win32::Foundation::{ HANDLE, LUID};
251 use windows::Win32::Security::{
252 AdjustTokenPrivileges, LookupPrivilegeValueA, LUID_AND_ATTRIBUTES, SE_PRIVILEGE_ENABLED,
253 TOKEN_ADJUST_PRIVILEGES, TOKEN_PRIVILEGES, TOKEN_QUERY,
254 };
255 use windows::Win32::System::Threading::GetCurrentProcess;
256 use windows::Win32::System::Threading::OpenProcessToken;
257
258 unsafe {
259 let mut h = HANDLE(0 as _);
260 if OpenProcessToken(
261 GetCurrentProcess(),
262 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
263 &mut h,
264 ).is_err() {
265 return false;
266 }
267
268 let token = TokenHandle(h);
269
270 let mut tp = TOKEN_PRIVILEGES {
271 PrivilegeCount: 1,
272 Privileges: [LUID_AND_ATTRIBUTES {
273 Luid: LUID { LowPart: 0, HighPart: 0 },
274 Attributes: SE_PRIVILEGE_ENABLED,
275 }],
276 };
277
278 let privilege = "SeDebugPrivilege\0";
279 if LookupPrivilegeValueA(
280 PCSTR(null_mut()),
281 PCSTR(privilege.as_ptr()),
282 &mut tp.Privileges[0].Luid,
283 ).is_err() {
284 return false;
285 }
286
287 AdjustTokenPrivileges(
288 token.0,
289 false,
290 Some(&mut tp),
291 size_of::<TOKEN_PRIVILEGES>() as _,
292 None,
293 None,
294 ).is_ok()
295 }
296}
297
298/// Terminates a process by its process ID.
299///
300/// This function attempts to terminate the specified process using Windows API.
301/// It returns a `Result` indicating success or failure with detailed error message.
302///
303/// # Safety
304/// This function is unsafe because it works with raw Windows handles.
305///
306/// # Arguments
307/// * `pid` - The process ID to terminate
308///
309/// # Returns
310/// - `Ok(())` - Process was successfully terminated
311/// - `Err(String)` - Error message describing the failure
312///
313/// # Examples
314/// ```
315/// match tasklist::kill(1234) {
316/// Ok(()) => println!("Process terminated successfully"),
317/// Err(e) => eprintln!("Failed to terminate process: {}", e),
318/// }
319/// ```
320pub fn kill(pid: u32) -> Result<(), String> {
321 use windows::Win32::System::Threading::{OpenProcess, TerminateProcess, PROCESS_TERMINATE};
322
323 unsafe{
324 let h = match OpenProcess(PROCESS_TERMINATE, false, pid) {
325 Ok(h) => ProcessHandle(h),
326 Err(e) => return Err(format!("Failed to open process {}: {}", pid, e)),
327 };
328
329 match TerminateProcess(h.0, 0) {
330 Ok(_) => Ok(()),
331 Err(e) => Err(format!("Failed to terminate process {}: {}", pid, e)),
332 }
333 }
334}
335//load infos::info
336pub mod infos;
337#[doc(inline)]
338pub use infos::info;
339#[doc(inline)]
340pub use infos::info::*;
341#[doc(inline)]
342pub use infos::{IoCounter, MemoryCounter, Process, Tasklist};
343mod windows_wrap;
344use windows_wrap::{ProcessHandle,SnapshotHandle, TokenHandle};