Skip to content

Commit

Permalink
win32: load DPI-related function pointers
Browse files Browse the repository at this point in the history
These DPI-related functions will fail to link on older versions of
Windows, so we load them dynamically at runtime and implement a fallback
strategy if they're not available.
  • Loading branch information
micahrj committed Sep 17, 2023
1 parent 47dfd5d commit 29ec6d2
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ features = [
"Win32_Foundation",
"Win32_UI_WindowsAndMessaging",
"Win32_UI_Input_KeyboardAndMouse",
"Win32_UI_HiDpi",
"Win32_Graphics_Gdi",
"Win32_System_LibraryLoader",
"Win32_System_SystemServices",
]

Expand Down
5 changes: 5 additions & 0 deletions src/backend/win32/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ use windows_sys::Win32::UI::WindowsAndMessaging::{
RegisterClassW, TranslateMessage, UnregisterClassW, MSG, WNDCLASSW,
};

use super::dpi::DpiFns;
use super::timer::{TimerHandleInner, Timers};
use super::window::wnd_proc;
use super::{class_name, hinstance, to_wstring, OsError};
use crate::{App, AppContext, AppOptions, Error, IntoInnerError, Result};

pub struct AppState {
pub class: u16,
pub dpi: DpiFns,
pub timers: Timers,
pub data: RefCell<Option<Box<dyn Any>>>,
}
Expand Down Expand Up @@ -68,10 +70,13 @@ impl<T: 'static> AppInner<T> {
class
};

let dpi = DpiFns::load();

let timers = Timers::new()?;

let state = Rc::new(AppState {
class,
dpi,
timers,
data: RefCell::new(None),
});
Expand Down
73 changes: 73 additions & 0 deletions src/backend/win32/dpi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use std::mem;

use windows_sys::core::HRESULT;
use windows_sys::Win32::Foundation::{BOOL, HWND, RECT};
use windows_sys::Win32::Graphics::Gdi::HMONITOR;
use windows_sys::Win32::System::LibraryLoader::{GetProcAddress, LoadLibraryA};
use windows_sys::Win32::UI::HiDpi::{
DPI_AWARENESS_CONTEXT, MONITOR_DPI_TYPE, PROCESS_DPI_AWARENESS,
};
use windows_sys::Win32::UI::WindowsAndMessaging::{WINDOW_EX_STYLE, WINDOW_STYLE};

macro_rules! c_str {
($str:literal) => {
concat!($str, "\0").as_ptr()
};
}

#[allow(non_snake_case)]
pub struct DpiFns {
pub SetProcessDPIAware: Option<unsafe extern "system" fn() -> BOOL>,
pub SetProcessDpiAwareness:
Option<unsafe extern "system" fn(value: PROCESS_DPI_AWARENESS) -> HRESULT>,
pub SetProcessDpiAwarenessContext:
Option<unsafe extern "system" fn(value: DPI_AWARENESS_CONTEXT) -> BOOL>,
pub GetDpiForMonitor: Option<
unsafe extern "system" fn(
hmonitor: HMONITOR,
dpitype: MONITOR_DPI_TYPE,
dpix: *mut u32,
dpiy: *mut u32,
) -> HRESULT,
>,
pub GetDpiForWindow: Option<unsafe extern "system" fn(hwnd: HWND) -> u32>,
pub EnableNonClientDpiScaling: Option<unsafe extern "system" fn(hwnd: HWND) -> BOOL>,
pub AdjustWindowRectExForDpi: Option<
unsafe extern "system" fn(
lprect: *mut RECT,
dwstyle: WINDOW_STYLE,
bmenu: BOOL,
dwexstyle: WINDOW_EX_STYLE,
dpi: u32,
) -> BOOL,
>,
}

impl DpiFns {
pub fn load() -> DpiFns {
macro_rules! load {
($lib:expr, $symbol:literal) => {
if $lib != 0 {
mem::transmute(GetProcAddress($lib, c_str!($symbol)))
} else {
None
}
};
}

unsafe {
let user32 = LoadLibraryA(c_str!("user32.dll"));
let shcore = LoadLibraryA(c_str!("shcore.dll"));

DpiFns {
SetProcessDPIAware: load!(user32, "SetProcessDPIAware"),
SetProcessDpiAwareness: load!(shcore, "SetProcessDpiAwareness"),
SetProcessDpiAwarenessContext: load!(user32, "SetProcessDpiAwarenessContext"),
GetDpiForMonitor: load!(shcore, "GetDpiForMonitor"),
GetDpiForWindow: load!(user32, "GetDpiForWindow"),
EnableNonClientDpiScaling: load!(user32, "EnableNonClientDpiScaling"),
AdjustWindowRectExForDpi: load!(user32, "AdjustWindowRectExForDpi"),
}
}
}
}
1 change: 1 addition & 0 deletions src/backend/win32/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use windows_sys::Win32::Foundation::{HMODULE, WIN32_ERROR};
use windows_sys::Win32::System::SystemServices::IMAGE_DOS_HEADER;

mod app;
mod dpi;
mod timer;
mod window;

Expand Down

0 comments on commit 29ec6d2

Please sign in to comment.