Skip to content

Commit 5bf303f

Browse files
streifmiOsspial
authored andcommitted
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
1 parent e37e46b commit 5bf303f

File tree

7 files changed

+25
-21
lines changed

7 files changed

+25
-21
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Unreleased
22

3+
- On Windows, support paths longer than MAX_PATH (260 characters) in `WindowEvent::DroppedFile`
4+
and `WindowEvent::HoveredFile`.
35
- On Mac, implement `DeviceEvent::Button`.
46
- Change `Event::Suspended(true / false)` to `Event::Suspended` and `Event::Resumed`.
57
- 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.

src/platform_impl/windows/drop_handler.rs

+14-12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use std::{
22
ffi::OsString,
3-
mem,
43
os::windows::ffi::OsStringExt,
54
path::PathBuf,
65
ptr,
@@ -11,7 +10,7 @@ use winapi::{
1110
ctypes::c_void,
1211
shared::{
1312
guiddef::REFIID,
14-
minwindef::{DWORD, MAX_PATH, UINT, ULONG},
13+
minwindef::{DWORD, UINT, ULONG},
1514
windef::{HWND, POINTL},
1615
winerror::S_OK,
1716
},
@@ -171,7 +170,6 @@ impl FileDropHandler {
171170
F: Fn(PathBuf),
172171
{
173172
use winapi::{
174-
ctypes::wchar_t,
175173
shared::{
176174
winerror::{DV_E_FORMATETC, SUCCEEDED},
177175
wtypes::{CLIPFORMAT, DVASPECT_CONTENT},
@@ -191,7 +189,7 @@ impl FileDropHandler {
191189
tymed: TYMED_HGLOBAL,
192190
};
193191

194-
let mut medium = mem::uninitialized();
192+
let mut medium = std::mem::zeroed();
195193
let get_data_result = (*data_obj).GetData(&mut drop_format, &mut medium);
196194
if SUCCEEDED(get_data_result) {
197195
let hglobal = (*medium.u).hGlobal();
@@ -200,15 +198,19 @@ impl FileDropHandler {
200198
// The second parameter (0xFFFFFFFF) instructs the function to return the item count
201199
let item_count = DragQueryFileW(hdrop, 0xFFFFFFFF, ptr::null_mut(), 0);
202200

203-
let mut pathbuf: [wchar_t; MAX_PATH] = mem::uninitialized();
204-
205201
for i in 0..item_count {
206-
let character_count =
207-
DragQueryFileW(hdrop, i, pathbuf.as_mut_ptr(), MAX_PATH as UINT) as usize;
208-
209-
if character_count > 0 {
210-
callback(OsString::from_wide(&pathbuf[0..character_count]).into());
211-
}
202+
// Get the length of the path string NOT including the terminating null character.
203+
// Previously, this was using a fixed size array of MAX_PATH length, but the
204+
// Windows API allows longer paths under certain circumstances.
205+
let character_count = DragQueryFileW(hdrop, i, ptr::null_mut(), 0) as usize;
206+
let str_len = character_count + 1;
207+
208+
// Fill path_buf with the null-terminated file name
209+
let mut path_buf = Vec::with_capacity(str_len);
210+
DragQueryFileW(hdrop, i, path_buf.as_mut_ptr(), str_len as UINT);
211+
path_buf.set_len(str_len);
212+
213+
callback(OsString::from_wide(&path_buf[0..character_count]).into());
212214
}
213215

214216
return Some(hdrop);

src/platform_impl/windows/event_loop.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ impl<T: 'static> EventLoop<T> {
182182
}
183183

184184
unsafe {
185-
let mut msg = mem::uninitialized();
185+
let mut msg = mem::zeroed();
186186
let mut msg_unprocessed = false;
187187

188188
'main: loop {
@@ -507,7 +507,7 @@ impl<T> EventLoopRunner<T> {
507507

508508
// Returns true if the wait time was reached, and false if a message must be processed.
509509
unsafe fn wait_until_time_or_msg(wait_until: Instant) -> bool {
510-
let mut msg = mem::uninitialized();
510+
let mut msg = mem::zeroed();
511511
let now = Instant::now();
512512
if now <= wait_until {
513513
// 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>(
16451645
}
16461646
};
16471647
if in_modal_loop {
1648-
let mut msg = mem::uninitialized();
1648+
let mut msg = mem::zeroed();
16491649
loop {
16501650
if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 0) {
16511651
break;

src/platform_impl/windows/monitor.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ impl Window {
109109
}
110110

111111
pub(crate) fn get_monitor_info(hmonitor: HMONITOR) -> Result<winuser::MONITORINFOEXW, io::Error> {
112-
let mut monitor_info: winuser::MONITORINFOEXW = unsafe { mem::uninitialized() };
112+
let mut monitor_info: winuser::MONITORINFOEXW = unsafe { mem::zeroed() };
113113
monitor_info.cbSize = mem::size_of::<winuser::MONITORINFOEXW>() as DWORD;
114114
let status = unsafe {
115115
winuser::GetMonitorInfoW(

src/platform_impl/windows/raw_input.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl From<RID_DEVICE_INFO> for RawDeviceInfo {
7474

7575
#[allow(dead_code)]
7676
pub fn get_raw_input_device_info(handle: HANDLE) -> Option<RawDeviceInfo> {
77-
let mut info: RID_DEVICE_INFO = unsafe { mem::uninitialized() };
77+
let mut info: RID_DEVICE_INFO = unsafe { mem::zeroed() };
7878
let info_size = size_of::<RID_DEVICE_INFO>() as UINT;
7979

8080
info.cbSize = info_size;
@@ -164,7 +164,7 @@ pub fn register_all_mice_and_keyboards_for_raw_input(window_handle: HWND) -> boo
164164
}
165165

166166
pub fn get_raw_input_data(handle: HRAWINPUT) -> Option<RAWINPUT> {
167-
let mut data: RAWINPUT = unsafe { mem::uninitialized() };
167+
let mut data: RAWINPUT = unsafe { mem::zeroed() };
168168
let mut data_size = size_of::<RAWINPUT>() as UINT;
169169
let header_size = size_of::<RAWINPUTHEADER>() as UINT;
170170

src/platform_impl/windows/util.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pub fn wchar_ptr_to_string(wchar: *const wchar_t) -> String {
3333
}
3434

3535
pub unsafe fn status_map<T, F: FnMut(&mut T) -> BOOL>(mut fun: F) -> Option<T> {
36-
let mut data: T = mem::uninitialized();
36+
let mut data: T = mem::zeroed();
3737
if fun(&mut data) != 0 {
3838
Some(data)
3939
} else {
@@ -59,7 +59,7 @@ pub fn get_window_rect(hwnd: HWND) -> Option<RECT> {
5959

6060
pub fn get_client_rect(hwnd: HWND) -> Result<RECT, io::Error> {
6161
unsafe {
62-
let mut rect = mem::uninitialized();
62+
let mut rect = mem::zeroed();
6363
let mut top_left = mem::zeroed();
6464

6565
win_to_err(|| winuser::ClientToScreen(hwnd, &mut top_left))?;

src/platform_impl/windows/window.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ impl Window {
211211
}
212212

213213
pub(crate) fn inner_size_physical(&self) -> (u32, u32) {
214-
let mut rect: RECT = unsafe { mem::uninitialized() };
214+
let mut rect: RECT = unsafe { mem::zeroed() };
215215
if unsafe { winuser::GetClientRect(self.window.0, &mut rect) } == 0 {
216216
panic!("Unexpected GetClientRect failure: please report this error to https://github.com/rust-windowing/winit")
217217
}

0 commit comments

Comments
 (0)