You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Rust中获取所有可见窗口对应的进程文件名?

问题分析与修复方案

核心错误:错误获取进程ID

你的调用代码中,GetWindowThreadProcessId的使用完全错误:该函数返回值是窗口所属的线程ID,而进程ID需要通过第二个指针参数输出。你传入ptr::null_mut()导致根本没拿到正确的进程ID,反而把线程ID传给了get_file_name_from_process_id,自然无法打开进程,返回None。

修复后的调用代码

// 正确获取进程ID
let mut pid = 0;
GetWindowThreadProcessId(hwnd, &mut pid);
let file_name: String = get_file_name_from_process_id(pid).unwrap_or("default".to_string());

修复get_file_name_from_process_id函数的其他问题

除了进程ID的错误,原函数还有两个关键问题:

  1. 缓冲区初始化错误:Vec::with_capacity仅预留内存但未设置实际长度,导致WinAPI函数无法写入数据
  2. 权限问题:部分系统进程无法用PROCESS_QUERY_INFORMATION打开,建议使用更宽松的PROCESS_QUERY_LIMITED_INFORMATION权限

修复后的函数代码:

use std::ffi::{OsString, OsStr};
use std::os::windows::ffi::OsStringExt;
use std::path::Path;
use std::ptr;
use winapi::um::handleapi::CloseHandle;
use winapi::um::processthreadsapi::{OpenProcess, GetWindowThreadProcessId};
use winapi::um::psapi::QueryFullProcessImageNameW;
use winapi::um::winnt::PROCESS_QUERY_LIMITED_INFORMATION;

unsafe fn get_file_name_from_process_id(pid: u32) -> Option<String> {
    // 使用兼容性更好的PROCESS_QUERY_LIMITED_INFORMATION权限
    let process_handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, 0, pid);
    if process_handle.is_null() {
        return None;
    }

    // 第一次调用获取所需缓冲区大小
    let mut size: u32 = 0;
    if QueryFullProcessImageNameW(process_handle, 0, ptr::null_mut(), &mut size) == 0 {
        let err = std::io::Error::last_os_error();
        // ERROR_INSUFFICIENT_BUFFER是预期错误,说明需要分配缓冲区
        if err.raw_os_error() != Some(0x7A) {
            CloseHandle(process_handle);
            return None;
        }
    }

    // 初始化足够大小的缓冲区(包含终止符)
    let mut buffer = vec![0u16; size as usize];

    // 第二次调用获取进程路径
    if QueryFullProcessImageNameW(process_handle, 0, buffer.as_mut_ptr(), &mut size) == 0 {
        CloseHandle(process_handle);
        return None;
    }

    // 转换为OsString并截断到实际有效长度
    let process_path = OsString::from_wide(&buffer[..size as usize]);

    // 提取文件名
    let file_name = process_path.as_os_str()
        .and_then(OsStr::to_str)
        .and_then(|s| Path::new(s).file_name())
        .and_then(|s| s.to_str())
        .map(|s| s.to_string());

    CloseHandle(process_handle);
    file_name
}

额外注意事项

  • 对于csrss.exe、wininit.exe等系统核心进程,即使使用管理员权限也可能无法获取路径,这是Windows的安全限制
  • 必须确保关闭进程句柄,避免资源泄漏
  • 可取消注释错误打印语句(代码中被注释的部分),帮助排查特定进程的获取失败原因

内容的提问来源于stack exchange,提问作者m0ke0

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 05:25:09