Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【Rust调用Windows API】获取正在运行的全部进程信息

【Rust调用Windows API】获取正在运行的全部进程信息

原创
作者头像
beifengtz
发布于 2024-11-18 02:31:56
发布于 2024-11-18 02:31:56
3180
举报

前言

WIndows API官方文档 提供了C++的调用示例,最近想尝试用Rust去实现,本系列博客记录一下实现过程。

依赖

Rust调用Windows API需要引入依赖winapi,在Cargo.toml中添加依赖

代码语言:shell
AI代码解释
复制
winapi = "0.3.9"

调用不同的API集就需要使用相应的功能features,很好的一个判断方式是你在微软官方文档中看到的是在哪个头文件内,就添加哪个feature,例如本篇文章需要使用 tlhelp32.hprocessthreadsapi.h 那么就将这俩feature添加进去

代码语言:shell
AI代码解释
复制
winapi = { version = "0.3.9", features = ["tlhelp32", "processthreadsapi"] }

实现

大致步骤

  1. 创建进程快照,拿到快照句柄
  2. 遍历快照中的进程(以迭代器的方式实现),得到每个进程的数据
  3. 释放快照句柄

创建快照句柄

创建进程快照需要用到 CreateToolhelp32Snapshot 方法,它在 tlhelp32.h 头文件中定义。

代码语言:rust
AI代码解释
复制
use winapi::um::tlhelp32::{CreateToolhelp32Snapshot, TH32CS_SNAPPROCESS};
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
use winapi::um::errhandlingapi::GetLastError;

/// 保存进程快照并返回进程信息迭代器 `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 是自定义的,为了结构更清晰,这里使用迭代器模式来读取。

如果保存进程快照失败,返回的句柄会是一个无效的值(这里用了两个条件或的关系去判断是否无效,其实任用其一都可以,他们都表示一个“空”内存或“空”指针),使用 GetLastError 方法可以获取错误代码,错误代码对应含义见系统错误代码说明,也可以通过API解析成可读文本,这个后面的文章再介绍,这里先用code简单表示一下。

实现迭代器

Rust中的迭代器模式实现方法这里就不多赘述,你只需要知道实现一个迭代器至少需要 一个迭代元素Item一个实现了Iterator特征的迭代器 就可以了。

迭代元素Item

代码语言:rust
AI代码解释
复制
let vec = vec![1, 2]
for item in vec {
	...
}

上面代码的item就是迭代器中具体的元素,因为进程信息有很多,这里就使用一个结构体来存

代码语言:rust
AI代码解释
复制
use winapi::um::tlhelp32::PROCESSENTRY32;

pub struct ProcessInformation {
    inner: PROCESSENTRY32,
}

这里并没有直接将进程的数据解析之后再存入结构体,而是直接将 PROCESSENTRY32 结构体做一个包装,这里是为了节省不必要的计算,从句柄中直接读取出来的 PROCESSENTRY32 并不是所有信息都是Rust直接可读的,在需要时才解析,并且通过getter方法读取数据更方便以后拓展,下面是ProcessInformation的具体方法实现。

代码语言:rust
AI代码解释
复制
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
        }
    }

    /// 获取进程ID
    pub fn get_pid(&self) -> u32 {
        self.inner.th32ProcessID as u32
    }

    /// 获取进程名
    pub fn get_name(&self) -> String {
        char_arr_to_string(&self.inner.szExeFile)
    }

    /// 获取父进程ID
    pub fn get_parent_pid(&self) -> u32 {
        self.inner.th32ParentProcessID as u32
    }

    /// 获取线程数量
    pub fn get_thread_count(&self) -> usize {
        self.inner.cntThreads as usize
    }

    /// 获取基础优先权值
    pub fn get_priority_base(&self) -> i64 {
        self.inner.pcPriClassBase as i64
    }

    /// 获取优先权类别,如果调用进程没有指定权限可能会获取失败,失败时返回 `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
    }
}

迭代器实现

迭代器中需要保存一些迭代遍历的状态,因此除了前面保存的快照句柄之外还要存储迭代的索引以及释放句柄的状态,迭代器是不可逆的

代码语言:rust
AI代码解释
复制
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,
        }
    }
}

然后就是迭代器的具体实现

代码语言:rust
AI代码解释
复制
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;
        //  读取快照中的第一个进程
        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))
    }
}

上面的代码有几点需要说明一下:

  1. entry在初始化时需要先到一个全0值的内存空间,并不是分配为一个Rust引用空间,这里用 unsafe 方法 std::mem::zeroed()
  2. 在读取进程Entry之前需要先指定内存长度,这里用 size_of::<PROCESSENTRY32>() 来获取并赋值给 entry.dwSize
  3. 遍历时第一个元素需要调用 Process32First读取,后续的使用 Process32Next 读取
  4. 遍历完时记得关闭快照剧本 使用 CloseHandle 接口

特殊情况处理:如果用户并没有迭代完,上面的代码实现可能会出现快照句柄未释放的情况,所以还需要给迭代器实现一个Drop特征,在释放迭代器时释放快照句柄

代码语言:rust
AI代码解释
复制
impl Drop for ProcessInformationIterator {
    fn drop(&mut self) {
        if self.finished {
            return;
        }
        // 释放快照句柄。
        unsafe {
            CloseHandle(self.process_snapshot);
        }
        self.finished = true;
    }
}

代码汇总

我在写的时候放在了自定义的utils::process::win包下面,具体引用路径根据自己的情况调整

mod.rs文件

代码语言:rust
AI代码解释
复制
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文件

代码语言:rust
AI代码解释
复制
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包装实现
pub struct ProcessInformation {
    inner: PROCESSENTRY32,
}

impl ProcessInformation {
    pub(crate) fn new(entry: PROCESSENTRY32) -> ProcessInformation {
        ProcessInformation {
            inner: entry
        }
    }

    /// 获取进程ID
    pub fn get_pid(&self) -> u32 {
        self.inner.th32ProcessID as u32
    }

    /// 获取进程名
    pub fn get_name(&self) -> String {
        char_arr_to_string(&self.inner.szExeFile)
    }

    /// 获取父进程ID
    pub fn get_parent_pid(&self) -> u32 {
        self.inner.th32ParentProcessID as u32
    }

    /// 获取线程数量
    pub fn get_thread_count(&self) -> usize {
        self.inner.cntThreads as usize
    }

    /// 获取基础优先权值
    pub fn get_priority_base(&self) -> i64 {
        self.inner.pcPriClassBase as i64
    }

    /// 获取优先权类别,如果调用进程没有指定权限可能会获取失败,失败时返回 `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;
        //  读取快照中的第一个进程
        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))
    }
}

测试

测试代码

代码语言:rust
AI代码解释
复制
#[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)
    }
}

结果

