Skip to main content

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};