Replace `winapi` with `windows-sys` crate (#7416)

This the second take of <https://github.com/emilk/egui/pull/5038>,
adjusted for newer version of `windows-sys`, and with merge conflicts
resolved. I added the original author to `Co-authored-by:`.

* Closes <https://github.com/emilk/egui/issues/7334>
* Closes <https://github.com/emilk/egui/pull/5038>
* [x] I have followed the instructions in the PR template

Tested on Windows 10:
<img width="322" height="272" alt="image"
src="https://github.com/user-attachments/assets/15ddf0bf-1f30-452f-8764-07ccfce2b00c"
/>
<img width="802" height="632" alt="image"
src="https://github.com/user-attachments/assets/db6f4586-cfa5-4f7f-996c-06f7e2489df6"
/>

Action run result:
https://github.com/sola-contrib/egui/actions/runs/16748810761

---------

Co-authored-by: Casper Meijn <casper@meijn.net>
This commit is contained in:
Sola 2025-08-12 18:28:51 +08:00 committed by GitHub
parent 68d456ac0b
commit adf463b0a9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 20 additions and 19 deletions

View File

@ -1242,7 +1242,6 @@ dependencies = [
"web-sys",
"web-time",
"wgpu",
"winapi",
"windows-sys 0.59.0",
"winit",
]

View File

@ -192,11 +192,12 @@ objc2-app-kit = { version = "0.2.0", default-features = false, features = [
# windows:
[target.'cfg(any(target_os = "windows"))'.dependencies]
winapi = { version = "0.3.9", features = ["winuser"] }
windows-sys = { workspace = true, features = [
"Win32_Foundation",
"Win32_UI_Shell",
"Win32_System_Com",
"Win32_UI_Input_KeyboardAndMouse",
"Win32_UI_Shell",
"Win32_UI_WindowsAndMessaging",
] }
# -------------------------------------------

View File

@ -80,7 +80,11 @@ fn set_title_and_icon(_title: &str, _icon_data: Option<&IconData>) -> AppIconSta
#[expect(unsafe_code)]
fn set_app_icon_windows(icon_data: &IconData) -> AppIconStatus {
use crate::icon_data::IconDataExt as _;
use winapi::um::winuser;
use windows_sys::Win32::UI::Input::KeyboardAndMouse::GetActiveWindow;
use windows_sys::Win32::UI::WindowsAndMessaging::{
CreateIconFromResourceEx, GetSystemMetrics, HICON, ICON_BIG, ICON_SMALL, LR_DEFAULTCOLOR,
SM_CXICON, SM_CXSMICON, SendMessageW, WM_SETICON,
};
// We would get fairly far already with winit's `set_window_icon` (which is exposed to eframe) actually!
// However, it only sets ICON_SMALL, i.e. doesn't allow us to set a higher resolution icon for the task bar.
@ -92,16 +96,13 @@ fn set_app_icon_windows(icon_data: &IconData) -> AppIconStatus {
// * using undocumented SetConsoleIcon method (successfully queried via GetProcAddress)
// SAFETY: WinApi function without side-effects.
let window_handle = unsafe { winuser::GetActiveWindow() };
let window_handle = unsafe { GetActiveWindow() };
if window_handle.is_null() {
// The Window isn't available yet. Try again later!
return AppIconStatus::NotSetTryAgain;
}
fn create_hicon_with_scale(
unscaled_image: &image::RgbaImage,
target_size: i32,
) -> winapi::shared::windef::HICON {
fn create_hicon_with_scale(unscaled_image: &image::RgbaImage, target_size: i32) -> HICON {
let image_scaled = image::imageops::resize(
unscaled_image,
target_size as _,
@ -127,14 +128,14 @@ fn set_app_icon_windows(icon_data: &IconData) -> AppIconStatus {
// SAFETY: Creating an HICON which should be readonly on our data.
unsafe {
winuser::CreateIconFromResourceEx(
CreateIconFromResourceEx(
image_scaled_bytes.as_mut_ptr(),
image_scaled_bytes.len() as u32,
1, // Means this is an icon, not a cursor.
0x00030000, // Version number of the HICON
target_size, // Note that this method can scale, but it does so *very* poorly. So let's avoid that!
target_size,
winuser::LR_DEFAULTCOLOR,
LR_DEFAULTCOLOR,
)
}
}
@ -155,7 +156,7 @@ fn set_app_icon_windows(icon_data: &IconData) -> AppIconStatus {
// Note that ICON_SMALL may be used even if we don't render a title bar as it may be used in alt+tab!
{
// SAFETY: WinAPI getter function with no known side effects.
let icon_size_big = unsafe { winuser::GetSystemMetrics(winuser::SM_CXICON) };
let icon_size_big = unsafe { GetSystemMetrics(SM_CXICON) };
let icon_big = create_hicon_with_scale(&unscaled_image, icon_size_big);
if icon_big.is_null() {
log::warn!("Failed to create HICON (for big icon) from embedded png data.");
@ -163,10 +164,10 @@ fn set_app_icon_windows(icon_data: &IconData) -> AppIconStatus {
} else {
// SAFETY: Unsafe WinApi function, takes objects previously created with WinAPI, all checked for null prior.
unsafe {
winuser::SendMessageW(
SendMessageW(
window_handle,
winuser::WM_SETICON,
winuser::ICON_BIG as usize,
WM_SETICON,
ICON_BIG as usize,
icon_big as isize,
);
}
@ -174,7 +175,7 @@ fn set_app_icon_windows(icon_data: &IconData) -> AppIconStatus {
}
{
// SAFETY: WinAPI getter function with no known side effects.
let icon_size_small = unsafe { winuser::GetSystemMetrics(winuser::SM_CXSMICON) };
let icon_size_small = unsafe { GetSystemMetrics(SM_CXSMICON) };
let icon_small = create_hicon_with_scale(&unscaled_image, icon_size_small);
if icon_small.is_null() {
log::warn!("Failed to create HICON (for small icon) from embedded png data.");
@ -182,10 +183,10 @@ fn set_app_icon_windows(icon_data: &IconData) -> AppIconStatus {
} else {
// SAFETY: Unsafe WinApi function, takes objects previously created with WinAPI, all checked for null prior.
unsafe {
winuser::SendMessageW(
SendMessageW(
window_handle,
winuser::WM_SETICON,
winuser::ICON_SMALL as usize,
WM_SETICON,
ICON_SMALL as usize,
icon_small as isize,
);
}