代码语言:shell
AI代码解释
复制
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)

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
3D卷积神经网络
首先,我们先参考Tensorflow深度学习算法整理 中卷积神经网络回忆一下2D卷积。
算法之名
2022/05/06
3K0
3D卷积神经网络
你知道Deeplab那些事儿吗?
DeepLab系列论文一共有四篇,分别对应DeepLab V1,DeepLab V2,DeepLab V3,DeepLab V3+。
灿视学长
2021/05/28
8120
图像分割之DeepLab v3+
from PIL import Image import math import torch import torch.nn as nn import torch.nn.functional as F
烤粽子
2021/07/21
4190
PyTorch—torchvision.models导入预训练模型—残差网络代码讲解
PyTorch框架中torchvision模块下有:torchvision.datasets、torchvision.models、torchvision.transforms这3个子包。 关于详情请参考官网: http://pytorch.org/docs/master/torchvision/index.html。 具体代码可以参考github: https://github.com/pytorch/vision/tree/master/torchvision。
全栈程序员站长
2022/09/12
1.7K0
PyTorch—torchvision.models导入预训练模型—残差网络代码讲解
【最强ResNet改进系列】Res2Net:一种新的多尺度网络结构,性能提升显著
【导读】2020年,在各大CV顶会上又出现了许多基于ResNet改进的工作,比如:Res2Net,ResNeSt,IResNet,SCNet等等。为了更好的了解ResNet整个体系脉络的发展,我们开设了一个最强ResNet改进系列专题,主要为大家介绍2020年最新发表在顶会顶刊上基于ResNet改进的论文,这些论文的创新点很值得参考借鉴!本文是【最强ResNet改进系列】第一篇文章,本文我们将着重讲解Res2Net,该论文已被TPAMI2020录用,另外ResNeSt的论文解读见:【CV中的注意力机制】史上最强"ResNet"变体--ResNeSt,下一篇我们将直接来讲解IResNet
深度学习技术前沿公众号博主
2020/08/11
10.6K0
通过和resnet18和resnet50理解PyTorch的ResNet模块
resnet和resnext的框架基本相同的,这里先学习下resnet的构建,感觉高度模块化,很方便。本文算是对 PyTorch源码解读之torchvision.modelsResNet代码的详细理解,另外,强烈推荐这位大神的PyTorch的教程!
全栈程序员站长
2022/09/01
1.7K0
通过和resnet18和resnet50理解PyTorch的ResNet模块
轻松学Pytorch-全卷积神经网络实现表情识别
我又又一周没有更新这个系列文章了,但是我说过我会继续坚持更新下去的,今天给大家更新了一篇如何使用残差Block构建全卷积神经网络实现图像分类,对的,你没有看错就是基于全卷积神经网络实现人脸表情图像的识别,其中数据集一部分来自CK+,更多的是我自己使用OpenVINO的表情识别模型来自动标注的,总数大致有5000张的表情图像。
OpenCV学堂
2020/07/08
1.2K0
『深度概念』原理图解代码FPN Feature Pyramid Networks
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
小宋是呢
2019/12/02
2.5K0
PyTorch源码解读之torchvision.models「建议收藏」
PyTorch框架中有一个非常重要且好用的包:torchvision,该包主要由3个子包组成,分别是:torchvision.datasets、torchvision.models、torchvision.transforms。这3个子包的具体介绍可以参考官网:http://pytorch.org/docs/master/torchvision/index.html。具体代码可以参考github:https://github.com/pytorch/vision/tree/master/torchvision。
全栈程序员站长
2022/09/07
9270
[源码解析] PyTorch 分布式(18) --- 使用 RPC 的分布式管道并行
在前面的文章之中,我们已经学习了PyTorch 分布式的基本模块,接下来我们通过几篇文章来看看如何把这些模块应用到实践之中,顺便把PyTorch分布式逻辑整体梳理一下。本文介绍如何使用 RPC 来完成分布式管道并行。
罗西的思考
2021/12/21
8170
[源码解析] PyTorch 分布式(18) --- 使用 RPC 的分布式管道并行
明月深度学习实践004:ResNet网络结构学习
ResNet可谓大名鼎鼎了,一直遵循拿来主义,没有好好去学习它,当然,作为一个提出来快五年的网络结构,已经有太多人写过它了,不好下笔。
明月AI
2021/10/28
1.2K0
明月深度学习实践004:ResNet网络结构学习
Pytorch预训练模型以及修改
pytorch中自带几种常用的深度学习网络预训练模型,torchvision.models包中包含alexnet、densenet、inception、resnet、squeezenet、vgg等常用网络结构,并且提供了预训练模型,可通过调用来读取网络结构和预训练模型(模型参数)。往往为了加快学习进度,训练的初期直接加载pretrain模型中预先训练好的参数。加载model如下所示:
狼啸风云
2020/05/06
20.6K0
里程碑式成果Faster RCNN复现难?我们试了一下 | 附完整代码
【导读】2019年以来,除各AI 大厂私有网络范围外,MaskRCNN,CascadeRCNN 成为了支撑很多业务得以开展的基础,而以 Faster RCNN 为基础去复现其他的检测网络既省时又省力,也算得上是里程碑性成果了。因此本文主要以简洁易懂的文字复现了 Resnet - Faster R-CNN 。
AI科技大本营
2019/08/23
2.2K0
里程碑式成果Faster RCNN复现难?我们试了一下 | 附完整代码
libtorch-resnet18
与大家分享一下自己在学习使用libtorch搭建神经网络时学到的一些心得和例子,记录下来供大家参考 首先我们要参考着pytorch版的resnet来搭建,这样我们可以省去不必要的麻烦,上代码: 1、首先是pytorch版残差模块
全栈程序员站长
2022/08/31
6190
FPN(特征图金字塔网络)理论基础与具体实现
论文地址:Feature Pyramid Networks for Object Detection
全栈程序员站长
2022/09/06
1.1K0
FPN(特征图金字塔网络)理论基础与具体实现
深度学习算法优化系列八 | VGG,ResNet,DenseNe模型剪枝代码实战
具体原理已经讲过了,见上回的推文。深度学习算法优化系列七 | ICCV 2017的一篇模型剪枝论文,也是2019年众多开源剪枝项目的理论基础 。这篇文章是从源码实战的角度来解释模型剪枝,源码来自:https://github.com/Eric-mingjie/network-slimming 。我这里主要是结合源码来分析每个模型的具体剪枝过程,希望能给你剪枝自己的模型一些启发。
BBuf
2020/02/12
2.4K0
深度学习算法优化系列八 | VGG,ResNet,DenseNe模型剪枝代码实战
深度学习算法中的 时空卷积网络(Spatio-Temporal Convolutional Networks)
随着深度学习的快速发展,传统的卷积神经网络(Convolutional Neural Networks, CNNs)在计算机视觉领域取得了巨大的成功。然而,对于一些涉及到时序和空间信息的任务,如视频分析、动作识别和人体姿态估计等,传统的CNNs存在一定的局限性。为了有效地处理这些时空信息,研究人员提出了一种新型的卷积神经网络模型,即时空卷积网络(Spatio-Temporal Convolutional Networks)。
大盘鸡拌面
2023/09/21
2.2K0
【论文笔记】Improved Residual Networks for Image and Video Recognition(ResNet新变体:IResNet)
github地址:https://github.com/iduta/iresnet
西西嘛呦
2020/08/26
9200
【论文笔记】Improved Residual Networks for Image and Video Recognition(ResNet新变体:IResNet)
项目笔记 LUNA16-DeepLung:(二)肺结节检测
在前面进行了肺结节数据的预处理之后,接下来开始进入肺结节检测环节。首先附上该项目的Github链接:https://github.com/Minerva-J/DeepLung。
Minerva
2020/05/25
3.7K5
Pytorch搭建DenseNet[通俗易懂]
首先回顾一下DenseNet的结构,DenseNet的每一层都都与前面层相连,实现了特征重用。
全栈程序员站长
2022/11/10
5260
Pytorch搭建DenseNet[通俗易懂]
推荐阅读
相关推荐
3D卷积神经网络
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档