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

如何通过Rust获取Windows活动资源管理器中选中文件的路径?

获取活动Windows资源管理器窗口中选中文件的路径(Rust实现)

原代码问题说明

原代码中GetWindowModuleFileNameA无法正确获取资源管理器的进程路径——该函数仅能获取调用进程自身或其拥有窗口的模块路径,而资源管理器的窗口结构特殊,不属于调用进程,因此返回空或错误路径。

解决方案实现

要实现需求,需要分两步:验证当前前台窗口是资源管理器,再通过COM接口IShellFolderViewDual2获取选中文件路径。

1. Cargo依赖配置

确保Cargo.toml中包含所需的windows-rs功能:

[dependencies]
windows = { version = "0.52", features = [
    "Win32_Foundation",
    "Win32_UI_WindowsAndMessaging",
    "Win32_System_Threading",
    "Win32_System_ProcessStatus",
    "Win32_Shell",
    "Win32_System_Com",
    "Win32_System_Ole",
] }

2. 完整代码实现

use std::{thread, time};
use windows::{
    core::{Interface, Result, GUID, HSTRING},
    Win32::{
        Foundation::{CloseHandle, BOOL, HINSTANCE, HWND, LPARAM, LRESULT, WPARAM},
        System::{
            Com::{CoInitializeEx, COINIT_APARTMENTTHREADED},
            Ole::{IDispatch, Variant},
            ProcessStatus::GetModuleFileNameExA,
            Threading::{OpenProcess, PROCESS_QUERY_INFORMATION, PROCESS_VM_READ},
        },
        UI::WindowsAndMessaging::{GetForegroundWindow, GetWindowThreadProcessId, SendMessageA, WM_GETOBJECT},
    },
};

// IShellFolderViewDual2的GUID
const IID_IShellFolderViewDual2: GUID = GUID::from_u128(0x00020430_0000_0000_c000_000000000046);

fn get_process_path(hwnd: HWND) -> Option<String> {
    let mut pid = 0;
    unsafe { GetWindowThreadProcessId(hwnd, &mut pid) };
    if pid == 0 {
        return None;
    }

    let process_handle = unsafe {
        OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, BOOL(0), pid)
    };
    if process_handle.is_invalid() {
        return None;
    }

    let mut buffer = [0u8; 260];
    let len = unsafe {
        GetModuleFileNameExA(process_handle, HINSTANCE(0), &mut buffer)
    };
    unsafe { CloseHandle(process_handle) };

    if len == 0 {
        None
    } else {
        String::from_utf8_lossy(&buffer[..len as usize]).into_owned()
    }
}

fn get_selected_items(hwnd: HWND) -> Result<Vec<String>> {
    // 初始化COM环境
    unsafe { CoInitializeEx(std::ptr::null_mut(), COINIT_APARTMENTTHREADED)? };

    // 通过WM_GETOBJECT消息获取IShellFolderViewDual2接口
    let result = unsafe {
        SendMessageA(hwnd, WM_GETOBJECT, WPARAM(0), LPARAM(IID_IShellFolderViewDual2.as_ptr() as isize))
    };

    if result == LRESULT(0) {
        return Err(windows::core::Error::from_win32());
    }

    // 将返回值转换为IDispatch,再查询目标接口
    let dispatch: IDispatch = unsafe { Interface::from_raw(result as *mut _) };
    let shell_folder_view: windows::Win32::Shell::IShellFolderViewDual2 = dispatch.cast()?;

    // 获取选中项集合
    let items = shell_folder_view.SelectedItems()?;
    let count = items.Count()?;

    let mut paths = Vec::new();
    for i in 1..=count {
        let item = items.Item(&Variant::I4(i as i32))?;
        let folder_item: windows::Win32::Shell::IShellFolderItem = item.cast()?;
        let path = folder_item.Path()?;
        paths.push(path.to_string());
    }

    Ok(paths)
}

fn main() -> Result<()> {
    // 等待用户切换到目标资源管理器窗口
    thread::sleep(time::Duration::from_millis(2000));

    let hwnd = unsafe { GetForegroundWindow() };
    if hwnd.is_invalid() {
        println!("无法获取前台窗口");
        return Ok(());
    }

    // 验证是否为资源管理器进程
    match get_process_path(hwnd) {
        Some(path) if path.to_lowercase().ends_with("explorer.exe") => {
            match get_selected_items(hwnd) {
                Ok(paths) => {
                    println!("选中文件路径:");
                    for path in paths {
                        println!("{}", path);
                    }
                }
                Err(e) => println!("获取选中文件失败:{}", e),
            }
        }
        _ => println!("当前前台窗口不是资源管理器"),
    }

    Ok(())
}

关键步骤说明

  • 进程路径验证:通过GetWindowThreadProcessId获取窗口所属进程ID,再用OpenProcess和GetModuleFileNameExA获取进程路径,确保目标窗口属于资源管理器。
  • COM接口调用:
    1. 调用CoInitializeEx初始化COM环境(需单线程公寓模式)。
    2. 通过WM_GETOBJECT消息向资源管理器窗口请求IShellFolderViewDual2接口。
    3. 从返回的IDispatch转换到IShellFolderViewDual2,访问其SelectedItems属性获取选中项集合。
    4. 遍历集合,通过IShellFolderItem的Path方法获取每个文件的完整路径。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 01:15:11