Skip to content

Commit

Permalink
Update windows-rs to 0.37.0 and webview2-com to 0.16.0 to match (#592)
Browse files Browse the repository at this point in the history
Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
  • Loading branch information
wravery and lucasfernog committed May 24, 2022
1 parent 16d1924 commit 9d9d9d8
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 130 deletions.
9 changes: 9 additions & 0 deletions .changes/windows-0.37.0.md
@@ -0,0 +1,9 @@
---
"wry": patch
---

Update the `windows` crate to the latest 0.37.0 release and `webview2-com` to 0.16.0 to match.

The `#[implement]` macro in `windows-implement` and the `implement` feature in `windows` depend on some `const` generic features which stabilized in `rustc` 1.61. The MSRV on Windows targets is effectively 1.61, but other targets do not require these features.

The `webview2-com` crate specifies `rust-version = "1.61"`, so `wry` will inherit that MSRV and developers on Windows should get a clear error message telling them to update their toolchain when building `wry` or anything that depends on `wry`. Developers targeting other platforms should be able to continue using whatever toolchain they were using before.
12 changes: 7 additions & 5 deletions Cargo.toml
Expand Up @@ -48,7 +48,7 @@ serde = { version = "1.0", features = [ "derive" ] }
serde_json = "1.0"
thiserror = "1.0"
url = "2.2"
tao = { version = "0.8.4", default-features = false, features = [ "serde" ] }
tao = { version = "0.9.1", default-features = false, features = [ "serde" ] }
http = "0.2.7"

[dev-dependencies]
Expand All @@ -65,19 +65,21 @@ gtk = "0.15"
gdk = "0.15"

[target."cfg(target_os = \"windows\")".dependencies]
webview2-com = "0.13.0"
windows_macros = "0.30.0"
webview2-com = "0.16.0"
windows-implement = "0.37.0"

[target."cfg(target_os = \"windows\")".dependencies.windows]
version = "0.30.0"
version = "0.37.0"
features = [
"alloc",
"implement",
"Win32_Foundation",
"Win32_Graphics_Gdi",
"Win32_System_Com",
"Win32_System_Com_StructuredStorage",
"Win32_System_SystemInformation",
"Win32_System_LibraryLoader",
"Win32_System_Ole",
"Win32_System_SystemInformation",
"Win32_System_SystemServices",
"Win32_UI_Shell",
"Win32_UI_WindowsAndMessaging"
Expand Down
173 changes: 91 additions & 82 deletions src/webview/webview2/file_drop.rs
Expand Up @@ -10,30 +10,31 @@ use crate::webview::FileDropEvent;
// https://docs.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2experimentalcompositioncontroller3?view=webview2-1.0.721-prerelease&preserve-view=true

use std::{
cell::UnsafeCell,
ffi::OsString,
os::{raw::c_void, windows::ffi::OsStringExt},
path::PathBuf,
ptr,
rc::Rc,
};

use windows::{
self as Windows,
Win32::{
Foundation::{self as win32f, BOOL, DRAGDROP_E_INVALIDHWND, HWND, LPARAM, POINTL, PWSTR},
System::{
Com::{IDataObject, DVASPECT_CONTENT, FORMATETC, TYMED_HGLOBAL},
Ole::{IDropTarget, RegisterDragDrop, RevokeDragDrop, DROPEFFECT_COPY, DROPEFFECT_NONE},
SystemServices::CF_HDROP,
},
UI::{
Shell::{DragFinish, DragQueryFileW, HDROP},
WindowsAndMessaging::EnumChildWindows,
use windows::Win32::{
Foundation::{self as win32f, BOOL, DRAGDROP_E_INVALIDHWND, HWND, LPARAM, POINTL},
System::{
Com::{IDataObject, DVASPECT_CONTENT, FORMATETC, TYMED_HGLOBAL},
Ole::{
IDropTarget, IDropTarget_Impl, RegisterDragDrop, RevokeDragDrop, DROPEFFECT_COPY,
DROPEFFECT_NONE,
},
SystemServices::CF_HDROP,
},
UI::{
Shell::{DragFinish, DragQueryFileW, HDROP},
WindowsAndMessaging::EnumChildWindows,
},
};

use windows_macros::implement;
use windows_implement::implement;

use crate::application::window::Window;

Expand Down Expand Up @@ -102,15 +103,14 @@ unsafe extern "system" fn enumerate_callback(hwnd: HWND, lparam: LPARAM) -> BOOL
closure(hwnd).into()
}

#[implement(Windows::Win32::System::Ole::IDropTarget)]
#[implement(IDropTarget)]
pub struct FileDropHandler {
window: Rc<Window>,
listener: Rc<dyn Fn(&Window, FileDropEvent) -> bool>,
cursor_effect: u32,
hovered_is_valid: bool, /* If the currently hovered item is not valid there must not be any `HoveredFileCancelled` emitted */
cursor_effect: UnsafeCell<u32>,
hovered_is_valid: UnsafeCell<bool>, /* If the currently hovered item is not valid there must not be any `HoveredFileCancelled` emitted */
}

#[allow(non_snake_case)]
impl FileDropHandler {
pub fn new(
window: Rc<Window>,
Expand All @@ -119,78 +119,21 @@ impl FileDropHandler {
Self {
window,
listener,
cursor_effect: DROPEFFECT_NONE,
hovered_is_valid: false,
}
}

unsafe fn DragEnter(
&mut self,
pDataObj: &Option<IDataObject>,
_grfKeyState: u32,
_pt: POINTL,
pdwEffect: *mut u32,
) -> windows::core::Result<()> {
let mut paths = Vec::new();
let hdrop = Self::collect_paths(pDataObj, &mut paths);
self.hovered_is_valid = hdrop.is_some();
self.cursor_effect = if self.hovered_is_valid {
DROPEFFECT_COPY
} else {
DROPEFFECT_NONE
};
*pdwEffect = self.cursor_effect;

(self.listener)(&self.window, FileDropEvent::Hovered(paths));

Ok(())
}

unsafe fn DragOver(
&self,
_grfKeyState: u32,
_pt: POINTL,
pdwEffect: *mut u32,
) -> windows::core::Result<()> {
*pdwEffect = self.cursor_effect;
Ok(())
}

unsafe fn DragLeave(&self) -> windows::core::Result<()> {
if self.hovered_is_valid {
(self.listener)(&self.window, FileDropEvent::Cancelled);
cursor_effect: DROPEFFECT_NONE.into(),
hovered_is_valid: false.into(),
}
Ok(())
}

unsafe fn Drop(
&self,
pDataObj: &Option<IDataObject>,
_grfKeyState: u32,
_pt: POINTL,
_pdwEffect: *mut u32,
) -> windows::core::Result<()> {
let mut paths = Vec::new();
let hdrop = Self::collect_paths(pDataObj, &mut paths);
if let Some(hdrop) = hdrop {
DragFinish(hdrop);
}

(self.listener)(&self.window, FileDropEvent::Dropped(paths));

Ok(())
}

unsafe fn collect_paths(
data_obj: &Option<IDataObject>,
paths: &mut Vec<PathBuf>,
) -> Option<HDROP> {
let drop_format = FORMATETC {
cfFormat: CF_HDROP as u16,
cfFormat: CF_HDROP.0 as u16,
ptd: ptr::null_mut(),
dwAspect: DVASPECT_CONTENT as u32,
dwAspect: DVASPECT_CONTENT.0 as u32,
lindex: -1,
tymed: TYMED_HGLOBAL as u32,
tymed: TYMED_HGLOBAL.0 as u32,
};

match data_obj
Expand All @@ -202,18 +145,18 @@ impl FileDropHandler {
let hdrop = HDROP(medium.Anonymous.hGlobal);

// The second parameter (0xFFFFFFFF) instructs the function to return the item count
let item_count = DragQueryFileW(hdrop, 0xFFFFFFFF, PWSTR::default(), 0);
let item_count = DragQueryFileW(hdrop, 0xFFFFFFFF, &mut []);

for i in 0..item_count {
// Get the length of the path string NOT including the terminating null character.
// 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, PWSTR::default(), 0) as usize;
let character_count = DragQueryFileW(hdrop, i, &mut []) as usize;
let str_len = character_count + 1;

// Fill path_buf with the null-terminated file name
let mut path_buf = Vec::with_capacity(str_len);
DragQueryFileW(hdrop, i, PWSTR(path_buf.as_mut_ptr()), str_len as u32);
DragQueryFileW(hdrop, i, std::mem::transmute(path_buf.spare_capacity_mut()));
path_buf.set_len(str_len);

paths.push(OsString::from_wide(&path_buf[0..character_count]).into());
Expand All @@ -238,3 +181,69 @@ impl FileDropHandler {
}
}
}

#[allow(non_snake_case)]
impl IDropTarget_Impl for FileDropHandler {
fn DragEnter(
&self,
pDataObj: &Option<IDataObject>,
_grfKeyState: u32,
_pt: &POINTL,
pdwEffect: *mut u32,
) -> windows::core::Result<()> {
let mut paths = Vec::new();
unsafe {
let hdrop = Self::collect_paths(pDataObj, &mut paths);
let hovered_is_valid = hdrop.is_some();
let cursor_effect = if hovered_is_valid {
DROPEFFECT_COPY
} else {
DROPEFFECT_NONE
};
*pdwEffect = cursor_effect;
*self.hovered_is_valid.get() = hovered_is_valid;
*self.cursor_effect.get() = cursor_effect;
}

(self.listener)(&self.window, FileDropEvent::Hovered(paths));

Ok(())
}

fn DragOver(
&self,
_grfKeyState: u32,
_pt: &POINTL,
pdwEffect: *mut u32,
) -> windows::core::Result<()> {
unsafe { *pdwEffect = *self.cursor_effect.get() };
Ok(())
}

fn DragLeave(&self) -> windows::core::Result<()> {
if unsafe { *self.hovered_is_valid.get() } {
(self.listener)(&self.window, FileDropEvent::Cancelled);
}
Ok(())
}

fn Drop(
&self,
pDataObj: &Option<IDataObject>,
_grfKeyState: u32,
_pt: &POINTL,
_pdwEffect: *mut u32,
) -> windows::core::Result<()> {
let mut paths = Vec::new();
unsafe {
let hdrop = Self::collect_paths(pDataObj, &mut paths);
if let Some(hdrop) = hdrop {
DragFinish(hdrop);
}
}

(self.listener)(&self.window, FileDropEvent::Dropped(paths));

Ok(())
}
}

0 comments on commit 9d9d9d8

Please sign in to comment.