mirror of
https://github.com/tauri-apps/tauri.git
synced 2026-02-06 13:37:09 +00:00
fix(windows): ensure APIs exist before using it (#12848)
* fix(windows): ensure APIs exist before using it * fix build on other platforms * clippy * use GetSystemMetricsForDpi
This commit is contained in:
parent
bca02967a9
commit
e103e87f15
6
.changes/windows-crash.md
Normal file
6
.changes/windows-crash.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
"tauri": "patch:bug"
|
||||
"tauri-runtime-wry": "patch:bug"
|
||||
---
|
||||
|
||||
Fix crash on Windows because of missing functions on older Windows systems, regression in 2.3.0
|
||||
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -8797,6 +8797,7 @@ dependencies = [
|
||||
"objc2 0.6.0",
|
||||
"objc2-app-kit",
|
||||
"objc2-foundation 0.3.0",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"raw-window-handle",
|
||||
"softbuffer",
|
||||
|
||||
@ -35,6 +35,7 @@ log = "0.4.21"
|
||||
[target."cfg(windows)".dependencies]
|
||||
webview2-com = "0.36"
|
||||
softbuffer = { version = "0.4", default-features = false }
|
||||
once_cell = "1.20"
|
||||
|
||||
[target."cfg(windows)".dependencies.windows]
|
||||
version = "0.60"
|
||||
|
||||
@ -134,6 +134,7 @@ type IpcHandler = dyn Fn(Request<String>) + 'static;
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
mod undecorated_resizing;
|
||||
mod util;
|
||||
mod webview;
|
||||
mod window;
|
||||
|
||||
|
||||
@ -78,11 +78,12 @@ fn hit_test(
|
||||
|
||||
#[cfg(windows)]
|
||||
mod windows {
|
||||
use crate::util;
|
||||
|
||||
use super::{hit_test, HitTestResult};
|
||||
|
||||
use windows::core::*;
|
||||
use windows::Win32::System::LibraryLoader::*;
|
||||
use windows::Win32::UI::HiDpi::{GetDpiForWindow, GetSystemMetricsForDpi};
|
||||
use windows::Win32::UI::WindowsAndMessaging::*;
|
||||
use windows::Win32::{Foundation::*, UI::Shell::SetWindowSubclass};
|
||||
use windows::Win32::{Graphics::Gdi::*, UI::Shell::DefSubclassProc};
|
||||
@ -302,9 +303,9 @@ mod windows {
|
||||
|
||||
let (cx, cy) = (GET_X_LPARAM(lparam) as i32, GET_Y_LPARAM(lparam) as i32);
|
||||
|
||||
let dpi = unsafe { GetDpiForWindow(child) };
|
||||
let border_x = GetSystemMetricsForDpi(SM_CXFRAME, dpi);
|
||||
let border_y = GetSystemMetricsForDpi(SM_CYFRAME, dpi);
|
||||
let dpi = unsafe { util::hwnd_dpi(child) };
|
||||
let border_x = util::get_system_metrics_for_dpi(SM_CXFRAME, dpi);
|
||||
let border_y = util::get_system_metrics_for_dpi(SM_CYFRAME, dpi);
|
||||
|
||||
let res = hit_test(
|
||||
rect.left,
|
||||
@ -348,9 +349,9 @@ mod windows {
|
||||
return DefWindowProcW(child, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
let padded_border = GetSystemMetrics(SM_CXPADDEDBORDER);
|
||||
let border_x = GetSystemMetrics(SM_CXFRAME) + padded_border;
|
||||
let border_y = GetSystemMetrics(SM_CYFRAME) + padded_border;
|
||||
let dpi = unsafe { util::hwnd_dpi(child) };
|
||||
let border_x = util::get_system_metrics_for_dpi(SM_CXFRAME, dpi);
|
||||
let border_y = util::get_system_metrics_for_dpi(SM_CYFRAME, dpi);
|
||||
|
||||
hit_test(
|
||||
rect.left,
|
||||
@ -415,9 +416,9 @@ mod windows {
|
||||
// and so we need create a cut out in the middle for the parent and other child
|
||||
// windows like the webview can receive mouse events.
|
||||
|
||||
let dpi = unsafe { GetDpiForWindow(hwnd) };
|
||||
let border_x = GetSystemMetricsForDpi(SM_CXFRAME, dpi);
|
||||
let border_y = GetSystemMetricsForDpi(SM_CYFRAME, dpi);
|
||||
let dpi = unsafe { util::hwnd_dpi(hwnd) };
|
||||
let border_x = util::get_system_metrics_for_dpi(SM_CXFRAME, dpi);
|
||||
let border_y = util::get_system_metrics_for_dpi(SM_CYFRAME, dpi);
|
||||
|
||||
let hrgn1 = CreateRectRgn(0, 0, width, height);
|
||||
|
||||
|
||||
118
crates/tauri-runtime-wry/src/util.rs
Normal file
118
crates/tauri-runtime-wry/src/util.rs
Normal file
@ -0,0 +1,118 @@
|
||||
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#[cfg_attr(not(windows), allow(unused_imports))]
|
||||
pub use imp::*;
|
||||
|
||||
#[cfg(not(windows))]
|
||||
mod imp {}
|
||||
|
||||
#[cfg(windows)]
|
||||
mod imp {
|
||||
use std::{iter::once, os::windows::ffi::OsStrExt};
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use windows::{
|
||||
core::{HRESULT, PCSTR, PCWSTR},
|
||||
Win32::{
|
||||
Foundation::*,
|
||||
Graphics::Gdi::*,
|
||||
System::LibraryLoader::{GetProcAddress, LoadLibraryW},
|
||||
UI::{HiDpi::*, WindowsAndMessaging::*},
|
||||
},
|
||||
};
|
||||
|
||||
pub fn encode_wide(string: impl AsRef<std::ffi::OsStr>) -> Vec<u16> {
|
||||
string.as_ref().encode_wide().chain(once(0)).collect()
|
||||
}
|
||||
|
||||
// Helper function to dynamically load function pointer.
|
||||
// `library` and `function` must be zero-terminated.
|
||||
pub(super) fn get_function_impl(library: &str, function: &str) -> FARPROC {
|
||||
let library = encode_wide(library);
|
||||
assert_eq!(function.chars().last(), Some('\0'));
|
||||
|
||||
// Library names we will use are ASCII so we can use the A version to avoid string conversion.
|
||||
let module = unsafe { LoadLibraryW(PCWSTR::from_raw(library.as_ptr())) }.unwrap_or_default();
|
||||
if module.is_invalid() {
|
||||
return None;
|
||||
}
|
||||
|
||||
unsafe { GetProcAddress(module, PCSTR::from_raw(function.as_ptr())) }
|
||||
}
|
||||
|
||||
macro_rules! get_function {
|
||||
($lib:expr, $func:ident) => {
|
||||
$crate::util::get_function_impl($lib, concat!(stringify!($func), '\0'))
|
||||
.map(|f| unsafe { std::mem::transmute::<_, $func>(f) })
|
||||
};
|
||||
}
|
||||
|
||||
type GetDpiForWindow = unsafe extern "system" fn(hwnd: HWND) -> u32;
|
||||
type GetDpiForMonitor = unsafe extern "system" fn(
|
||||
hmonitor: HMONITOR,
|
||||
dpi_type: MONITOR_DPI_TYPE,
|
||||
dpi_x: *mut u32,
|
||||
dpi_y: *mut u32,
|
||||
) -> HRESULT;
|
||||
type GetSystemMetricsForDpi =
|
||||
unsafe extern "system" fn(nindex: SYSTEM_METRICS_INDEX, dpi: u32) -> i32;
|
||||
|
||||
static GET_DPI_FOR_WINDOW: Lazy<Option<GetDpiForWindow>> =
|
||||
Lazy::new(|| get_function!("user32.dll", GetDpiForWindow));
|
||||
static GET_DPI_FOR_MONITOR: Lazy<Option<GetDpiForMonitor>> =
|
||||
Lazy::new(|| get_function!("shcore.dll", GetDpiForMonitor));
|
||||
static GET_SYSTEM_METRICS_FOR_DPI: Lazy<Option<GetSystemMetricsForDpi>> =
|
||||
Lazy::new(|| get_function!("user32.dll", GetSystemMetricsForDpi));
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn hwnd_dpi(hwnd: HWND) -> u32 {
|
||||
let hdc = GetDC(Some(hwnd));
|
||||
if hdc.is_invalid() {
|
||||
return USER_DEFAULT_SCREEN_DPI;
|
||||
}
|
||||
if let Some(GetDpiForWindow) = *GET_DPI_FOR_WINDOW {
|
||||
// We are on Windows 10 Anniversary Update (1607) or later.
|
||||
match GetDpiForWindow(hwnd) {
|
||||
0 => USER_DEFAULT_SCREEN_DPI, // 0 is returned if hwnd is invalid
|
||||
dpi => dpi,
|
||||
}
|
||||
} else if let Some(GetDpiForMonitor) = *GET_DPI_FOR_MONITOR {
|
||||
// We are on Windows 8.1 or later.
|
||||
let monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
|
||||
if monitor.is_invalid() {
|
||||
return USER_DEFAULT_SCREEN_DPI;
|
||||
}
|
||||
|
||||
let mut dpi_x = 0;
|
||||
let mut dpi_y = 0;
|
||||
if GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &mut dpi_x, &mut dpi_y).is_ok() {
|
||||
dpi_x
|
||||
} else {
|
||||
USER_DEFAULT_SCREEN_DPI
|
||||
}
|
||||
} else {
|
||||
// We are on Vista or later.
|
||||
if IsProcessDPIAware().as_bool() {
|
||||
// If the process is DPI aware, then scaling must be handled by the application using
|
||||
// this DPI value.
|
||||
GetDeviceCaps(Some(hdc), LOGPIXELSX) as u32
|
||||
} else {
|
||||
// If the process is DPI unaware, then scaling is performed by the OS; we thus return
|
||||
// 96 (scale factor 1.0) to prevent the window from being re-scaled by both the
|
||||
// application and the WM.
|
||||
USER_DEFAULT_SCREEN_DPI
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn get_system_metrics_for_dpi(nindex: SYSTEM_METRICS_INDEX, dpi: u32) -> i32 {
|
||||
if let Some(GetSystemMetricsForDpi) = *GET_SYSTEM_METRICS_FOR_DPI {
|
||||
GetSystemMetricsForDpi(nindex, dpi)
|
||||
} else {
|
||||
GetSystemMetrics(nindex)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user