如何在Windows系统中使用Rust获取任意文件或目录的ICO图标?
在Windows系统中用Rust获取文件/目录ICO图标的方法
方法一:调用Windows Shell API(微软官方windows crate)
用微软维护的windows crate直接对接Windows API,这是最原生可靠的方式,支持所有文件和目录的图标提取。
- 先在
Cargo.toml里加依赖:
[dependencies] windows = { version = "0.52", features = ["Win32_Shell_Shell32", "Win32_Gdi", "Win32_Foundation", "Win32_System_Com"] }
- 示例代码:
use windows::Win32::Shell::Shell32::{SHGetFileInfoW, SHGFI_ICON, SHGFI_LARGEICON, SHGFI_SMALLICON}; use windows::Win32::Foundation::{PWSTR, HICON}; use windows::Win32::Gdi::{DestroyIcon}; use std::ffi::OsStr; use std::os::windows::ffi::OsStrExt; // 获取文件/目录的图标句柄,large=true返回大图标,false返回小图标 fn get_file_icon(path: &str, large: bool) -> Option<HICON> { // 把路径转成Windows宽字符格式 let wide_path: Vec<u16> = OsStr::new(path) .encode_wide() .chain(std::iter::once(0)) .collect(); let mut file_info = std::mem::zeroed(); let flags = if large { SHGFI_ICON | SHGFI_LARGEICON } else { SHGFI_ICON | SHGFI_SMALLICON }; unsafe { // 调用SHGetFileInfoW获取图标 if SHGetFileInfoW( PWSTR(wide_path.as_ptr()), 0, &mut file_info, std::mem::size_of_val(&file_info) as u32, flags ).is_null() { return None; } Some(file_info.hIcon) } } fn main() { // 示例:获取记事本的大图标 let icon_handle = get_file_icon("C:\\Windows\\notepad.exe", true); if let Some(hicon) = icon_handle { // 这里可以对图标句柄做后续处理,比如转成ICO文件 // 用完一定要销毁句柄,不然会内存泄漏 unsafe { DestroyIcon(hicon); } } }
如果要把图标句柄保存成ICO文件,可以搭配ico crate来处理数据转换,核心逻辑是把HICON里的位图数据提取出来再写入文件。
方法二:用封装好的第三方库ico_extract
不想写复杂的API调用?这个库已经把Windows API的逻辑封装好了,直接调用就能拿图标,适合快速开发。
- 加依赖:
[dependencies] ico_extract = "0.2"
- 示例代码:
use ico_extract::IconExtractor; fn main() { // 提取可执行文件的图标 let exe_extractor = IconExtractor::new("C:\\Windows\\explorer.exe").unwrap(); if let Some(main_icon) = exe_extractor.get_icon(0) { // 保存为ICO文件 main_icon.save_to_file("explorer_icon.ico").unwrap(); } // 提取目录的图标 let dir_extractor = IconExtractor::new("C:\\Users").unwrap(); if let Some(dir_icon) = dir_extractor.get_icon(0) { dir_icon.save_to_file("directory_icon.ico").unwrap(); } }
这个库会自动处理系统分配给目录或普通文件的图标,不用自己操心API细节,缺点是灵活性不如原生调用。
方法三:手动解析PE文件资源(仅适用于可执行文件)
如果只需要处理.exe、.dll这类PE格式文件,而且不想依赖Windows API,可以直接解析文件里的资源段提取图标。用goblin解析PE,ico处理图标格式:
- 加依赖:
[dependencies] goblin = "0.7" ico = "0.2"
- 示例代码:
use goblin::pe::PE; use ico::IconDir; use std::fs::File; use std::io::Read; fn extract_pe_icon(path: &str) -> Option<IconDir> { let mut file = File::open(path).ok()?; let mut buffer = Vec::new(); file.read_to_end(&mut buffer).ok()?; // 解析PE文件结构 let pe = PE::parse(&buffer).ok()?; if let Some(resources) = pe.resources { // 遍历资源表找ICON类型的资源 for entry in resources.entries { if entry.name.to_string_lossy() == "ICON" { let icon_data = &buffer[entry.offset as usize..entry.offset as usize + entry.size as usize]; return IconDir::read(icon_data).ok(); } } } None } fn main() { if let Some(icon_dir) = extract_pe_icon("C:\\Windows\\notepad.exe") { let mut icon_file = File::create("notepad_icon.ico").unwrap(); icon_dir.write(&mut icon_file).unwrap(); } }
注意:这个方法不能提取普通文件或目录的图标,因为这类图标是系统根据文件类型动态分配的,不在文件本身的资源里。
内容的提问来源于stack exchange,提问作者DLillard0
相关产品推荐
相关产品推荐

