2025-08-10 07:54:03 +09:00
|
|
|
|
// Windows Icon Extraction Test
|
|
|
|
|
|
// アイコンを実際に取得してICOファイルとして保存するテスト
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
|
use windows::{
|
|
|
|
|
|
core::*,
|
2025-09-16 23:49:36 +09:00
|
|
|
|
Win32::{Graphics::Gdi::*, Storage::FileSystem::*, UI::Shell::*, UI::WindowsAndMessaging::*},
|
2025-08-10 07:54:03 +09:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
|
unsafe {
|
|
|
|
|
|
println!("Windows Icon Extraction Test");
|
2025-09-16 23:49:36 +09:00
|
|
|
|
|
2025-08-10 07:54:03 +09:00
|
|
|
|
// C:ドライブのアイコンを取得
|
|
|
|
|
|
let drive_path = "C:\\";
|
2025-09-16 23:49:36 +09:00
|
|
|
|
let drive_path_wide: Vec<u16> = drive_path
|
|
|
|
|
|
.encode_utf16()
|
|
|
|
|
|
.chain(std::iter::once(0))
|
|
|
|
|
|
.collect();
|
|
|
|
|
|
|
2025-08-10 07:54:03 +09:00
|
|
|
|
let mut shfi = SHFILEINFOW::default();
|
2025-09-16 23:49:36 +09:00
|
|
|
|
|
2025-08-10 07:54:03 +09:00
|
|
|
|
let result = SHGetFileInfoW(
|
|
|
|
|
|
PCWSTR::from_raw(drive_path_wide.as_ptr()),
|
|
|
|
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
|
|
|
|
Some(&mut shfi),
|
|
|
|
|
|
std::mem::size_of::<SHFILEINFOW>() as u32,
|
|
|
|
|
|
SHGFI_ICON | SHGFI_LARGEICON | SHGFI_USEFILEATTRIBUTES,
|
|
|
|
|
|
);
|
2025-09-16 23:49:36 +09:00
|
|
|
|
|
2025-08-10 07:54:03 +09:00
|
|
|
|
println!("SHGetFileInfoW result: {}", result);
|
2025-09-16 23:49:36 +09:00
|
|
|
|
|
2025-08-10 07:54:03 +09:00
|
|
|
|
if result != 0 && !shfi.hIcon.is_invalid() {
|
|
|
|
|
|
println!("Icon handle obtained!");
|
2025-09-16 23:49:36 +09:00
|
|
|
|
|
2025-08-10 07:54:03 +09:00
|
|
|
|
// アイコン情報を取得
|
|
|
|
|
|
let mut icon_info = ICONINFO::default();
|
|
|
|
|
|
if GetIconInfo(shfi.hIcon, &mut icon_info).is_ok() {
|
|
|
|
|
|
println!("GetIconInfo success!");
|
|
|
|
|
|
println!("fIcon: {}", icon_info.fIcon.as_bool());
|
2025-09-16 23:49:36 +09:00
|
|
|
|
|
2025-08-10 07:54:03 +09:00
|
|
|
|
// ビットマップ情報を取得
|
|
|
|
|
|
if !icon_info.hbmColor.is_invalid() {
|
|
|
|
|
|
println!("Color bitmap handle obtained!");
|
2025-09-16 23:49:36 +09:00
|
|
|
|
|
2025-08-10 07:54:03 +09:00
|
|
|
|
// ビットマップ情報を取得
|
|
|
|
|
|
let mut bitmap = BITMAP::default();
|
|
|
|
|
|
let size = GetObjectW(
|
2025-09-16 23:49:36 +09:00
|
|
|
|
icon_info.hbmColor.into(),
|
2025-08-10 07:54:03 +09:00
|
|
|
|
std::mem::size_of::<BITMAP>() as i32,
|
2025-09-16 23:49:36 +09:00
|
|
|
|
Some(&mut bitmap as *mut _ as *mut _),
|
2025-08-10 07:54:03 +09:00
|
|
|
|
);
|
2025-09-16 23:49:36 +09:00
|
|
|
|
|
2025-08-10 07:54:03 +09:00
|
|
|
|
if size > 0 {
|
|
|
|
|
|
println!("Bitmap info:");
|
|
|
|
|
|
println!(" Width: {}", bitmap.bmWidth);
|
|
|
|
|
|
println!(" Height: {}", bitmap.bmHeight);
|
|
|
|
|
|
println!(" Bits per pixel: {}", bitmap.bmBitsPixel);
|
|
|
|
|
|
println!(" Planes: {}", bitmap.bmPlanes);
|
2025-09-16 23:49:36 +09:00
|
|
|
|
|
2025-08-10 07:54:03 +09:00
|
|
|
|
// ピクセルデータを取得
|
|
|
|
|
|
let pixel_count = (bitmap.bmWidth * bitmap.bmHeight) as usize;
|
|
|
|
|
|
let bytes_per_pixel = (bitmap.bmBitsPixel / 8) as usize;
|
|
|
|
|
|
let mut pixels = vec![0u8; pixel_count * bytes_per_pixel];
|
2025-09-16 23:49:36 +09:00
|
|
|
|
|
2025-08-10 07:54:03 +09:00
|
|
|
|
let copied = GetBitmapBits(
|
|
|
|
|
|
icon_info.hbmColor,
|
|
|
|
|
|
pixels.len() as i32,
|
2025-09-16 23:49:36 +09:00
|
|
|
|
pixels.as_mut_ptr() as *mut _,
|
2025-08-10 07:54:03 +09:00
|
|
|
|
);
|
2025-09-16 23:49:36 +09:00
|
|
|
|
|
2025-08-10 07:54:03 +09:00
|
|
|
|
println!("Copied {} bytes of pixel data", copied);
|
2025-09-16 23:49:36 +09:00
|
|
|
|
|
2025-08-10 07:54:03 +09:00
|
|
|
|
// 簡易的にBMPファイルとして保存
|
|
|
|
|
|
if copied > 0 {
|
2025-09-16 23:49:36 +09:00
|
|
|
|
save_as_bmp(
|
|
|
|
|
|
"c_drive_icon.bmp",
|
|
|
|
|
|
&pixels,
|
|
|
|
|
|
bitmap.bmWidth,
|
|
|
|
|
|
bitmap.bmHeight,
|
|
|
|
|
|
bitmap.bmBitsPixel,
|
|
|
|
|
|
);
|
2025-08-10 07:54:03 +09:00
|
|
|
|
println!("Saved as c_drive_icon.bmp");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-16 23:49:36 +09:00
|
|
|
|
|
2025-08-10 07:54:03 +09:00
|
|
|
|
// ビットマップを削除
|
|
|
|
|
|
let _ = DeleteObject(icon_info.hbmColor.into());
|
|
|
|
|
|
}
|
2025-09-16 23:49:36 +09:00
|
|
|
|
|
2025-08-10 07:54:03 +09:00
|
|
|
|
if !icon_info.hbmMask.is_invalid() {
|
|
|
|
|
|
println!("Mask bitmap handle obtained!");
|
|
|
|
|
|
let _ = DeleteObject(icon_info.hbmMask.into());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-16 23:49:36 +09:00
|
|
|
|
|
2025-08-10 07:54:03 +09:00
|
|
|
|
// アイコンを破棄
|
|
|
|
|
|
let _ = DestroyIcon(shfi.hIcon);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
println!("Failed to get icon");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-16 23:49:36 +09:00
|
|
|
|
|
2025-08-10 07:54:03 +09:00
|
|
|
|
#[cfg(not(windows))]
|
|
|
|
|
|
println!("This test only works on Windows");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
|
fn save_as_bmp(filename: &str, pixels: &[u8], width: i32, height: i32, bits_per_pixel: u16) {
|
|
|
|
|
|
use std::fs::File;
|
|
|
|
|
|
use std::io::Write;
|
2025-09-16 23:49:36 +09:00
|
|
|
|
|
2025-08-10 07:54:03 +09:00
|
|
|
|
// 簡易BMPヘッダー(実際の実装はもっと複雑)
|
|
|
|
|
|
let file_size = 54 + pixels.len() as u32;
|
|
|
|
|
|
let mut file = File::create(filename).unwrap();
|
2025-09-16 23:49:36 +09:00
|
|
|
|
|
2025-08-10 07:54:03 +09:00
|
|
|
|
// BMPファイルヘッダー
|
|
|
|
|
|
file.write_all(b"BM").unwrap(); // マジックナンバー
|
|
|
|
|
|
file.write_all(&file_size.to_le_bytes()).unwrap();
|
|
|
|
|
|
file.write_all(&0u32.to_le_bytes()).unwrap(); // 予約
|
|
|
|
|
|
file.write_all(&54u32.to_le_bytes()).unwrap(); // データオフセット
|
2025-09-16 23:49:36 +09:00
|
|
|
|
|
2025-08-10 07:54:03 +09:00
|
|
|
|
// BMPインフォヘッダー
|
|
|
|
|
|
file.write_all(&40u32.to_le_bytes()).unwrap(); // ヘッダーサイズ
|
|
|
|
|
|
file.write_all(&width.to_le_bytes()).unwrap();
|
|
|
|
|
|
file.write_all(&height.to_le_bytes()).unwrap();
|
|
|
|
|
|
file.write_all(&1u16.to_le_bytes()).unwrap(); // プレーン数
|
|
|
|
|
|
file.write_all(&bits_per_pixel.to_le_bytes()).unwrap();
|
|
|
|
|
|
file.write_all(&0u32.to_le_bytes()).unwrap(); // 圧縮なし
|
2025-09-16 23:49:36 +09:00
|
|
|
|
file.write_all(&(pixels.len() as u32).to_le_bytes())
|
|
|
|
|
|
.unwrap();
|
2025-08-10 07:54:03 +09:00
|
|
|
|
file.write_all(&0i32.to_le_bytes()).unwrap(); // X解像度
|
|
|
|
|
|
file.write_all(&0i32.to_le_bytes()).unwrap(); // Y解像度
|
|
|
|
|
|
file.write_all(&0u32.to_le_bytes()).unwrap(); // カラーテーブル数
|
|
|
|
|
|
file.write_all(&0u32.to_le_bytes()).unwrap(); // 重要な色数
|
2025-09-16 23:49:36 +09:00
|
|
|
|
|
2025-08-10 07:54:03 +09:00
|
|
|
|
// ピクセルデータ
|
|
|
|
|
|
file.write_all(pixels).unwrap();
|
2025-09-16 23:49:36 +09:00
|
|
|
|
|
2025-08-10 07:54:03 +09:00
|
|
|
|
println!("BMP file saved: {}", filename);
|
2025-09-16 23:49:36 +09:00
|
|
|
|
}
|