Rust調(diào)用Windows API 如何獲取正在運(yùn)行的全部進(jìn)程信息
前言
WIndows API官方文檔 提供了C++的調(diào)用示例,最近想嘗試用Rust去實(shí)現(xiàn),本系列博客記錄一下實(shí)現(xiàn)過(guò)程。
依賴(lài)
Rust調(diào)用Windows API需要引入依賴(lài)winapi,在Cargo.toml中添加依賴(lài)
winapi = "0.3.9"
調(diào)用不同的API集就需要使用相應(yīng)的功能features,很好的一個(gè)判斷方式是你在微軟官方文檔中看到的是在哪個(gè)頭文件內(nèi),就添加哪個(gè)feature,例如本篇文章需要使用 tlhelp32.h 和 processthreadsapi.h 那么就將這倆feature添加進(jìn)去
winapi = { version = "0.3.9", features = ["tlhelp32", "processthreadsapi"] }實(shí)現(xiàn)
大致步驟:
- 創(chuàng)建進(jìn)程快照,拿到快照句柄
- 遍歷快照中的進(jìn)程(以迭代器的方式實(shí)現(xiàn)),得到每個(gè)進(jìn)程的數(shù)據(jù)
- 釋放快照句柄
創(chuàng)建快照句柄
創(chuàng)建進(jìn)程快照需要用到 CreateToolhelp32Snapshot 方法,它在 tlhelp32.h 頭文件中定義。
use winapi::um::tlhelp32::{CreateToolhelp32Snapshot, TH32CS_SNAPPROCESS};
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
use winapi::um::errhandlingapi::GetLastError;
/// 保存進(jìn)程快照并返回進(jìn)程信息迭代器 `ProcessInformationIterator`
pub fn list() -> Result<ProcessInformationIterator, String> {
let process_snapshot: HANDLE = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) };
if process_snapshot == INVALID_HANDLE_VALUE || process_snapshot.is_null() {
unsafe {
return Err(format!("Cannot list processes, code: {}", GetLastError()));
}
}
Ok(ProcessInformationIterator::new(process_snapshot))
}代碼中的 ProcessInfomationIterator 是自定義的,為了結(jié)構(gòu)更清晰,這里使用迭代器模式來(lái)讀取。
如果保存進(jìn)程快照失敗,返回的句柄會(huì)是一個(gè)無(wú)效的值(這里用了兩個(gè)條件或的關(guān)系去判斷是否無(wú)效,其實(shí)任用其一都可以,他們都表示一個(gè)“空”內(nèi)存或“空”指針),使用 GetLastError 方法可以獲取錯(cuò)誤代碼,錯(cuò)誤代碼對(duì)應(yīng)含義見(jiàn)系統(tǒng)錯(cuò)誤代碼說(shuō)明,也可以通過(guò)API解析成可讀文本,這個(gè)后面的文章再介紹,這里先用code簡(jiǎn)單表示一下。
實(shí)現(xiàn)迭代器
Rust中的迭代器模式實(shí)現(xiàn)方法這里就不多贅述,你只需要知道實(shí)現(xiàn)一個(gè)迭代器至少需要 一個(gè)迭代元素Item 和 一個(gè)實(shí)現(xiàn)了Iterator特征的迭代器 就可以了。
迭代元素Item
let vec = vec![1, 2]
for item in vec {
...
}上面代碼的item就是迭代器中具體的元素,因?yàn)檫M(jìn)程信息有很多,這里就使用一個(gè)結(jié)構(gòu)體來(lái)存
use winapi::um::tlhelp32::PROCESSENTRY32;
pub struct ProcessInformation {
inner: PROCESSENTRY32,
}這里并沒(méi)有直接將進(jìn)程的數(shù)據(jù)解析之后再存入結(jié)構(gòu)體,而是直接將 PROCESSENTRY32 結(jié)構(gòu)體做一個(gè)包裝,這里是為了節(jié)省不必要的計(jì)算,從句柄中直接讀取出來(lái)的 PROCESSENTRY32 并不是所有信息都是Rust直接可讀的,在需要時(shí)才解析,并且通過(guò)getter方法讀取數(shù)據(jù)更方便以后拓展,下面是ProcessInformation的具體方法實(shí)現(xiàn)。
use winapi::um::processthreadsapi::{GetPriorityClass, OpenProcess};
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::tlhelp32::PROCESSENTRY32;
use winapi::um::winnt::{HANDLE, PROCESS_ALL_ACCESS};
pub(crate) fn char_arr_to_string(chars: &[i8]) -> String {
chars.into_iter().map(|&c| c as u8 as char).collect()
}
impl ProcessInformation {
pub(crate) fn new(entry: PROCESSENTRY32) -> ProcessInformation {
ProcessInformation {
inner: entry
}
}
/// 獲取進(jìn)程ID
pub fn get_pid(&self) -> u32 {
self.inner.th32ProcessID as u32
}
/// 獲取進(jìn)程名
pub fn get_name(&self) -> String {
char_arr_to_string(&self.inner.szExeFile)
}
/// 獲取父進(jìn)程ID
pub fn get_parent_pid(&self) -> u32 {
self.inner.th32ParentProcessID as u32
}
/// 獲取線程數(shù)量
pub fn get_thread_count(&self) -> usize {
self.inner.cntThreads as usize
}
/// 獲取基礎(chǔ)優(yōu)先權(quán)值
pub fn get_priority_base(&self) -> i64 {
self.inner.pcPriClassBase as i64
}
/// 獲取優(yōu)先權(quán)類(lèi)別,如果調(diào)用進(jìn)程沒(méi)有指定權(quán)限可能會(huì)獲取失敗,失敗時(shí)返回 `None`
pub fn get_priority_class(&self) -> Option<i32> {
let mut priority_class = None;
unsafe {
let handle = OpenProcess(PROCESS_ALL_ACCESS, 0, self.inner.th32ProcessID);
if !handle.is_null() {
let class = GetPriorityClass(handle);
CloseHandle(handle);
priority_class = Some(class as i32);
}
}
priority_class
}
}迭代器實(shí)現(xiàn)
迭代器中需要保存一些迭代遍歷的狀態(tài),因此除了前面保存的快照句柄之外還要存儲(chǔ)迭代的索引以及釋放句柄的狀態(tài),迭代器是不可逆的。
use winapi::um::winnt::HANDLE;
pub struct ProcessInformationIterator {
process_snapshot: HANDLE,
index: usize,
finished: bool,
}
impl ProcessInformationIterator {
pub(crate) fn new(process_snapshot: HANDLE) -> ProcessInformationIterator {
ProcessInformationIterator {
process_snapshot,
index: 0,
finished: false,
}
}
}然后就是迭代器的具體實(shí)現(xiàn)
use winapi::um::winnt::HANDLE;
use winapi::um::tlhelp32::{Process32First, Process32Next, PROCESSENTRY32};
use winapi::um::handleapi::CloseHandle;
impl Iterator for ProcessInformationIterator {
type Item = ProcessInformation;
fn next(&mut self) -> Option<Self::Item> {
if self.finished {
return None;
}
self.index += 1;
let mut entry: PROCESSENTRY32 = unsafe { std::mem::zeroed() };
entry.dwSize = size_of::<PROCESSENTRY32>() as u32;
// 讀取快照中的第一個(gè)進(jìn)程
let res = unsafe {
if self.index == 1 {
Process32First(self.process_snapshot, &mut entry)
} else {
Process32Next(self.process_snapshot, &mut entry)
}
};
if res == 0 {
unsafe {
CloseHandle(self.process_snapshot);
}
self.finished = true;
return None;
}
Some(ProcessInformation::new(entry))
}
}上面的代碼有幾點(diǎn)需要說(shuō)明一下:
- entry在初始化時(shí)需要先到一個(gè)全0值的內(nèi)存空間,并不是分配為一個(gè)Rust引用空間,這里用 unsafe 方法
std::mem::zeroed() - 在讀取進(jìn)程Entry之前需要先指定內(nèi)存長(zhǎng)度,這里用
size_of::<PROCESSENTRY32>()來(lái)獲取并賦值給entry.dwSize - 遍歷時(shí)第一個(gè)元素需要調(diào)用
Process32First讀取,后續(xù)的使用Process32Next讀取 - 遍歷完時(shí)記得關(guān)閉快照劇本 使用
CloseHandle接口
特殊情況處理:如果用戶(hù)并沒(méi)有迭代完,上面的代碼實(shí)現(xiàn)可能會(huì)出現(xiàn)快照句柄未釋放的情況,所以還需要給迭代器實(shí)現(xiàn)一個(gè)Drop特征,在釋放迭代器時(shí)釋放快照句柄
impl Drop for ProcessInformationIterator {
fn drop(&mut self) {
if self.finished {
return;
}
// 釋放快照句柄。
unsafe {
CloseHandle(self.process_snapshot);
}
self.finished = true;
}
}代碼匯總
我在寫(xiě)的時(shí)候放在了自定義的utils::process::win包下面,具體引用路徑根據(jù)自己的情況調(diào)整
mod.rs文件
use crate::utils::process::win::process_information::ProcessInformationIterator;
use winapi::um::tlhelp32::{CreateToolhelp32Snapshot, TH32CS_SNAPPROCESS};
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
use winapi::um::winnt::HANDLE;
pub mod process_information;
pub fn list() -> Result<ProcessInformationIterator, String> {
let process_snapshot: HANDLE = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) };
if process_snapshot == INVALID_HANDLE_VALUE || process_snapshot.is_null() {
unsafe {
return Err(format!("Cannot list processes, code: {}", GetLastError()));
}
}
Ok(ProcessInformationIterator::new(process_snapshot))
}
pub(crate) fn char_arr_to_string(chars: &[i8]) -> String {
chars.into_iter().map(|&c| c as u8 as char).collect()
}process_information.rs文件
use crate::utils::process::win::char_arr_to_string;
use crate::utils::process::win::process_module::ProcessModuleIterator;
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::handleapi::CloseHandle;
use winapi::um::processthreadsapi::{GetPriorityClass, OpenProcess};
use winapi::um::tlhelp32::{Process32First, Process32Next, PROCESSENTRY32};
use winapi::um::winnt::{HANDLE, PROCESS_ALL_ACCESS};
/// [PROCESSENTRY32](https://learn.microsoft.com/zh-cn/windows/win32/api/tlhelp32/ns-tlhelp32-processentry32) 的Rust包裝實(shí)現(xiàn)
pub struct ProcessInformation {
inner: PROCESSENTRY32,
}
impl ProcessInformation {
pub(crate) fn new(entry: PROCESSENTRY32) -> ProcessInformation {
ProcessInformation {
inner: entry
}
}
/// 獲取進(jìn)程ID
pub fn get_pid(&self) -> u32 {
self.inner.th32ProcessID as u32
}
/// 獲取進(jìn)程名
pub fn get_name(&self) -> String {
char_arr_to_string(&self.inner.szExeFile)
}
/// 獲取父進(jìn)程ID
pub fn get_parent_pid(&self) -> u32 {
self.inner.th32ParentProcessID as u32
}
/// 獲取線程數(shù)量
pub fn get_thread_count(&self) -> usize {
self.inner.cntThreads as usize
}
/// 獲取基礎(chǔ)優(yōu)先權(quán)值
pub fn get_priority_base(&self) -> i64 {
self.inner.pcPriClassBase as i64
}
/// 獲取優(yōu)先權(quán)類(lèi)別,如果調(diào)用進(jìn)程沒(méi)有指定權(quán)限可能會(huì)獲取失敗,失敗時(shí)返回 `None`
pub fn get_priority_class(&self) -> Option<i32> {
let mut priority_class = None;
unsafe {
let handle = OpenProcess(PROCESS_ALL_ACCESS, 0, self.inner.th32ProcessID);
if !handle.is_null() {
let class = GetPriorityClass(handle);
CloseHandle(handle);
priority_class = Some(class as i32);
}
}
priority_class
}
}
pub struct ProcessInformationIterator {
process_snapshot: HANDLE,
index: usize,
finished: bool,
}
impl ProcessInformationIterator {
pub(crate) fn new(process_snapshot: HANDLE) -> ProcessInformationIterator {
ProcessInformationIterator {
process_snapshot,
index: 0,
finished: false,
}
}
}
impl Drop for ProcessInformationIterator {
fn drop(&mut self) {
if self.finished {
return;
}
// 釋放快照句柄。
unsafe {
CloseHandle(self.process_snapshot);
}
self.finished = true;
}
}
impl Iterator for ProcessInformationIterator {
type Item = ProcessInformation;
fn next(&mut self) -> Option<Self::Item> {
if self.finished {
return None;
}
self.index += 1;
let mut entry: PROCESSENTRY32 = unsafe { std::mem::zeroed() };
entry.dwSize = size_of::<PROCESSENTRY32>() as u32;
// 讀取快照中的第一個(gè)進(jìn)程
let res = unsafe {
if self.index == 1 {
Process32First(self.process_snapshot, &mut entry)
} else {
Process32Next(self.process_snapshot, &mut entry)
}
};
if res == 0 {
unsafe {
CloseHandle(self.process_snapshot);
}
self.finished = true;
return None;
}
Some(ProcessInformation::new(entry))
}
}測(cè)試
測(cè)試代碼
#[test]
pub fn test_list() {
println!("PID\tName\tParent PID\tThreads\tPriority Base\tPriority Class");
let iter = list().unwrap();
for process in iter {
let pid = process.get_pid();
let name = process.get_name();
let parent_pid = process.get_parent_pid();
let thread_count = process.get_thread_count();
let priority_base = process.get_priority_base();
let priority_class = process.get_priority_class();
println!("{}\t{}\t{}\t{}\t{}\t{:?}", pid, name, parent_pid, thread_count, priority_base, priority_class)
}
}結(jié)果
PID Name Parent PID Threads Priority Base Priority Class 0 [System Process] 0 6 0 None 4 System 0 236 8 None 64 Secure System 4 0 8 None 132 Registry 4 4 8 None 504 smss.exe 4 2 11 None 728 csrss.exe 712 11 13 None 824 wininit.exe 712 1 13 None 832 csrss.exe 816 15 13 None ... 12624 chrome.exe 12148 19 8 Some(32) 16352 chrome.exe 12148 18 4 Some(64) 14904 chrome.exe 12148 17 4 Some(64) 14672 wslinstaller.exe 892 2 8 None 11160 chrome.exe 12148 20 4 Some(64) 18048 chrome.exe 12148 19 4 Some(64) 5452 chrome.exe 12148 14 4 Some(64) 14468 svchost.exe 892 3 8 None 18060 chrome.exe 12148 14 4 Some(64) 17748 dllhost.exe 688 8 8 Some(32) 16084 vctip.exe 16648 27 8 Some(32) 9008 OpenConsole.exe 10644 6 8 Some(32) 15516 cargo.exe 10644 4 8 Some(32) 11312 cargo.exe 15516 4 8 Some(32)
到此這篇關(guān)于Rust調(diào)用Windows API 獲取正在運(yùn)行的全部進(jìn)程信息的文章就介紹到這了,更多相關(guān)Rust調(diào)用Windows API 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Rust 數(shù)據(jù)分析利器polars用法詳解
這篇文章主要介紹了Rust 數(shù)據(jù)分析利器polars用法詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-08-08
Rust用宏實(shí)現(xiàn)參數(shù)可變的函數(shù)的實(shí)現(xiàn)示例
本文主要介紹了Rust用宏實(shí)現(xiàn)參數(shù)可變的函數(shù)的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-03-03
rust多個(gè)mod文件引用和文件夾mod使用注意事項(xiàng)小結(jié)
在 Rust 項(xiàng)目中,可以使用 mod 關(guān)鍵字將一個(gè)文件夾或一個(gè) rs 文件作為一個(gè)模塊引入到當(dāng)前文件中,本文給大家介紹rust多個(gè)mod文件引用和文件夾mod使用注意事項(xiàng)小結(jié),感興趣的朋友跟隨小編一起看看吧2024-03-03
vscode搭建rust開(kāi)發(fā)環(huán)境的圖文教程
Rust 是一種系統(tǒng)編程語(yǔ)言,它專(zhuān)注于內(nèi)存安全、并發(fā)和性能,本文主要介紹了vscode搭建rust開(kāi)發(fā)環(huán)境的圖文教程,具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03
rust使用Atomic創(chuàng)建全局變量和使用操作方法
從 Rust1.34 版本后,就正式支持原子類(lèi)型,原子指的是一系列不可被 CPU 上下文交換的機(jī)器指令,這些指令組合在一起就形成了原子操作,這篇文章主要介紹了rust使用Atomic創(chuàng)建全局變量和使用,需要的朋友可以參考下2024-05-05

