mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2025-02-24 00:37:43 +11:00
Improve handling of file paths in the windows DnD handler (#980)
* Make FileDropHandler::iterate_filenames more robust by replacing the call to mem::uninitialized with mem::zeroed and change file name retrieval to use buffers of exact length as reported by DragQueryFileW instead of relying on MAX_PATH. * Change remaining calls of uninitialized to zeroed * Run rustfmt * Add CHANGELOG entry and comment
This commit is contained in:
parent
e37e46b155
commit
5bf303fd26
7 changed files with 24 additions and 20 deletions
CHANGELOG.md
src/platform_impl/windows
|
@ -1,5 +1,7 @@
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
- On Windows, support paths longer than MAX_PATH (260 characters) in `WindowEvent::DroppedFile`
|
||||||
|
and `WindowEvent::HoveredFile`.
|
||||||
- On Mac, implement `DeviceEvent::Button`.
|
- On Mac, implement `DeviceEvent::Button`.
|
||||||
- Change `Event::Suspended(true / false)` to `Event::Suspended` and `Event::Resumed`.
|
- Change `Event::Suspended(true / false)` to `Event::Suspended` and `Event::Resumed`.
|
||||||
- On X11, fix sanity check which checks that a monitor's reported width and height (in millimeters) are non-zero when calculating the DPI factor.
|
- On X11, fix sanity check which checks that a monitor's reported width and height (in millimeters) are non-zero when calculating the DPI factor.
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use std::{
|
use std::{
|
||||||
ffi::OsString,
|
ffi::OsString,
|
||||||
mem,
|
|
||||||
os::windows::ffi::OsStringExt,
|
os::windows::ffi::OsStringExt,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
ptr,
|
ptr,
|
||||||
|
@ -11,7 +10,7 @@ use winapi::{
|
||||||
ctypes::c_void,
|
ctypes::c_void,
|
||||||
shared::{
|
shared::{
|
||||||
guiddef::REFIID,
|
guiddef::REFIID,
|
||||||
minwindef::{DWORD, MAX_PATH, UINT, ULONG},
|
minwindef::{DWORD, UINT, ULONG},
|
||||||
windef::{HWND, POINTL},
|
windef::{HWND, POINTL},
|
||||||
winerror::S_OK,
|
winerror::S_OK,
|
||||||
},
|
},
|
||||||
|
@ -171,7 +170,6 @@ impl FileDropHandler {
|
||||||
F: Fn(PathBuf),
|
F: Fn(PathBuf),
|
||||||
{
|
{
|
||||||
use winapi::{
|
use winapi::{
|
||||||
ctypes::wchar_t,
|
|
||||||
shared::{
|
shared::{
|
||||||
winerror::{DV_E_FORMATETC, SUCCEEDED},
|
winerror::{DV_E_FORMATETC, SUCCEEDED},
|
||||||
wtypes::{CLIPFORMAT, DVASPECT_CONTENT},
|
wtypes::{CLIPFORMAT, DVASPECT_CONTENT},
|
||||||
|
@ -191,7 +189,7 @@ impl FileDropHandler {
|
||||||
tymed: TYMED_HGLOBAL,
|
tymed: TYMED_HGLOBAL,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut medium = mem::uninitialized();
|
let mut medium = std::mem::zeroed();
|
||||||
let get_data_result = (*data_obj).GetData(&mut drop_format, &mut medium);
|
let get_data_result = (*data_obj).GetData(&mut drop_format, &mut medium);
|
||||||
if SUCCEEDED(get_data_result) {
|
if SUCCEEDED(get_data_result) {
|
||||||
let hglobal = (*medium.u).hGlobal();
|
let hglobal = (*medium.u).hGlobal();
|
||||||
|
@ -200,15 +198,19 @@ impl FileDropHandler {
|
||||||
// The second parameter (0xFFFFFFFF) instructs the function to return the item count
|
// The second parameter (0xFFFFFFFF) instructs the function to return the item count
|
||||||
let item_count = DragQueryFileW(hdrop, 0xFFFFFFFF, ptr::null_mut(), 0);
|
let item_count = DragQueryFileW(hdrop, 0xFFFFFFFF, ptr::null_mut(), 0);
|
||||||
|
|
||||||
let mut pathbuf: [wchar_t; MAX_PATH] = mem::uninitialized();
|
|
||||||
|
|
||||||
for i in 0..item_count {
|
for i in 0..item_count {
|
||||||
let character_count =
|
// Get the length of the path string NOT including the terminating null character.
|
||||||
DragQueryFileW(hdrop, i, pathbuf.as_mut_ptr(), MAX_PATH as UINT) as usize;
|
// Previously, this was using a fixed size array of MAX_PATH length, but the
|
||||||
|
// Windows API allows longer paths under certain circumstances.
|
||||||
|
let character_count = DragQueryFileW(hdrop, i, ptr::null_mut(), 0) as usize;
|
||||||
|
let str_len = character_count + 1;
|
||||||
|
|
||||||
if character_count > 0 {
|
// Fill path_buf with the null-terminated file name
|
||||||
callback(OsString::from_wide(&pathbuf[0..character_count]).into());
|
let mut path_buf = Vec::with_capacity(str_len);
|
||||||
}
|
DragQueryFileW(hdrop, i, path_buf.as_mut_ptr(), str_len as UINT);
|
||||||
|
path_buf.set_len(str_len);
|
||||||
|
|
||||||
|
callback(OsString::from_wide(&path_buf[0..character_count]).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
return Some(hdrop);
|
return Some(hdrop);
|
||||||
|
|
|
@ -182,7 +182,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut msg = mem::uninitialized();
|
let mut msg = mem::zeroed();
|
||||||
let mut msg_unprocessed = false;
|
let mut msg_unprocessed = false;
|
||||||
|
|
||||||
'main: loop {
|
'main: loop {
|
||||||
|
@ -507,7 +507,7 @@ impl<T> EventLoopRunner<T> {
|
||||||
|
|
||||||
// Returns true if the wait time was reached, and false if a message must be processed.
|
// Returns true if the wait time was reached, and false if a message must be processed.
|
||||||
unsafe fn wait_until_time_or_msg(wait_until: Instant) -> bool {
|
unsafe fn wait_until_time_or_msg(wait_until: Instant) -> bool {
|
||||||
let mut msg = mem::uninitialized();
|
let mut msg = mem::zeroed();
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
if now <= wait_until {
|
if now <= wait_until {
|
||||||
// MsgWaitForMultipleObjects tends to overshoot just a little bit. We subtract 1 millisecond
|
// MsgWaitForMultipleObjects tends to overshoot just a little bit. We subtract 1 millisecond
|
||||||
|
@ -1645,7 +1645,7 @@ unsafe extern "system" fn thread_event_target_callback<T>(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if in_modal_loop {
|
if in_modal_loop {
|
||||||
let mut msg = mem::uninitialized();
|
let mut msg = mem::zeroed();
|
||||||
loop {
|
loop {
|
||||||
if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 0) {
|
if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 0) {
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -109,7 +109,7 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_monitor_info(hmonitor: HMONITOR) -> Result<winuser::MONITORINFOEXW, io::Error> {
|
pub(crate) fn get_monitor_info(hmonitor: HMONITOR) -> Result<winuser::MONITORINFOEXW, io::Error> {
|
||||||
let mut monitor_info: winuser::MONITORINFOEXW = unsafe { mem::uninitialized() };
|
let mut monitor_info: winuser::MONITORINFOEXW = unsafe { mem::zeroed() };
|
||||||
monitor_info.cbSize = mem::size_of::<winuser::MONITORINFOEXW>() as DWORD;
|
monitor_info.cbSize = mem::size_of::<winuser::MONITORINFOEXW>() as DWORD;
|
||||||
let status = unsafe {
|
let status = unsafe {
|
||||||
winuser::GetMonitorInfoW(
|
winuser::GetMonitorInfoW(
|
||||||
|
|
|
@ -74,7 +74,7 @@ impl From<RID_DEVICE_INFO> for RawDeviceInfo {
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn get_raw_input_device_info(handle: HANDLE) -> Option<RawDeviceInfo> {
|
pub fn get_raw_input_device_info(handle: HANDLE) -> Option<RawDeviceInfo> {
|
||||||
let mut info: RID_DEVICE_INFO = unsafe { mem::uninitialized() };
|
let mut info: RID_DEVICE_INFO = unsafe { mem::zeroed() };
|
||||||
let info_size = size_of::<RID_DEVICE_INFO>() as UINT;
|
let info_size = size_of::<RID_DEVICE_INFO>() as UINT;
|
||||||
|
|
||||||
info.cbSize = info_size;
|
info.cbSize = info_size;
|
||||||
|
@ -164,7 +164,7 @@ pub fn register_all_mice_and_keyboards_for_raw_input(window_handle: HWND) -> boo
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_raw_input_data(handle: HRAWINPUT) -> Option<RAWINPUT> {
|
pub fn get_raw_input_data(handle: HRAWINPUT) -> Option<RAWINPUT> {
|
||||||
let mut data: RAWINPUT = unsafe { mem::uninitialized() };
|
let mut data: RAWINPUT = unsafe { mem::zeroed() };
|
||||||
let mut data_size = size_of::<RAWINPUT>() as UINT;
|
let mut data_size = size_of::<RAWINPUT>() as UINT;
|
||||||
let header_size = size_of::<RAWINPUTHEADER>() as UINT;
|
let header_size = size_of::<RAWINPUTHEADER>() as UINT;
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ pub fn wchar_ptr_to_string(wchar: *const wchar_t) -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn status_map<T, F: FnMut(&mut T) -> BOOL>(mut fun: F) -> Option<T> {
|
pub unsafe fn status_map<T, F: FnMut(&mut T) -> BOOL>(mut fun: F) -> Option<T> {
|
||||||
let mut data: T = mem::uninitialized();
|
let mut data: T = mem::zeroed();
|
||||||
if fun(&mut data) != 0 {
|
if fun(&mut data) != 0 {
|
||||||
Some(data)
|
Some(data)
|
||||||
} else {
|
} else {
|
||||||
|
@ -59,7 +59,7 @@ pub fn get_window_rect(hwnd: HWND) -> Option<RECT> {
|
||||||
|
|
||||||
pub fn get_client_rect(hwnd: HWND) -> Result<RECT, io::Error> {
|
pub fn get_client_rect(hwnd: HWND) -> Result<RECT, io::Error> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut rect = mem::uninitialized();
|
let mut rect = mem::zeroed();
|
||||||
let mut top_left = mem::zeroed();
|
let mut top_left = mem::zeroed();
|
||||||
|
|
||||||
win_to_err(|| winuser::ClientToScreen(hwnd, &mut top_left))?;
|
win_to_err(|| winuser::ClientToScreen(hwnd, &mut top_left))?;
|
||||||
|
|
|
@ -211,7 +211,7 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn inner_size_physical(&self) -> (u32, u32) {
|
pub(crate) fn inner_size_physical(&self) -> (u32, u32) {
|
||||||
let mut rect: RECT = unsafe { mem::uninitialized() };
|
let mut rect: RECT = unsafe { mem::zeroed() };
|
||||||
if unsafe { winuser::GetClientRect(self.window.0, &mut rect) } == 0 {
|
if unsafe { winuser::GetClientRect(self.window.0, &mut rect) } == 0 {
|
||||||
panic!("Unexpected GetClientRect failure: please report this error to https://github.com/rust-windowing/winit")
|
panic!("Unexpected GetClientRect failure: please report this error to https://github.com/rust-windowing/winit")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue