I’m making some code to extract the 64x64px variant of the icon in an exe file.
The following code does work, but it outputs a grayscale 16x16px image.
I’m still a bit new to rust so please excuse the bad code.
I’m using winapi
version 0.3.9 with the features: “winuser”, “shellapi”.
use std::ffi::CString;
use std::ptr;
use iced::widget::image::Handle;
use winapi::shared::minwindef::DWORD;
use winapi::um::shellapi::ExtractIconA;
use winapi::shared::windef::HICON;
use winapi::um::wingdi::{CreateDIBSection, DeleteObject, GetDIBits, BITMAPINFO, BITMAPINFOHEADER, BI_RGB, DIB_RGB_COLORS, RGBQUAD};
use winapi::um::winuser::{DestroyIcon, GetIconInfo};
use winapi::um::wingdi::{CreateCompatibleDC, SelectObject};
pub fn exe_icon_to_vec_u8(path: &str) -> Result<Handle, String> {
let c_path = CString::new(path).map_err(|_| "Invalid path".to_string())?;
let hicon: HICON = unsafe { ExtractIconA(ptr::null_mut(), c_path.as_ptr(), 0) };
if hicon.is_null() {
return Err("Failed to extract icon".into());
}
let mut icon_info = unsafe { std::mem::zeroed() };
if unsafe { GetIconInfo(hicon, &mut icon_info) } == 0 {
unsafe { DestroyIcon(hicon) };
return Err("Failed to get icon info".into());
}
let mut bmp_info = BITMAPINFO {
bmiHeader: BITMAPINFOHEADER {
biSize: std::mem::size_of::<BITMAPINFOHEADER>() as DWORD,
biWidth: 64, biHeight: -64, biPlanes: 1, biBitCount: 32,
biCompression: BI_RGB, biSizeImage: 0, biXPelsPerMeter: 0,
biYPelsPerMeter: 0, biClrUsed: 0, biClrImportant: 0,
}, bmiColors: [RGBQUAD { rgbBlue: 0, rgbGreen: 0, rgbRed: 0, rgbReserved: 0 }; 1],
};
let mut pixels: Vec<u8> = vec![0; 64 * 64 * 4];
let hdc = unsafe { CreateCompatibleDC(ptr::null_mut()) };
if hdc.is_null() {
unsafe {
DestroyIcon(hicon);
}
return Err("Failed to create compatible DC".into());
}
let hbitmap = unsafe {
CreateDIBSection(
hdc,
&mut bmp_info,
DIB_RGB_COLORS,
&mut pixels.as_mut_ptr() as *mut _ as *mut _,
ptr::null_mut(),
0,
)
};
if hbitmap.is_null() {
unsafe {
DeleteObject(icon_info.hbmColor as _);
DeleteObject(icon_info.hbmMask as _);
DestroyIcon(hicon);
}
return Err("Failed to create DIB section".into());
}
unsafe {
SelectObject(hdc, hbitmap as _);
GetDIBits(
hdc,
icon_info.hbmColor,
0,
64,
pixels.as_mut_ptr() as *mut _,
&mut bmp_info,
DIB_RGB_COLORS,
);
DeleteObject(hbitmap as _);
DeleteObject(icon_info.hbmColor as _);
DeleteObject(icon_info.hbmMask as _);
DestroyIcon(hicon);
}
Ok(Handle::from_pixels(64, 64, pixels))
}
I tried to find some cargo packages that do this but with no success.
New contributor
Barnabás is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.