From d62d4da1283d4a2ca3fc5e9184a72c85c69b4482 Mon Sep 17 00:00:00 2001 From: Lej77 <31554212+Lej77@users.noreply.github.com> Date: Mon, 1 Apr 2024 23:42:12 +0200 Subject: [PATCH 01/11] Revert "Support Windows 10 and Windows 11 at the same time" This reverts commit 2c11b69b6d94e20ad92df06f9f296a12e471f47e. --- Cargo.toml | 10 +- dll/src/lib.rs | 31 +- src/comobjects.rs | 289 ++++++----- src/desktop.rs | 27 +- src/interfaces.rs | 431 +++++++++++++--- src/interfaces/build_10240.rs | 366 ------------- src/interfaces/build_22000.rs | 409 --------------- src/interfaces/build_dyn.rs | 940 ---------------------------------- src/listener.rs | 53 +- 9 files changed, 592 insertions(+), 1964 deletions(-) delete mode 100644 src/interfaces/build_10240.rs delete mode 100644 src/interfaces/build_22000.rs delete mode 100644 src/interfaces/build_dyn.rs diff --git a/Cargo.toml b/Cargo.toml index 8d5e3a8..650384c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,12 +14,10 @@ windows = { version = "0.52", features = [ # Find WinApi features with searching here https://microsoft.github.io/windows-docs-rs/ "implement", "Win32_System_Com", - "Win32_UI_Shell_Common", # for IObjectArray - "Win32_UI_WindowsAndMessaging", # for TranslateMessage etc. - "Win32_Foundation", # for FindWindowW - "Win32_System_Threading", # For CreateThread - "Win32_System_SystemInformation", # For RtlGetVersion return type - "Wdk_System_SystemServices", # For RtlGetVersion + "Win32_UI_Shell_Common", # for IObjectArray + "Win32_UI_WindowsAndMessaging", # for TranslateMessage etc. + "Win32_Foundation", # for FindWindowW + "Win32_System_Threading", # For CreateThread ] } windows-interface = { version = "0.52" } windows-implement = { version = "0.52" } diff --git a/dll/src/lib.rs b/dll/src/lib.rs index 376c57e..07f5483 100644 --- a/dll/src/lib.rs +++ b/dll/src/lib.rs @@ -1,4 +1,4 @@ -#![allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)] +#![allow(non_snake_case)] use once_cell::sync::Lazy; use std::{ @@ -40,7 +40,7 @@ pub extern "C" fn GetDesktopIdByNumber(number: i32) -> GUID { #[no_mangle] pub extern "C" fn GetDesktopNumberById(desktop_id: GUID) -> i32 { - get_desktop(desktop_id) + get_desktop(&desktop_id) .get_index() .map_or(-1, |x| x as i32) } @@ -120,20 +120,23 @@ pub extern "C" fn RegisterPostMessageHook(listener_hwnd: HWND, message_offset: u log::log_output("RegisterPostMessageHook: create new threads"); let listener_thread = std::thread::spawn(move || { for item in rx { - if let DesktopEvent::DesktopChanged { new, old } = item { - let new_index = new.get_index().unwrap_or(0); - let old_index = old.get_index().unwrap_or(0); - let a = LISTENER_HWNDS.lock().unwrap(); - for hwnd in a.iter() { - unsafe { - let _ = PostMessageW( - HWND(*hwnd), - message_offset, - WPARAM(old_index as usize), - LPARAM(new_index as isize), - ); + match item { + DesktopEvent::DesktopChanged { new, old } => { + let new_index = new.get_index().unwrap_or(0); + let old_index = old.get_index().unwrap_or(0); + let a = LISTENER_HWNDS.lock().unwrap(); + for hwnd in a.iter() { + unsafe { + let _ = PostMessageW( + HWND(*hwnd as isize), + message_offset, + WPARAM(old_index as usize), + LPARAM(new_index as isize), + ); + } } } + _ => (), } } }); diff --git a/src/comobjects.rs b/src/comobjects.rs index ea72d39..94becd9 100644 --- a/src/comobjects.rs +++ b/src/comobjects.rs @@ -1,7 +1,4 @@ -//! This module contains COM object for accessing the Windows Virtual Desktop API -#![allow(clippy::bool_assert_comparison)] -#![allow(clippy::upper_case_acronyms)] - +/// This module contains COM object for accessing the Windows Virtual Desktop API use super::interfaces::*; use super::Result; use std::convert::TryFrom; @@ -52,14 +49,6 @@ pub enum Error { /// Generic element not found ComElementNotFound, - /// A requested interface was not supported. Windows might have changed the - /// definitions of some unstable virtual desktop interfaces used by this - /// library. - ComNoInterface, - - /// Not implemented - ComNotImplemented, - /// Some unhandled COM error ComError(HRESULT), @@ -79,37 +68,27 @@ trait HRESULTHelpers { impl HRESULTHelpers for ::windows::core::HRESULT { fn as_error(&self) -> Error { - match self.0 { - -2147221164 => { - // 0x80040154 - Error::ClassNotRegistered - } - -2147023174 => { - // 0x800706BA - Error::RpcServerNotAvailable - } - -2147220995 => { - // 0x800401FD - Error::ComObjectNotConnected - } - -2147319765 => { - // 0x8002802B - Error::ComElementNotFound - } - -2147221008 => { - // 0x800401F0 - Error::ComNotInitialized - } - -2147467262 => { - // 0x80004002 - Error::ComNoInterface - } - -2147467263 => { - // 0x80004001 - Error::ComNotImplemented - } - _ => Error::ComError(*self), + if self.0 == -2147221164 { + // 0x80040154 + return Error::ClassNotRegistered; + } + if self.0 == -2147023174 { + // 0x800706BA + return Error::RpcServerNotAvailable; } + if self.0 == -2147220995 { + // 0x800401FD + return Error::ComObjectNotConnected; + } + if self.0 == -2147319765 { + // 0x8002802B + return Error::ComElementNotFound; + } + if self.0 == -2147221008 { + // 0x800401F0 + return Error::ComNotInitialized; + } + Error::ComError(self.clone()) } fn as_result(&self) -> Result<()> { @@ -166,7 +145,16 @@ impl<'a> TryFrom<&'a IVirtualDesktop> for DesktopInternal { fn try_from(desktop: &'a IVirtualDesktop) -> Result { let mut guid = GUID::default(); - desktop.get_id(&mut guid).as_result()?; + unsafe { desktop.get_id(&mut guid).as_result()? } + Ok(DesktopInternal::Guid(guid)) + } +} +impl<'a> TryFrom<&'a ComIn<'a, IVirtualDesktop>> for DesktopInternal { + type Error = Error; + + fn try_from(desktop: &'a ComIn<'a, IVirtualDesktop>) -> Result { + let mut guid = GUID::default(); + unsafe { desktop.get_id(&mut guid).as_result()? } Ok(DesktopInternal::Guid(guid)) } } @@ -180,7 +168,7 @@ pub struct ComObjects { view_collection: RefCell>>, } -fn retry_function(com_objects: &ComObjects, f: F, fn_name: &str) -> Result +fn retry_function(com_objects: &ComObjects, f: F) -> Result where F: Fn() -> Result, { @@ -195,7 +183,7 @@ where || er == &Error::ComNotInitialized => { #[cfg(debug_assertions)] - log_output(&format!("Retry the function \"{fn_name}\" after {:?}", er)); + log_output(&format!("Retry the function after {:?}", er)); if er == &Error::ComNotInitialized { let _ = unsafe { CoIncrementMTAUsage() }; @@ -217,10 +205,7 @@ where #[cfg(debug_assertions)] if let Err(er) = &value { - log_output(&format!( - "Com_objects function \"{fn_name}\" failed with {:?}", - er - )); + log_output(&format!("Com_objects function failed with {:?}", er)); } value @@ -248,7 +233,7 @@ macro_rules! retry_function {( { retry_function(&$self_, || -> $RetTy { $body - }, stringify!($fname)) + }) } )} @@ -278,7 +263,7 @@ impl ComObjects { provider .as_ref() - .map(Rc::clone) + .map(|v| Rc::clone(&v)) .ok_or(Error::ComAllocatedNullPtr) } @@ -304,7 +289,7 @@ impl ComObjects { } manager .as_ref() - .map(Rc::clone) + .map(|v| Rc::clone(&v)) .ok_or(Error::ComAllocatedNullPtr) } @@ -320,7 +305,7 @@ impl ComObjects { provider .query_service( &CLSID_VirtualDesktopManagerInternal, - &IVirtualDesktopManagerInternal::IID(), + &IVirtualDesktopManagerInternal::IID, &mut obj, ) .as_result()?; @@ -332,7 +317,7 @@ impl ComObjects { } manager_internal .as_ref() - .map(Rc::clone) + .map(|v| Rc::clone(&v)) .ok_or(Error::ComAllocatedNullPtr) } @@ -348,7 +333,7 @@ impl ComObjects { provider .query_service( &CLSID_IVirtualNotificationService, - &IVirtualDesktopNotificationService::IID(), + &IVirtualDesktopNotificationService::IID, &mut obj, ) .as_result()?; @@ -360,7 +345,7 @@ impl ComObjects { } notification_service .as_ref() - .map(Rc::clone) + .map(|v| Rc::clone(&v)) .ok_or(Error::ComAllocatedNullPtr) } @@ -376,7 +361,7 @@ impl ComObjects { provider .query_service( &CLSID_VirtualDesktopPinnedApps, - &IVirtualDesktopPinnedApps::IID(), + &IVirtualDesktopPinnedApps::IID, &mut obj, ) .as_result()?; @@ -387,7 +372,7 @@ impl ComObjects { pinned_apps .as_ref() .ok_or(Error::ComAllocatedNullPtr) - .map(Rc::clone) + .map(|a| Rc::clone(a)) } fn get_view_collection(&self) -> Result> { @@ -401,8 +386,8 @@ impl ComObjects { unsafe { provider .query_service( - &IApplicationViewCollection::IID(), - &IApplicationViewCollection::IID(), + &IApplicationViewCollection::IID, + &IApplicationViewCollection::IID, &mut obj, ) .as_result()?; @@ -414,7 +399,7 @@ impl ComObjects { } view_collection .as_ref() - .map(Rc::clone) + .map(|v| Rc::clone(&v)) .ok_or(Error::ComAllocatedNullPtr) } @@ -448,9 +433,11 @@ impl ComObjects { match self.get_manager_internal() { Ok(manager_internal) => { let mut out_count = 0; - let res = manager_internal - .get_desktop_count(&mut out_count) - .as_result(); + let res = unsafe { + manager_internal + .get_desktop_count(&mut out_count) + .as_result() + }; #[cfg(debug_assertions)] if let Err(er) = &res { @@ -468,9 +455,11 @@ impl ComObjects { fn get_idesktops_array(&self) -> Result { let mut desktops = None; - self.get_manager_internal()? - .get_desktops(&mut desktops) - .as_result()?; + unsafe { + self.get_manager_internal()? + .get_desktops(&mut desktops) + .as_result()? + } desktops.ok_or(Error::ComAllocatedNullPtr) } @@ -478,7 +467,7 @@ impl ComObjects { let desktops = self.get_idesktops_array()?; let count = unsafe { desktops.GetCount()? }; for i in 0..count { - let desktop_id: GUID = get_idesktop_guid(&unsafe { IObjectArrayGetAt(&desktops, i)? })?; + let desktop_id: GUID = get_idesktop_guid(&unsafe { desktops.GetAt(i)? })?; if desktop_id == *id { return Ok(i); } @@ -492,7 +481,7 @@ impl ComObjects { if id >= count { return Err(Error::DesktopNotFound); } - get_idesktop_guid(&unsafe { IObjectArrayGetAt(&desktops, id)? }) + get_idesktop_guid(&unsafe { desktops.GetAt(id)? }) } fn get_idesktop(&self, desktop: &DesktopInternal) -> Result { @@ -503,18 +492,22 @@ impl ComObjects { if *id >= count { return Err(Error::DesktopNotFound); } - Ok(unsafe { IObjectArrayGetAt(&desktops, *id)? }) + Ok(unsafe { desktops.GetAt(*id)? }) } DesktopInternal::Guid(id) => { let manager = self.get_manager_internal()?; let mut desktop = None; - manager.find_desktop(id, &mut desktop).as_result()?; + unsafe { + manager.find_desktop(id, &mut desktop).as_result()?; + } desktop.ok_or(Error::DesktopNotFound) } DesktopInternal::IndexGuid(_, id) => { let manager = self.get_manager_internal()?; let mut desktop = None; - manager.find_desktop(id, &mut desktop).as_result()?; + unsafe { + manager.find_desktop(id, &mut desktop).as_result()?; + } desktop.ok_or(Error::DesktopNotFound) } } @@ -522,22 +515,22 @@ impl ComObjects { fn move_view_to_desktop( &self, - view: &IApplicationView, + view: ComIn, desktop: &DesktopInternal, ) -> Result<()> { let desktop = self.get_idesktop(desktop)?; - - self.get_manager_internal()? - .move_view_to_desktop(view, &desktop) - .as_result() - .map_err(|e| { - if e == Error::ComElementNotFound { - Error::DesktopNotFound - } else { - e - } - })?; - + unsafe { + self.get_manager_internal()? + .move_view_to_desktop(view, ComIn::new(&desktop)) + .as_result() + .map_err(|e| { + if e == Error::ComElementNotFound { + Error::DesktopNotFound + } else { + e + } + })? + } Ok(()) } @@ -545,7 +538,7 @@ impl ComObjects { let mut view = None; unsafe { self.get_view_collection()? - .get_view_for_hwnd(*hwnd, &mut view) + .get_view_for_hwnd(hwnd.clone(), &mut view) .as_result() .map_err(|er| { if er == Error::ComElementNotFound { @@ -582,7 +575,7 @@ impl ComObjects { let count = unsafe { desktops.GetCount()? }; let mut result = Vec::with_capacity(count as usize); for i in 0..count { - let desktop = unsafe { IObjectArrayGetAt(&desktops, i)? }; + let desktop = unsafe { desktops.GetAt(i)? }; let id = get_idesktop_guid(&desktop)?; result.push(DesktopInternal::IndexGuid(i, id)); } @@ -592,39 +585,45 @@ impl ComObjects { #[apply(retry_function)] pub fn register_for_notifications( &self, - notification: &IVirtualDesktopNotification, - // notification: *mut c_void, // IVirtualDesktopNotification raw pointer + // notification: &IVirtualDesktopNotification, + notification: *mut c_void, // IVirtualDesktopNotification raw pointer ) -> Result { let notification_service = self.get_notification_service()?; - let mut cookie = 0; - notification_service - .register(notification, &mut cookie) - .as_result() - .map(|_| cookie) + unsafe { + let mut cookie = 0; + notification_service + .register(notification, &mut cookie) + .as_result() + .map(|_| cookie) + } } #[apply(retry_function)] pub fn unregister_for_notifications(&self, cookie: u32) -> Result<()> { let notification_service = self.get_notification_service()?; - notification_service.unregister(cookie).as_result() + unsafe { notification_service.unregister(cookie).as_result() } } #[apply(retry_function)] pub fn switch_desktop(&self, desktop: &DesktopInternal) -> Result<()> { let desktop = self.get_idesktop(desktop)?; - self.get_manager_internal()? - .switch_desktop(&desktop) - .as_result()?; + unsafe { + self.get_manager_internal()? + .switch_desktop(ComIn::new(&desktop)) + .as_result()? + } Ok(()) } #[apply(retry_function)] pub fn create_desktop(&self) -> Result { let mut desktop = None; - self.get_manager_internal()? - .create_desktop(&mut desktop) - .as_result()?; + unsafe { + self.get_manager_internal()? + .create_desktop(&mut desktop) + .as_result()? + } let desktop = desktop.ok_or(Error::ComAllocatedNullPtr)?; let id = get_idesktop_guid(&desktop)?; let index = self.get_desktop_index_by_guid(&id)?; @@ -639,16 +638,18 @@ impl ComObjects { ) -> Result<()> { let desktop = self.get_idesktop(desktop)?; let fb_desktop = self.get_idesktop(fallback_desktop)?; - self.get_manager_internal()? - .remove_desktop(&desktop, &fb_desktop) - .as_result()?; + unsafe { + self.get_manager_internal()? + .remove_desktop(ComIn::new(&desktop), ComIn::new(&fb_desktop)) + .as_result()? + } Ok(()) } #[apply(retry_function)] pub fn is_window_on_desktop(&self, window: &HWND, desktop: &DesktopInternal) -> Result { let desktop_win = self.get_desktop_by_window(window)?; - Ok(self.get_desktop_id(&desktop_win)? == self.get_desktop_id(desktop)?) + Ok(self.get_desktop_id(&desktop_win)? == self.get_desktop_id(&*desktop)?) } #[apply(retry_function)] @@ -656,7 +657,7 @@ impl ComObjects { unsafe { let mut value = false; self.get_manager()? - .is_window_on_current_desktop(*window, &mut value) + .is_window_on_current_desktop(window.clone(), &mut value) .as_result() .map_err(|er| match er { // Window does not exist @@ -670,14 +671,16 @@ impl ComObjects { #[apply(retry_function)] pub fn move_window_to_desktop(&self, window: &HWND, desktop: &DesktopInternal) -> Result<()> { let view = self.get_iapplication_view_for_hwnd(window)?; - self.move_view_to_desktop(&view, desktop) + self.move_view_to_desktop(ComIn::new(&view), desktop) } #[apply(retry_function)] pub fn get_desktop_count(&self) -> Result { let manager = self.get_manager_internal()?; let mut count = 0; - manager.get_desktop_count(&mut count).as_result()?; + unsafe { + manager.get_desktop_count(&mut count).as_result()?; + }; Ok(count) } @@ -686,7 +689,7 @@ impl ComObjects { let mut desktop = GUID::default(); unsafe { self.get_manager()? - .get_desktop_by_window(*window, &mut desktop) + .get_desktop_by_window(window.clone(), &mut desktop) .as_result() .map_err(|er| match er { // Window does not exist @@ -703,9 +706,11 @@ impl ComObjects { #[apply(retry_function)] pub fn get_current_desktop(&self) -> Result { let mut desktop = None; - self.get_manager_internal()? - .get_current_desktop(&mut desktop) - .as_result()?; + unsafe { + self.get_manager_internal()? + .get_current_desktop(&mut desktop) + .as_result()? + } let desktop = desktop.ok_or(Error::ComAllocatedNullPtr)?; let id = get_idesktop_guid(&desktop)?; Ok(DesktopInternal::Guid(id)) @@ -714,24 +719,34 @@ impl ComObjects { #[apply(retry_function)] pub fn is_pinned_window(&self, window: &HWND) -> Result { let view = self.get_iapplication_view_for_hwnd(window)?; - let mut value = false; - self.get_pinned_apps()? - .is_view_pinned(&view, &mut value) - .as_result()?; - Ok(value) + unsafe { + let mut value = false; + self.get_pinned_apps()? + .is_view_pinned(ComIn::new(&view), &mut value) + .as_result()?; + Ok(value) + } } #[apply(retry_function)] pub fn pin_window(&self, window: &HWND) -> Result<()> { let view = self.get_iapplication_view_for_hwnd(window)?; - self.get_pinned_apps()?.pin_view(&view).as_result()?; + unsafe { + self.get_pinned_apps()? + .pin_view(ComIn::new(&view)) + .as_result()?; + } Ok(()) } #[apply(retry_function)] pub fn unpin_window(&self, window: &HWND) -> Result<()> { let view = self.get_iapplication_view_for_hwnd(window)?; - self.get_pinned_apps()?.unpin_view(&view).as_result()?; + unsafe { + self.get_pinned_apps()? + .unpin_view(ComIn::new(&view)) + .as_result()?; + } Ok(()) } @@ -780,43 +795,51 @@ impl ComObjects { #[apply(retry_function)] pub fn get_desktop_name(&self, desktop: &DesktopInternal) -> Result { - let desktop = self.get_idesktop(desktop)?; + let desktop = self.get_idesktop(&desktop)?; let mut name = HSTRING::default(); - desktop.get_name(&mut name).as_result()?; + unsafe { + desktop.get_name(&mut name).as_result()?; + } Ok(name.to_string()) } #[apply(retry_function)] pub fn set_desktop_name(&self, desktop: &DesktopInternal, name: &str) -> Result<()> { - let desktop = self.get_idesktop(desktop)?; + let desktop = self.get_idesktop(&desktop)?; let manager_internal = self.get_manager_internal()?; - manager_internal - .set_name(&desktop, HSTRING::from(name)) - .as_result() + unsafe { + manager_internal + .set_name(ComIn::new(&desktop), HSTRING::from(name)) + .as_result() + } } #[apply(retry_function)] pub fn get_desktop_wallpaper(&self, desktop: &DesktopInternal) -> Result { - let desktop = self.get_idesktop(desktop)?; + let desktop = self.get_idesktop(&desktop)?; let mut path = HSTRING::default(); - desktop.get_wallpaper(&mut path).as_result()?; + unsafe { + desktop.get_wallpaper(&mut path).as_result()?; + } Ok(path.to_string()) } #[apply(retry_function)] pub fn set_desktop_wallpaper(&self, desktop: &DesktopInternal, path: &str) -> Result<()> { let manager_internal = self.get_manager_internal()?; - let desktop = self.get_idesktop(desktop)?; - manager_internal - .set_wallpaper(&desktop, HSTRING::from(path)) - .as_result() + let desktop = self.get_idesktop(&desktop)?; + unsafe { + manager_internal + .set_wallpaper(ComIn::new(&desktop), HSTRING::from(path)) + .as_result() + } } } fn get_idesktop_guid(desktop: &IVirtualDesktop) -> Result { let mut guid = GUID::default(); - desktop.get_id(&mut guid).as_result()?; + unsafe { desktop.get_id(&mut guid).as_result()? } Ok(guid) } @@ -841,5 +864,5 @@ where // }); // return COM_OBJECTS.with(|c| run_function_and_retry(&f, &c)); - COM_OBJECTS.with(|c| f(c)) + return COM_OBJECTS.with(|c| f(&c)); } diff --git a/src/desktop.rs b/src/desktop.rs index 27d0a90..a5f5a50 100644 --- a/src/desktop.rs +++ b/src/desktop.rs @@ -1,3 +1,5 @@ +use crate::interfaces::ComIn; + use super::comobjects::*; use super::{interfaces::IVirtualDesktop, *}; use std::{convert::TryFrom, fmt::Debug}; @@ -76,47 +78,54 @@ impl TryFrom for Desktop { Ok(Desktop(DesktopInternal::try_from(&desktop)?)) } } -impl<'a> TryFrom<&'a IVirtualDesktop> for Desktop { +impl<'a> TryFrom<&'a ComIn<'a, IVirtualDesktop>> for Desktop { type Error = Error; - fn try_from(desktop: &'a IVirtualDesktop) -> Result { + fn try_from(desktop: &'a ComIn<'a, IVirtualDesktop>) -> Result { Ok(Desktop(DesktopInternal::try_from(desktop)?)) } } +impl<'a> TryFrom> for Desktop { + type Error = Error; + + fn try_from(desktop: ComIn<'a, IVirtualDesktop>) -> Result { + Ok(Desktop(DesktopInternal::try_from(&desktop)?)) + } +} impl Desktop { /// Get the GUID of the desktop pub fn get_id(&self) -> Result { - let internal = self.0; + let internal = self.0.clone(); with_com_objects(move |o| o.get_desktop_id(&internal)) } pub fn get_index(&self) -> Result { - let internal = self.0; + let internal = self.0.clone(); with_com_objects(move |o| o.get_desktop_index(&internal)) } /// Get desktop name pub fn get_name(&self) -> Result { - let internal = self.0; + let internal = self.0.clone(); with_com_objects(move |o| o.get_desktop_name(&internal)) } /// Set desktop name pub fn set_name(&self, name: &str) -> Result<()> { - let internal = self.0; + let internal = self.0.clone(); let name_ = name.to_owned(); with_com_objects(move |o| o.set_desktop_name(&internal, &name_)) } /// Get desktop wallpaper path pub fn get_wallpaper(&self) -> Result { - let internal = self.0; + let internal = self.0.clone(); with_com_objects(move |o| o.get_desktop_wallpaper(&internal)) } /// Set desktop wallpaper path pub fn set_wallpaper(&self, path: &str) -> Result<()> { - let internal = self.0; + let internal = self.0.clone(); let path_ = path.to_owned(); with_com_objects(move |o| o.set_desktop_wallpaper(&internal, &path_)) } @@ -172,7 +181,7 @@ where T: Into, T: Send + 'static + Copy, { - let hwnd = *hwnd; + let hwnd = hwnd.clone(); with_com_objects(move |o| o.move_window_to_desktop(&hwnd, &desktop.into().into())) } diff --git a/src/interfaces.rs b/src/interfaces.rs index 7d33699..34d7035 100644 --- a/src/interfaces.rs +++ b/src/interfaces.rs @@ -1,41 +1,40 @@ -//! Interface definitions for the Virtual Desktop API -//! -//! Most of the functions are not tested or used, beware if you try to use these -//! for something else. Notably I know that most out parameters defined as `*mut -//! IMyObject` are incorrect, they probably should be *mut Option. -//! -//! Generally these are the rules: -//! 1. InOpt = `Option>` or `Option>` -//! 2. In = `ComIn` or `ManuallyDrop` -//! 3. Out = `*mut Option` -//! 4. OutOpt = `*mut Option` -//! -//! Last two are same intentionally. -//! -//! ## The summary of COM object lifetime rules: -//! -//! > 1. When a COM object is passed from caller to callee as an input parameter -//! > to a method, the caller is expected to keep a reference on the object -//! > for the duration of the method call. The callee shouldn't need to call -//! > `AddRef` or `Release` for the synchronous duration of that method call. -//! > -//! > 2. When a COM object is passed from callee to caller as an out parameter -//! > from a method the object is provided to the caller with a reference -//! > already taken and the caller owns the reference. Which is to say, it is -//! > the caller's responsibility to call `Release` when they're done with -//! > the object. -//! > -//! > 3. When making a copy of a COM object pointer you need to call `AddRef` -//! > and `Release`. The `AddRef` must be called before you call `Release` on -//! > the original COM object pointer. -//! -//! Rules as [written by David -//! Risney](https://github.com/MicrosoftEdge/WebView2Feedback/issues/2133). -//! -//! If you read the rules carefully, ComIn is most common usecase in Rust -//! API definitions as most parameters are `In` parameters. -#![allow(non_upper_case_globals, clippy::upper_case_acronyms)] - +/// Interface definitions for the Virtual Desktop API +/// +/// Most of the functions are not tested or used, beware if you try to use these +/// for something else. Notably I know that most out parameters defined as `*mut +/// IMyObject` are incorrect, they probably should be *mut Option. +/// +/// Generally these are the rules: +/// 1. InOpt = `Option>` or `Option>` +/// 2. In = `ComIn` or `ManuallyDrop` +/// 3. Out = `*mut Option` +/// 4. OutOpt = `*mut Option` +/// +/// Last two are same intentionally. +/// +/// ## The summary of COM object lifetime rules: +/// +/// > 1. When a COM object is passed from caller to callee as an input parameter +/// > to a method, the caller is expected to keep a reference on the object +/// > for the duration of the method call. The callee shouldn't need to call +/// > `AddRef` or `Release` for the synchronous duration of that method call. +/// > +/// > 2. When a COM object is passed from callee to caller as an out parameter +/// > from a method the object is provided to the caller with a reference +/// > already taken and the caller owns the reference. Which is to say, it is +/// > the caller's responsibility to call `Release` when they're done with +/// > the object. +/// > +/// > 3. When making a copy of a COM object pointer you need to call `AddRef` +/// > and `Release`. The `AddRef` must be called before you call `Release` on +/// > the original COM object pointer. +/// +/// Rules as [written by David +/// Risney](https://github.com/MicrosoftEdge/WebView2Feedback/issues/2133). +/// +/// If you read the rules carefully, ComIn is most common usecase in Rust +/// API definitions as most parameters are `In` parameters. +#[allow(non_upper_case_globals)] use std::ffi::c_void; use std::ops::Deref; use windows::{ @@ -43,15 +42,6 @@ use windows::{ Win32::{Foundation::HWND, UI::Shell::Common::IObjectArray}, }; -// Different versions of Windows have slightly different interfaces: -mod build_10240; -mod build_22000; -mod build_dyn; - -// We only consume the COM interfaces in a way where we don't depend on the -// exact Windows version: -pub use build_dyn::*; - /// ComIn is a wrapper for COM objects that are passed as input parameters. It /// allows to keep the life of the COM object for the duration of the function /// call. @@ -109,27 +99,42 @@ impl<'a, T: ComInterface> ComIn<'a, T> { impl<'a, T: ComInterface> Deref for ComIn<'a, T> { type Target = T; fn deref(&self) -> &Self::Target { - // Safety: A ComInterface type `T` is just a transparent type over a raw pointer - unsafe { &*(&self.data as *const *mut c_void as *const T) } + unsafe { std::mem::transmute(&self.data) } } } #[allow(non_upper_case_globals)] -pub const CLSID_ImmersiveShell: GUID = GUID::from_u128(0xC2F03A33_21F5_47FA_B4BB_156362A2F239); +pub const CLSID_ImmersiveShell: GUID = GUID { + data1: 0xC2F03A33, + data2: 0x21F5, + data3: 0x47FA, + data4: [0xB4, 0xBB, 0x15, 0x63, 0x62, 0xA2, 0xF2, 0x39], +}; #[allow(dead_code)] #[allow(non_upper_case_globals)] -pub const CLSID_IVirtualNotificationService: GUID = - GUID::from_u128(0xA501FDEC_4A09_464C_AE4E_1B9C21B84918); +pub const CLSID_IVirtualNotificationService: GUID = GUID { + data1: 0xA501FDEC, + data2: 0x4A09, + data3: 0x464C, + data4: [0xAE, 0x4E, 0x1B, 0x9C, 0x21, 0xB8, 0x49, 0x18], +}; #[allow(non_upper_case_globals)] -pub const CLSID_VirtualDesktopManagerInternal: GUID = - GUID::from_u128(0xC5E0CDCA_7B6E_41B2_9FC4_D93975CC467B); +pub const CLSID_VirtualDesktopManagerInternal: GUID = GUID { + data1: 0xC5E0CDCA, + data2: 0x7B6E, + data3: 0x41B2, + data4: [0x9F, 0xC4, 0xD9, 0x39, 0x75, 0xCC, 0x46, 0x7B], +}; #[allow(non_upper_case_globals)] -pub const CLSID_VirtualDesktopPinnedApps: GUID = - GUID::from_u128(0xb5a399e7_1c87_46b8_88e9_fc5747b171bd); - +pub const CLSID_VirtualDesktopPinnedApps: GUID = GUID { + data1: 0xb5a399e7, + data2: 0x1c87, + data3: 0x46b8, + data4: [0x88, 0xe9, 0xfc, 0x57, 0x47, 0xb1, 0x71, 0xbd], +}; type BOOL = i32; type DWORD = u32; type INT = i32; @@ -154,7 +159,6 @@ type APPLICATION_VIEW_COMPATIBILITY_POLICY = UINT; type APPLICATION_VIEW_CLOAK_TYPE = UINT; #[allow(dead_code)] -#[repr(C)] pub struct RECT { left: LONG, top: LONG, @@ -163,14 +167,11 @@ pub struct RECT { } #[allow(dead_code)] -#[repr(C)] pub struct SIZE { cx: LONG, cy: LONG, } -// These COM interfaces are not different between different Windows versions: - #[windows_interface::interface("6D5140C1-7436-11CE-8034-00AA006009FA")] pub unsafe trait IServiceProvider: IUnknown { pub unsafe fn query_service( @@ -205,3 +206,311 @@ pub unsafe trait IVirtualDesktopManager: IUnknown { desktop_id: *const GUID, ) -> HRESULT; } + +#[windows_interface::interface("372E1D3B-38D3-42E4-A15B-8AB2B178F513")] +pub unsafe trait IApplicationView: IUnknown { + /* IInspecateble */ + pub unsafe fn get_iids( + &self, + out_iid_count: *mut ULONG, + out_opt_iid_array_ptr: *mut *mut GUID, + ) -> HRESULT; + pub unsafe fn get_runtime_class_name(&self, out_opt_class_name: *mut HSTRING) -> HRESULT; + pub unsafe fn get_trust_level(&self, ptr_trust_level: LPVOID) -> HRESULT; + + /* IApplicationView methods */ + pub unsafe fn set_focus(&self) -> HRESULT; + pub unsafe fn switch_to(&self) -> HRESULT; + + pub unsafe fn try_invoke_back(&self, ptr_async_callback: IAsyncCallback) -> HRESULT; + pub unsafe fn get_thumbnail_window(&self, out_hwnd: *mut HWND) -> HRESULT; + pub unsafe fn get_monitor(&self, out_monitors: *mut *mut IImmersiveMonitor) -> HRESULT; + pub unsafe fn get_visibility(&self, out_int: LPVOID) -> HRESULT; + pub unsafe fn set_cloak( + &self, + application_view_cloak_type: APPLICATION_VIEW_CLOAK_TYPE, + unknown: INT, + ) -> HRESULT; + pub unsafe fn get_position( + &self, + unknowniid: *const GUID, + unknown_array_ptr: LPVOID, + ) -> HRESULT; + pub unsafe fn set_position(&self, view_position: *mut IApplicationViewPosition) -> HRESULT; + pub unsafe fn insert_after_window(&self, window: HWND) -> HRESULT; + pub unsafe fn get_extended_frame_position(&self, rect: *mut RECT) -> HRESULT; + pub unsafe fn get_app_user_model_id(&self, id: *mut PWSTR) -> HRESULT; // Proc17 + pub unsafe fn set_app_user_model_id(&self, id: PCWSTR) -> HRESULT; + pub unsafe fn is_equal_by_app_user_model_id(&self, id: PCWSTR, out_result: *mut INT) + -> HRESULT; + + /*** IApplicationView methods ***/ + pub unsafe fn get_view_state(&self, out_state: *mut UINT) -> HRESULT; // Proc20 + pub unsafe fn set_view_state(&self, state: UINT) -> HRESULT; // Proc21 + pub unsafe fn get_neediness(&self, out_neediness: *mut INT) -> HRESULT; // Proc22 + pub unsafe fn get_last_activation_timestamp(&self, out_timestamp: *mut ULONGLONG) -> HRESULT; + pub unsafe fn set_last_activation_timestamp(&self, timestamp: ULONGLONG) -> HRESULT; + pub unsafe fn get_virtual_desktop_id(&self, out_desktop_guid: *mut GUID) -> HRESULT; + pub unsafe fn set_virtual_desktop_id(&self, desktop_guid: *const GUID) -> HRESULT; + pub unsafe fn get_show_in_switchers(&self, out_show: *mut INT) -> HRESULT; + pub unsafe fn set_show_in_switchers(&self, show: INT) -> HRESULT; + pub unsafe fn get_scale_factor(&self, out_scale_factor: *mut INT) -> HRESULT; + pub unsafe fn can_receive_input(&self, out_can: *mut BOOL) -> HRESULT; + pub unsafe fn get_compatibility_policy_type( + &self, + out_policy_type: *mut APPLICATION_VIEW_COMPATIBILITY_POLICY, + ) -> HRESULT; + pub unsafe fn set_compatibility_policy_type( + &self, + policy_type: APPLICATION_VIEW_COMPATIBILITY_POLICY, + ) -> HRESULT; + + pub unsafe fn get_size_constraints( + &self, + monitor: *mut IImmersiveMonitor, + out_size1: *mut SIZE, + out_size2: *mut SIZE, + ) -> HRESULT; + pub unsafe fn get_size_constraints_for_dpi( + &self, + dpi: UINT, + out_size1: *mut SIZE, + out_size2: *mut SIZE, + ) -> HRESULT; + pub unsafe fn set_size_constraints_for_dpi( + &self, + dpi: *const UINT, + size1: *const SIZE, + size2: *const SIZE, + ) -> HRESULT; + + pub unsafe fn on_min_size_preferences_updated(&self, window: HWND) -> HRESULT; + pub unsafe fn apply_operation(&self, operation: *mut IApplicationViewOperation) -> HRESULT; + pub unsafe fn is_tray(&self, out_is: *mut BOOL) -> HRESULT; + pub unsafe fn is_in_high_zorder_band(&self, out_is: *mut BOOL) -> HRESULT; + pub unsafe fn is_splash_screen_presented(&self, out_is: *mut BOOL) -> HRESULT; + pub unsafe fn flash(&self) -> HRESULT; + pub unsafe fn get_root_switchable_owner(&self, app_view: *mut IApplicationView) -> HRESULT; // proc45 + pub unsafe fn enumerate_ownership_tree(&self, objects: *mut IObjectArray) -> HRESULT; // proc46 + + pub unsafe fn get_enterprise_id(&self, out_id: *mut PWSTR) -> HRESULT; // proc47 + pub unsafe fn is_mirrored(&self, out_is: *mut BOOL) -> HRESULT; // + + pub unsafe fn unknown1(&self, arg: *mut INT) -> HRESULT; + pub unsafe fn unknown2(&self, arg: *mut INT) -> HRESULT; + pub unsafe fn unknown3(&self, arg: *mut INT) -> HRESULT; + pub unsafe fn unknown4(&self, arg: INT) -> HRESULT; + pub unsafe fn unknown5(&self, arg: *mut INT) -> HRESULT; + pub unsafe fn unknown6(&self, arg: INT) -> HRESULT; + pub unsafe fn unknown7(&self) -> HRESULT; + pub unsafe fn unknown8(&self, arg: *mut INT) -> HRESULT; + pub unsafe fn unknown9(&self, arg: INT) -> HRESULT; + pub unsafe fn unknown10(&self, arg: INT, arg2: INT) -> HRESULT; + pub unsafe fn unknown11(&self, arg: INT) -> HRESULT; + pub unsafe fn unknown12(&self, arg: *mut SIZE) -> HRESULT; +} + +#[windows_interface::interface("3F07F4BE-B107-441A-AF0F-39D82529072C")] +pub unsafe trait IVirtualDesktop: IUnknown { + pub unsafe fn is_view_visible( + &self, + p_view: ComIn, + out_bool: *mut u32, + ) -> HRESULT; + pub unsafe fn get_id(&self, out_guid: *mut GUID) -> HRESULT; + pub unsafe fn get_name(&self, out_string: *mut HSTRING) -> HRESULT; + pub unsafe fn get_wallpaper(&self, out_string: *mut HSTRING) -> HRESULT; +} + +#[windows_interface::interface("1841c6d7-4f9d-42c0-af41-8747538f10e5")] +pub unsafe trait IApplicationViewCollection: IUnknown { + pub unsafe fn get_views(&self, out_views: *mut IObjectArray) -> HRESULT; + + pub unsafe fn get_views_by_zorder(&self, out_views: *mut IObjectArray) -> HRESULT; + + pub unsafe fn get_views_by_app_user_model_id( + &self, + id: PCWSTR, + out_views: *mut IObjectArray, + ) -> HRESULT; + + pub unsafe fn get_view_for_hwnd( + &self, + window: HWND, + out_view: *mut Option, + ) -> HRESULT; + + pub unsafe fn get_view_for_application( + &self, + app: IImmersiveApplication, + out_view: *mut IApplicationView, + ) -> HRESULT; + + pub unsafe fn get_view_for_app_user_model_id( + &self, + id: PCWSTR, + out_view: *mut IApplicationView, + ) -> HRESULT; + + pub unsafe fn get_view_in_focus(&self, out_view: *mut IApplicationView) -> HRESULT; + + pub unsafe fn try_get_last_active_visible_view( + &self, + out_view: *mut IApplicationView, + ) -> HRESULT; + + pub unsafe fn refresh_collection(&self) -> HRESULT; + + pub unsafe fn register_for_application_view_changes( + &self, + listener: IApplicationViewChangeListener, + out_id: *mut DWORD, + ) -> HRESULT; + + pub unsafe fn unregister_for_application_view_changes(&self, id: DWORD) -> HRESULT; +} + +#[windows_interface::interface("B9E5E94D-233E-49AB-AF5C-2B4541C3AADE")] +pub unsafe trait IVirtualDesktopNotification: IUnknown { + pub unsafe fn virtual_desktop_created(&self, desktop: ComIn) -> HRESULT; + + pub unsafe fn virtual_desktop_destroy_begin( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT; + + pub unsafe fn virtual_desktop_destroy_failed( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT; + + pub unsafe fn virtual_desktop_destroyed( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT; + + pub unsafe fn virtual_desktop_moved( + &self, + desktop: ComIn, + old_index: i64, + new_index: i64, + ) -> HRESULT; + + pub unsafe fn virtual_desktop_name_changed( + &self, + desktop: ComIn, + name: HSTRING, + ) -> HRESULT; + + pub unsafe fn view_virtual_desktop_changed(&self, view: ComIn) -> HRESULT; + + pub unsafe fn current_virtual_desktop_changed( + &self, + desktop_old: ComIn, + desktop_new: ComIn, + ) -> HRESULT; + + pub unsafe fn virtual_desktop_wallpaper_changed( + &self, + desktop: ComIn, + name: HSTRING, + ) -> HRESULT; + + pub unsafe fn virtual_desktop_switched(&self, desktop: ComIn) -> HRESULT; + + pub unsafe fn remote_virtual_desktop_connected( + &self, + desktop: ComIn, + ) -> HRESULT; +} + +#[windows_interface::interface("0CD45E71-D927-4F15-8B0A-8FEF525337BF")] +pub unsafe trait IVirtualDesktopNotificationService: IUnknown { + pub unsafe fn register( + &self, + notification: *mut std::ffi::c_void, // *const IVirtualDesktopNotification, + out_cookie: *mut DWORD, + ) -> HRESULT; + + pub unsafe fn unregister(&self, cookie: u32) -> HRESULT; +} + +#[windows_interface::interface("53F5CA0B-158F-4124-900C-057158060B27")] +pub unsafe trait IVirtualDesktopManagerInternal: IUnknown { + pub unsafe fn get_desktop_count(&self, out_count: *mut UINT) -> HRESULT; + + pub unsafe fn move_view_to_desktop( + &self, + view: ComIn, + desktop: ComIn, + ) -> HRESULT; + + pub unsafe fn can_move_view_between_desktops( + &self, + view: ComIn, + can_move: *mut i32, + ) -> HRESULT; + + pub unsafe fn get_current_desktop(&self, out_desktop: *mut Option) -> HRESULT; + + pub unsafe fn get_desktops(&self, out_desktops: *mut Option) -> HRESULT; + + /// Get next or previous desktop + /// + /// Direction values: + /// 3 = Left direction + /// 4 = Right direction + pub unsafe fn get_adjacent_desktop( + &self, + in_desktop: ComIn, + direction: UINT, + out_pp_desktop: *mut Option, + ) -> HRESULT; + + pub unsafe fn switch_desktop(&self, desktop: ComIn) -> HRESULT; + + pub unsafe fn create_desktop(&self, out_desktop: *mut Option) -> HRESULT; + + pub unsafe fn move_desktop(&self, in_desktop: ComIn, index: UINT) -> HRESULT; + + pub unsafe fn remove_desktop( + &self, + destroy_desktop: ComIn, + fallback_desktop: ComIn, + ) -> HRESULT; + + pub unsafe fn find_desktop( + &self, + guid: *const GUID, + out_desktop: *mut Option, + ) -> HRESULT; + + pub unsafe fn get_desktop_switch_include_exclude_views( + &self, + desktop: ComIn, + out_pp_desktops1: *mut IObjectArray, + out_pp_desktops2: *mut IObjectArray, + ) -> HRESULT; + + pub unsafe fn set_name(&self, desktop: ComIn, name: HSTRING) -> HRESULT; + pub unsafe fn set_wallpaper(&self, desktop: ComIn, name: HSTRING) -> HRESULT; + pub unsafe fn update_wallpaper_for_all(&self, name: HSTRING) -> HRESULT; +} + +#[windows_interface::interface("4CE81583-1E4C-4632-A621-07A53543148F")] +pub unsafe trait IVirtualDesktopPinnedApps: IUnknown { + pub unsafe fn is_app_pinned(&self, app_id: PCWSTR, out_iss: *mut bool) -> HRESULT; + pub unsafe fn pin_app(&self, app_id: PCWSTR) -> HRESULT; + pub unsafe fn unpin_app(&self, app_id: PCWSTR) -> HRESULT; + + pub unsafe fn is_view_pinned( + &self, + view: ComIn, + out_iss: *mut bool, + ) -> HRESULT; + pub unsafe fn pin_view(&self, view: ComIn) -> HRESULT; + pub unsafe fn unpin_view(&self, view: ComIn) -> HRESULT; +} diff --git a/src/interfaces/build_10240.rs b/src/interfaces/build_10240.rs deleted file mode 100644 index 1529a11..0000000 --- a/src/interfaces/build_10240.rs +++ /dev/null @@ -1,366 +0,0 @@ -//! Support for Windows 10. -//! -//! These definitions should be valid from Windows version `10240` (inclusive) to `22000` (exclusive). -//! -//! # References -//! -//! - Interface ids at [VirtualDesktop/src/VirtualDesktop/app.config at a6c69e420307e0717f296501c1e7595977e27b6b · Grabacr07/VirtualDesktop](https://github.com/Grabacr07/VirtualDesktop/blob/a6c69e420307e0717f296501c1e7595977e27b6b/src/VirtualDesktop/app.config) -//! - Bindings at [VirtualDesktop/src/VirtualDesktop/Interop at a6c69e420307e0717f296501c1e7595977e27b6b · Grabacr07/VirtualDesktop](https://github.com/Grabacr07/VirtualDesktop/tree/a6c69e420307e0717f296501c1e7595977e27b6b/src/VirtualDesktop/Interop) -//! - These are actually compiled when the app is executed by the `ComInterfaceAssemblyBuilder.CreateAssembly` method at: [VirtualDesktop/src/VirtualDesktop/Interop/ComInterfaceAssemblyBuilder.cs at a6c69e420307e0717f296501c1e7595977e27b6b · Grabacr07/VirtualDesktop](https://github.com/Grabacr07/VirtualDesktop/blob/a6c69e420307e0717f296501c1e7595977e27b6b/src/VirtualDesktop/Interop/ComInterfaceAssemblyBuilder.cs#L73-L192) -//! - Bindings at [MScholtes/VirtualDesktop at 6de804dced760778450ae3cd1481f8969f75fb39](https://github.com/MScholtes/VirtualDesktop/tree/6de804dced760778450ae3cd1481f8969f75fb39) -use super::*; - -#[windows_interface::interface("871F602A-2B58-42B4-8C4B-6C43D642C06F")] -pub unsafe trait IApplicationView: IUnknown { - /* IInspecateble */ - pub unsafe fn get_iids( - &self, - out_iid_count: *mut ULONG, - out_opt_iid_array_ptr: *mut *mut GUID, - ) -> HRESULT; - pub unsafe fn get_runtime_class_name(&self, out_opt_class_name: *mut HSTRING) -> HRESULT; - pub unsafe fn get_trust_level(&self, ptr_trust_level: LPVOID) -> HRESULT; - - /* IApplicationView methods */ - pub unsafe fn set_focus(&self) -> HRESULT; - pub unsafe fn switch_to(&self) -> HRESULT; - - pub unsafe fn try_invoke_back(&self, ptr_async_callback: IAsyncCallback) -> HRESULT; - pub unsafe fn get_thumbnail_window(&self, out_hwnd: *mut HWND) -> HRESULT; - pub unsafe fn get_monitor(&self, out_monitors: *mut *mut IImmersiveMonitor) -> HRESULT; - pub unsafe fn get_visibility(&self, out_int: LPVOID) -> HRESULT; - pub unsafe fn set_cloak( - &self, - application_view_cloak_type: APPLICATION_VIEW_CLOAK_TYPE, - unknown: INT, - ) -> HRESULT; - pub unsafe fn get_position( - &self, - unknowniid: *const GUID, - unknown_array_ptr: LPVOID, - ) -> HRESULT; - pub unsafe fn set_position(&self, view_position: *mut IApplicationViewPosition) -> HRESULT; - pub unsafe fn insert_after_window(&self, window: HWND) -> HRESULT; - pub unsafe fn get_extended_frame_position(&self, rect: *mut RECT) -> HRESULT; - pub unsafe fn get_app_user_model_id(&self, id: *mut PWSTR) -> HRESULT; // Proc17 - pub unsafe fn set_app_user_model_id(&self, id: PCWSTR) -> HRESULT; - pub unsafe fn is_equal_by_app_user_model_id( - &self, - id: PCWSTR, - out_result: *mut INT, - ) -> HRESULT; - - /*** IApplicationView methods ***/ - pub unsafe fn get_view_state(&self, out_state: *mut UINT) -> HRESULT; // Proc20 - pub unsafe fn set_view_state(&self, state: UINT) -> HRESULT; // Proc21 - pub unsafe fn get_neediness(&self, out_neediness: *mut INT) -> HRESULT; // Proc22 - pub unsafe fn get_last_activation_timestamp( - &self, - out_timestamp: *mut ULONGLONG, - ) -> HRESULT; - pub unsafe fn set_last_activation_timestamp(&self, timestamp: ULONGLONG) -> HRESULT; - pub unsafe fn get_virtual_desktop_id(&self, out_desktop_guid: *mut GUID) -> HRESULT; - pub unsafe fn set_virtual_desktop_id(&self, desktop_guid: *const GUID) -> HRESULT; - pub unsafe fn get_show_in_switchers(&self, out_show: *mut INT) -> HRESULT; - pub unsafe fn set_show_in_switchers(&self, show: INT) -> HRESULT; - pub unsafe fn get_scale_factor(&self, out_scale_factor: *mut INT) -> HRESULT; - pub unsafe fn can_receive_input(&self, out_can: *mut BOOL) -> HRESULT; - pub unsafe fn get_compatibility_policy_type( - &self, - out_policy_type: *mut APPLICATION_VIEW_COMPATIBILITY_POLICY, - ) -> HRESULT; - pub unsafe fn set_compatibility_policy_type( - &self, - policy_type: APPLICATION_VIEW_COMPATIBILITY_POLICY, - ) -> HRESULT; - - pub unsafe fn get_size_constraints( - &self, - monitor: *mut IImmersiveMonitor, - out_size1: *mut SIZE, - out_size2: *mut SIZE, - ) -> HRESULT; - pub unsafe fn get_size_constraints_for_dpi( - &self, - dpi: UINT, - out_size1: *mut SIZE, - out_size2: *mut SIZE, - ) -> HRESULT; - pub unsafe fn set_size_constraints_for_dpi( - &self, - dpi: *const UINT, - size1: *const SIZE, - size2: *const SIZE, - ) -> HRESULT; - - pub unsafe fn on_min_size_preferences_updated(&self, window: HWND) -> HRESULT; - pub unsafe fn apply_operation(&self, operation: *mut IApplicationViewOperation) -> HRESULT; - pub unsafe fn is_tray(&self, out_is: *mut BOOL) -> HRESULT; - pub unsafe fn is_in_high_zorder_band(&self, out_is: *mut BOOL) -> HRESULT; - pub unsafe fn is_splash_screen_presented(&self, out_is: *mut BOOL) -> HRESULT; - pub unsafe fn flash(&self) -> HRESULT; - pub unsafe fn get_root_switchable_owner(&self, app_view: *mut IApplicationView) -> HRESULT; // proc45 - pub unsafe fn enumerate_ownership_tree(&self, objects: *mut IObjectArray) -> HRESULT; // proc46 - - pub unsafe fn get_enterprise_id(&self, out_id: *mut PWSTR) -> HRESULT; // proc47 - pub unsafe fn is_mirrored(&self, out_is: *mut BOOL) -> HRESULT; // - - pub unsafe fn unknown1(&self, arg: *mut INT) -> HRESULT; - pub unsafe fn unknown2(&self, arg: *mut INT) -> HRESULT; - pub unsafe fn unknown3(&self, arg: *mut INT) -> HRESULT; - pub unsafe fn unknown4(&self, arg: INT) -> HRESULT; - pub unsafe fn unknown5(&self, arg: *mut INT) -> HRESULT; - pub unsafe fn unknown6(&self, arg: INT) -> HRESULT; - pub unsafe fn unknown7(&self) -> HRESULT; - pub unsafe fn unknown8(&self, arg: *mut INT) -> HRESULT; - pub unsafe fn unknown9(&self, arg: INT) -> HRESULT; - pub unsafe fn unknown10(&self, arg: INT, arg2: INT) -> HRESULT; - pub unsafe fn unknown11(&self, arg: INT) -> HRESULT; - pub unsafe fn unknown12(&self, arg: *mut SIZE) -> HRESULT; -} - -#[windows_interface::interface("FF72FFDD-BE7E-43FC-9C03-AD81681E88E4")] -pub unsafe trait IVirtualDesktop: IUnknown { - pub unsafe fn is_view_visible( - &self, - p_view: ComIn, - out_bool: *mut u32, - ) -> HRESULT; - pub unsafe fn get_id(&self, out_guid: *mut GUID) -> HRESULT; -} - -#[windows_interface::interface("1841C6D7-4F9D-42C0-AF41-8747538F10E5")] -pub unsafe trait IApplicationViewCollection: IUnknown { - pub unsafe fn get_views(&self, out_views: *mut IObjectArray) -> HRESULT; - - pub unsafe fn get_views_by_zorder(&self, out_views: *mut IObjectArray) -> HRESULT; - - pub unsafe fn get_views_by_app_user_model_id( - &self, - id: PCWSTR, - out_views: *mut IObjectArray, - ) -> HRESULT; - - pub unsafe fn get_view_for_hwnd( - &self, - window: HWND, - out_view: *mut Option, - ) -> HRESULT; - - pub unsafe fn get_view_for_application( - &self, - app: IImmersiveApplication, - out_view: *mut IApplicationView, - ) -> HRESULT; - - pub unsafe fn get_view_for_app_user_model_id( - &self, - id: PCWSTR, - out_view: *mut IApplicationView, - ) -> HRESULT; - - pub unsafe fn get_view_in_focus(&self, out_view: *mut IApplicationView) -> HRESULT; - - pub unsafe fn refresh_collection(&self) -> HRESULT; - - pub unsafe fn register_for_application_view_changes( - &self, - listener: IApplicationViewChangeListener, - out_id: *mut DWORD, - ) -> HRESULT; - - pub unsafe fn unregister_for_application_view_changes(&self, id: DWORD) -> HRESULT; -} - -#[windows_interface::interface("C179334C-4295-40D3-BEA1-C654D965605A")] -pub unsafe trait IVirtualDesktopNotification: IUnknown { - pub unsafe fn virtual_desktop_created(&self, desktop: ComIn) -> HRESULT; - - pub unsafe fn virtual_desktop_destroy_begin( - &self, - desktop_destroyed: ComIn, - desktop_fallback: ComIn, - ) -> HRESULT; - - pub unsafe fn virtual_desktop_destroy_failed( - &self, - desktop_destroyed: ComIn, - desktop_fallback: ComIn, - ) -> HRESULT; - - pub unsafe fn virtual_desktop_destroyed( - &self, - desktop_destroyed: ComIn, - desktop_fallback: ComIn, - ) -> HRESULT; - - pub unsafe fn view_virtual_desktop_changed(&self, view: ComIn) - -> HRESULT; - - pub unsafe fn current_virtual_desktop_changed( - &self, - desktop_old: ComIn, - desktop_new: ComIn, - ) -> HRESULT; -} - -#[windows_interface::interface("0CD45E71-D927-4F15-8B0A-8FEF525337BF")] -pub unsafe trait IVirtualDesktopNotificationService: IUnknown { - pub unsafe fn register( - &self, - notification: *mut std::ffi::c_void, // *const IVirtualDesktopNotification, - out_cookie: *mut DWORD, - ) -> HRESULT; - - pub unsafe fn unregister(&self, cookie: u32) -> HRESULT; -} - -#[windows_interface::interface("0F3A72B0-4566-487E-9A33-4ED302F6D6CE")] -pub unsafe trait IVirtualDesktopManagerInternal: IUnknown { - pub unsafe fn get_desktop_count(&self, out_count: *mut UINT) -> HRESULT; - - pub unsafe fn move_view_to_desktop( - &self, - view: ComIn, - desktop: ComIn, - ) -> HRESULT; - - pub unsafe fn can_move_view_between_desktops( - &self, - view: ComIn, - can_move: *mut i32, - ) -> HRESULT; - - pub unsafe fn get_current_desktop( - &self, - out_desktop: *mut Option, - ) -> HRESULT; - - pub unsafe fn get_desktops(&self, out_desktops: *mut Option) -> HRESULT; - - /// Get next or previous desktop - /// - /// Direction values: - /// 3 = Left direction - /// 4 = Right direction - pub unsafe fn get_adjacent_desktop( - &self, - in_desktop: ComIn, - direction: UINT, - out_pp_desktop: *mut Option, - ) -> HRESULT; - - pub unsafe fn switch_desktop(&self, desktop: ComIn) -> HRESULT; - - pub unsafe fn create_desktop(&self, out_desktop: *mut Option) -> HRESULT; - - pub unsafe fn move_desktop( - &self, - in_desktop: ComIn, - index: UINT, - ) -> HRESULT; - - pub unsafe fn remove_desktop( - &self, - destroy_desktop: ComIn, - fallback_desktop: ComIn, - ) -> HRESULT; - - pub unsafe fn find_desktop( - &self, - guid: *const GUID, - out_desktop: *mut Option, - ) -> HRESULT; - - pub unsafe fn get_desktop_switch_include_exclude_views( - &self, - desktop: ComIn, - out_pp_desktops1: *mut IObjectArray, - out_pp_desktops2: *mut IObjectArray, - ) -> HRESULT; - - pub unsafe fn set_name(&self, desktop: ComIn, name: HSTRING) -> HRESULT; - pub unsafe fn set_wallpaper( - &self, - desktop: ComIn, - name: HSTRING, - ) -> HRESULT; - pub unsafe fn update_wallpaper_for_all(&self, name: HSTRING) -> HRESULT; -} - -#[windows_interface::interface("4CE81583-1E4C-4632-A621-07A53543148F")] -pub unsafe trait IVirtualDesktopPinnedApps: IUnknown { - pub unsafe fn is_app_pinned(&self, app_id: PCWSTR, out_iss: *mut bool) -> HRESULT; - pub unsafe fn pin_app(&self, app_id: PCWSTR) -> HRESULT; - pub unsafe fn unpin_app(&self, app_id: PCWSTR) -> HRESULT; - - pub unsafe fn is_view_pinned( - &self, - view: ComIn, - out_iss: *mut bool, - ) -> HRESULT; - pub unsafe fn pin_view(&self, view: ComIn) -> HRESULT; - pub unsafe fn unpin_view(&self, view: ComIn) -> HRESULT; -} - -/// Implements an unstable interface that is only valid for a single Windows -/// version using a more stable trait that works for all Windows versions. -#[windows::core::implement(IVirtualDesktopNotification)] -pub struct VirtualDesktopNotificationAdaptor -where - T: build_dyn::IVirtualDesktopNotification_Impl, -{ - pub inner: T, -} -impl IVirtualDesktopNotification_Impl for VirtualDesktopNotificationAdaptor -where - T: build_dyn::IVirtualDesktopNotification_Impl, -{ - unsafe fn current_virtual_desktop_changed( - &self, - desktop_old: ComIn, - desktop_new: ComIn, - ) -> HRESULT { - self.inner - .current_virtual_desktop_changed((&*desktop_old).into(), (&*desktop_new).into()) - } - - unsafe fn virtual_desktop_created(&self, desktop: ComIn) -> HRESULT { - self.inner.virtual_desktop_created((&*desktop).into()) - } - - unsafe fn virtual_desktop_destroy_begin( - &self, - desktop_destroyed: ComIn, - desktop_fallback: ComIn, - ) -> HRESULT { - self.inner.virtual_desktop_destroy_begin( - (&*desktop_destroyed).into(), - (&*desktop_fallback).into(), - ) - } - - unsafe fn virtual_desktop_destroy_failed( - &self, - desktop_destroyed: ComIn, - desktop_fallback: ComIn, - ) -> HRESULT { - self.inner.virtual_desktop_destroy_failed( - (&*desktop_destroyed).into(), - (&*desktop_fallback).into(), - ) - } - - unsafe fn virtual_desktop_destroyed( - &self, - desktop_destroyed: ComIn, - desktop_fallback: ComIn, - ) -> HRESULT { - self.inner - .virtual_desktop_destroyed((&*desktop_destroyed).into(), (&*desktop_fallback).into()) - } - - unsafe fn view_virtual_desktop_changed(&self, view: ComIn) -> HRESULT { - self.inner.view_virtual_desktop_changed((&*view).into()) - } -} diff --git a/src/interfaces/build_22000.rs b/src/interfaces/build_22000.rs deleted file mode 100644 index d7d738b..0000000 --- a/src/interfaces/build_22000.rs +++ /dev/null @@ -1,409 +0,0 @@ -//! Support for Windows 11. -use super::*; - -#[windows_interface::interface("372E1D3B-38D3-42E4-A15B-8AB2B178F513")] -pub unsafe trait IApplicationView: IUnknown { - /* IInspecateble */ - pub unsafe fn get_iids( - &self, - out_iid_count: *mut ULONG, - out_opt_iid_array_ptr: *mut *mut GUID, - ) -> HRESULT; - pub unsafe fn get_runtime_class_name(&self, out_opt_class_name: *mut HSTRING) -> HRESULT; - pub unsafe fn get_trust_level(&self, ptr_trust_level: LPVOID) -> HRESULT; - - /* IApplicationView methods */ - pub unsafe fn set_focus(&self) -> HRESULT; - pub unsafe fn switch_to(&self) -> HRESULT; - - pub unsafe fn try_invoke_back(&self, ptr_async_callback: IAsyncCallback) -> HRESULT; - pub unsafe fn get_thumbnail_window(&self, out_hwnd: *mut HWND) -> HRESULT; - pub unsafe fn get_monitor(&self, out_monitors: *mut *mut IImmersiveMonitor) -> HRESULT; - pub unsafe fn get_visibility(&self, out_int: LPVOID) -> HRESULT; - pub unsafe fn set_cloak( - &self, - application_view_cloak_type: APPLICATION_VIEW_CLOAK_TYPE, - unknown: INT, - ) -> HRESULT; - pub unsafe fn get_position( - &self, - unknowniid: *const GUID, - unknown_array_ptr: LPVOID, - ) -> HRESULT; - pub unsafe fn set_position(&self, view_position: *mut IApplicationViewPosition) -> HRESULT; - pub unsafe fn insert_after_window(&self, window: HWND) -> HRESULT; - pub unsafe fn get_extended_frame_position(&self, rect: *mut RECT) -> HRESULT; - pub unsafe fn get_app_user_model_id(&self, id: *mut PWSTR) -> HRESULT; // Proc17 - pub unsafe fn set_app_user_model_id(&self, id: PCWSTR) -> HRESULT; - pub unsafe fn is_equal_by_app_user_model_id(&self, id: PCWSTR, out_result: *mut INT) - -> HRESULT; - - /*** IApplicationView methods ***/ - pub unsafe fn get_view_state(&self, out_state: *mut UINT) -> HRESULT; // Proc20 - pub unsafe fn set_view_state(&self, state: UINT) -> HRESULT; // Proc21 - pub unsafe fn get_neediness(&self, out_neediness: *mut INT) -> HRESULT; // Proc22 - pub unsafe fn get_last_activation_timestamp(&self, out_timestamp: *mut ULONGLONG) -> HRESULT; - pub unsafe fn set_last_activation_timestamp(&self, timestamp: ULONGLONG) -> HRESULT; - pub unsafe fn get_virtual_desktop_id(&self, out_desktop_guid: *mut GUID) -> HRESULT; - pub unsafe fn set_virtual_desktop_id(&self, desktop_guid: *const GUID) -> HRESULT; - pub unsafe fn get_show_in_switchers(&self, out_show: *mut INT) -> HRESULT; - pub unsafe fn set_show_in_switchers(&self, show: INT) -> HRESULT; - pub unsafe fn get_scale_factor(&self, out_scale_factor: *mut INT) -> HRESULT; - pub unsafe fn can_receive_input(&self, out_can: *mut BOOL) -> HRESULT; - pub unsafe fn get_compatibility_policy_type( - &self, - out_policy_type: *mut APPLICATION_VIEW_COMPATIBILITY_POLICY, - ) -> HRESULT; - pub unsafe fn set_compatibility_policy_type( - &self, - policy_type: APPLICATION_VIEW_COMPATIBILITY_POLICY, - ) -> HRESULT; - - pub unsafe fn get_size_constraints( - &self, - monitor: *mut IImmersiveMonitor, - out_size1: *mut SIZE, - out_size2: *mut SIZE, - ) -> HRESULT; - pub unsafe fn get_size_constraints_for_dpi( - &self, - dpi: UINT, - out_size1: *mut SIZE, - out_size2: *mut SIZE, - ) -> HRESULT; - pub unsafe fn set_size_constraints_for_dpi( - &self, - dpi: *const UINT, - size1: *const SIZE, - size2: *const SIZE, - ) -> HRESULT; - - pub unsafe fn on_min_size_preferences_updated(&self, window: HWND) -> HRESULT; - pub unsafe fn apply_operation(&self, operation: *mut IApplicationViewOperation) -> HRESULT; - pub unsafe fn is_tray(&self, out_is: *mut BOOL) -> HRESULT; - pub unsafe fn is_in_high_zorder_band(&self, out_is: *mut BOOL) -> HRESULT; - pub unsafe fn is_splash_screen_presented(&self, out_is: *mut BOOL) -> HRESULT; - pub unsafe fn flash(&self) -> HRESULT; - pub unsafe fn get_root_switchable_owner(&self, app_view: *mut IApplicationView) -> HRESULT; // proc45 - pub unsafe fn enumerate_ownership_tree(&self, objects: *mut IObjectArray) -> HRESULT; // proc46 - - pub unsafe fn get_enterprise_id(&self, out_id: *mut PWSTR) -> HRESULT; // proc47 - pub unsafe fn is_mirrored(&self, out_is: *mut BOOL) -> HRESULT; // - - pub unsafe fn unknown1(&self, arg: *mut INT) -> HRESULT; - pub unsafe fn unknown2(&self, arg: *mut INT) -> HRESULT; - pub unsafe fn unknown3(&self, arg: *mut INT) -> HRESULT; - pub unsafe fn unknown4(&self, arg: INT) -> HRESULT; - pub unsafe fn unknown5(&self, arg: *mut INT) -> HRESULT; - pub unsafe fn unknown6(&self, arg: INT) -> HRESULT; - pub unsafe fn unknown7(&self) -> HRESULT; - pub unsafe fn unknown8(&self, arg: *mut INT) -> HRESULT; - pub unsafe fn unknown9(&self, arg: INT) -> HRESULT; - pub unsafe fn unknown10(&self, arg: INT, arg2: INT) -> HRESULT; - pub unsafe fn unknown11(&self, arg: INT) -> HRESULT; - pub unsafe fn unknown12(&self, arg: *mut SIZE) -> HRESULT; -} - -#[windows_interface::interface("3F07F4BE-B107-441A-AF0F-39D82529072C")] -pub unsafe trait IVirtualDesktop: IUnknown { - pub unsafe fn is_view_visible( - &self, - p_view: ComIn, - out_bool: *mut u32, - ) -> HRESULT; - pub unsafe fn get_id(&self, out_guid: *mut GUID) -> HRESULT; - pub unsafe fn get_name(&self, out_string: *mut HSTRING) -> HRESULT; - pub unsafe fn get_wallpaper(&self, out_string: *mut HSTRING) -> HRESULT; -} - -#[windows_interface::interface("1841c6d7-4f9d-42c0-af41-8747538f10e5")] -pub unsafe trait IApplicationViewCollection: IUnknown { - pub unsafe fn get_views(&self, out_views: *mut IObjectArray) -> HRESULT; - - pub unsafe fn get_views_by_zorder(&self, out_views: *mut IObjectArray) -> HRESULT; - - pub unsafe fn get_views_by_app_user_model_id( - &self, - id: PCWSTR, - out_views: *mut IObjectArray, - ) -> HRESULT; - - pub unsafe fn get_view_for_hwnd( - &self, - window: HWND, - out_view: *mut Option, - ) -> HRESULT; - - pub unsafe fn get_view_for_application( - &self, - app: IImmersiveApplication, - out_view: *mut IApplicationView, - ) -> HRESULT; - - pub unsafe fn get_view_for_app_user_model_id( - &self, - id: PCWSTR, - out_view: *mut IApplicationView, - ) -> HRESULT; - - pub unsafe fn get_view_in_focus(&self, out_view: *mut IApplicationView) -> HRESULT; - - pub unsafe fn try_get_last_active_visible_view( - &self, - out_view: *mut IApplicationView, - ) -> HRESULT; - - pub unsafe fn refresh_collection(&self) -> HRESULT; - - pub unsafe fn register_for_application_view_changes( - &self, - listener: IApplicationViewChangeListener, - out_id: *mut DWORD, - ) -> HRESULT; - - pub unsafe fn unregister_for_application_view_changes(&self, id: DWORD) -> HRESULT; -} - -#[windows_interface::interface("B9E5E94D-233E-49AB-AF5C-2B4541C3AADE")] -pub unsafe trait IVirtualDesktopNotification: IUnknown { - pub unsafe fn virtual_desktop_created(&self, desktop: ComIn) -> HRESULT; - - pub unsafe fn virtual_desktop_destroy_begin( - &self, - desktop_destroyed: ComIn, - desktop_fallback: ComIn, - ) -> HRESULT; - - pub unsafe fn virtual_desktop_destroy_failed( - &self, - desktop_destroyed: ComIn, - desktop_fallback: ComIn, - ) -> HRESULT; - - pub unsafe fn virtual_desktop_destroyed( - &self, - desktop_destroyed: ComIn, - desktop_fallback: ComIn, - ) -> HRESULT; - - pub unsafe fn virtual_desktop_moved( - &self, - desktop: ComIn, - old_index: i64, - new_index: i64, - ) -> HRESULT; - - pub unsafe fn virtual_desktop_name_changed( - &self, - desktop: ComIn, - name: HSTRING, - ) -> HRESULT; - - pub unsafe fn view_virtual_desktop_changed(&self, view: ComIn) -> HRESULT; - - pub unsafe fn current_virtual_desktop_changed( - &self, - desktop_old: ComIn, - desktop_new: ComIn, - ) -> HRESULT; - - pub unsafe fn virtual_desktop_wallpaper_changed( - &self, - desktop: ComIn, - name: HSTRING, - ) -> HRESULT; - - pub unsafe fn virtual_desktop_switched(&self, desktop: ComIn) -> HRESULT; - - pub unsafe fn remote_virtual_desktop_connected( - &self, - desktop: ComIn, - ) -> HRESULT; -} - -#[windows_interface::interface("0CD45E71-D927-4F15-8B0A-8FEF525337BF")] -pub unsafe trait IVirtualDesktopNotificationService: IUnknown { - pub unsafe fn register( - &self, - notification: *mut std::ffi::c_void, // *const IVirtualDesktopNotification, - out_cookie: *mut DWORD, - ) -> HRESULT; - - pub unsafe fn unregister(&self, cookie: u32) -> HRESULT; -} - -#[windows_interface::interface("53F5CA0B-158F-4124-900C-057158060B27")] -pub unsafe trait IVirtualDesktopManagerInternal: IUnknown { - pub unsafe fn get_desktop_count(&self, out_count: *mut UINT) -> HRESULT; - - pub unsafe fn move_view_to_desktop( - &self, - view: ComIn, - desktop: ComIn, - ) -> HRESULT; - - pub unsafe fn can_move_view_between_desktops( - &self, - view: ComIn, - can_move: *mut i32, - ) -> HRESULT; - - pub unsafe fn get_current_desktop(&self, out_desktop: *mut Option) -> HRESULT; - - pub unsafe fn get_desktops(&self, out_desktops: *mut Option) -> HRESULT; - - /// Get next or previous desktop - /// - /// Direction values: - /// 3 = Left direction - /// 4 = Right direction - pub unsafe fn get_adjacent_desktop( - &self, - in_desktop: ComIn, - direction: UINT, - out_pp_desktop: *mut Option, - ) -> HRESULT; - - pub unsafe fn switch_desktop(&self, desktop: ComIn) -> HRESULT; - - pub unsafe fn create_desktop(&self, out_desktop: *mut Option) -> HRESULT; - - pub unsafe fn move_desktop(&self, in_desktop: ComIn, index: UINT) -> HRESULT; - - pub unsafe fn remove_desktop( - &self, - destroy_desktop: ComIn, - fallback_desktop: ComIn, - ) -> HRESULT; - - pub unsafe fn find_desktop( - &self, - guid: *const GUID, - out_desktop: *mut Option, - ) -> HRESULT; - - pub unsafe fn get_desktop_switch_include_exclude_views( - &self, - desktop: ComIn, - out_pp_desktops1: *mut IObjectArray, - out_pp_desktops2: *mut IObjectArray, - ) -> HRESULT; - - pub unsafe fn set_name(&self, desktop: ComIn, name: HSTRING) -> HRESULT; - pub unsafe fn set_wallpaper(&self, desktop: ComIn, name: HSTRING) -> HRESULT; - pub unsafe fn update_wallpaper_for_all(&self, name: HSTRING) -> HRESULT; -} - -#[windows_interface::interface("4CE81583-1E4C-4632-A621-07A53543148F")] -pub unsafe trait IVirtualDesktopPinnedApps: IUnknown { - pub unsafe fn is_app_pinned(&self, app_id: PCWSTR, out_iss: *mut bool) -> HRESULT; - pub unsafe fn pin_app(&self, app_id: PCWSTR) -> HRESULT; - pub unsafe fn unpin_app(&self, app_id: PCWSTR) -> HRESULT; - - pub unsafe fn is_view_pinned( - &self, - view: ComIn, - out_iss: *mut bool, - ) -> HRESULT; - pub unsafe fn pin_view(&self, view: ComIn) -> HRESULT; - pub unsafe fn unpin_view(&self, view: ComIn) -> HRESULT; -} - -/// Implements an unstable interface that is only valid for a single Windows -/// version using a more stable trait that works for all Windows versions. -#[windows::core::implement(IVirtualDesktopNotification)] -pub struct VirtualDesktopNotificationAdaptor -where - T: build_dyn::IVirtualDesktopNotification_Impl, -{ - pub inner: T, -} -impl IVirtualDesktopNotification_Impl for VirtualDesktopNotificationAdaptor -where - T: build_dyn::IVirtualDesktopNotification_Impl, -{ - unsafe fn current_virtual_desktop_changed( - &self, - desktop_old: ComIn, - desktop_new: ComIn, - ) -> HRESULT { - self.inner - .current_virtual_desktop_changed((&*desktop_old).into(), (&*desktop_new).into()) - } - - unsafe fn virtual_desktop_wallpaper_changed( - &self, - desktop: ComIn, - name: HSTRING, - ) -> HRESULT { - self.inner - .virtual_desktop_wallpaper_changed((&*desktop).into(), name) - } - - unsafe fn virtual_desktop_created(&self, desktop: ComIn) -> HRESULT { - self.inner.virtual_desktop_created((&*desktop).into()) - } - - unsafe fn virtual_desktop_destroy_begin( - &self, - desktop_destroyed: ComIn, - desktop_fallback: ComIn, - ) -> HRESULT { - self.inner.virtual_desktop_destroy_begin( - (&*desktop_destroyed).into(), - (&*desktop_fallback).into(), - ) - } - - unsafe fn virtual_desktop_destroy_failed( - &self, - desktop_destroyed: ComIn, - desktop_fallback: ComIn, - ) -> HRESULT { - self.inner.virtual_desktop_destroy_failed( - (&*desktop_destroyed).into(), - (&*desktop_fallback).into(), - ) - } - - unsafe fn virtual_desktop_destroyed( - &self, - desktop_destroyed: ComIn, - desktop_fallback: ComIn, - ) -> HRESULT { - self.inner - .virtual_desktop_destroyed((&*desktop_destroyed).into(), (&*desktop_fallback).into()) - } - - unsafe fn virtual_desktop_moved( - &self, - desktop: ComIn, - old_index: i64, - new_index: i64, - ) -> HRESULT { - self.inner - .virtual_desktop_moved((&*desktop).into(), old_index, new_index) - } - - unsafe fn virtual_desktop_name_changed( - &self, - desktop: ComIn, - name: HSTRING, - ) -> HRESULT { - self.inner - .virtual_desktop_name_changed((&*desktop).into(), name) - } - - unsafe fn view_virtual_desktop_changed(&self, view: ComIn) -> HRESULT { - self.inner.view_virtual_desktop_changed((&*view).into()) - } - - unsafe fn virtual_desktop_switched(&self, desktop: ComIn) -> HRESULT { - self.inner.virtual_desktop_switched((&*desktop).into()) - } - - unsafe fn remote_virtual_desktop_connected(&self, desktop: ComIn) -> HRESULT { - self.inner - .remote_virtual_desktop_connected((&*desktop).into()) - } -} diff --git a/src/interfaces/build_dyn.rs b/src/interfaces/build_dyn.rs deleted file mode 100644 index 7a78976..0000000 --- a/src/interfaces/build_dyn.rs +++ /dev/null @@ -1,940 +0,0 @@ -//! Interface abstraction that allow interacting with COM interfaces even when -//! we don't know their IID and what exact methods they have until runtime. - -use super::*; - -use core::{ffi::c_void, marker::PhantomData}; -use windows::{ - core::{ComInterface, Interface, GUID, HRESULT, HSTRING}, - Win32::{ - Foundation::{E_NOTIMPL, HWND}, - UI::Shell::Common::IObjectArray, - }, -}; - -/// Indicates different Windows versions that have different Virtual Desktop -/// interfaces. -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)] -pub enum WindowsVersion { - Build10240, - #[default] - Build22000, -} -impl WindowsVersion { - // Aliases used by macros (should match the module names above): - const build_10240: Self = Self::Build10240; - const build_22000: Self = Self::Build22000; - - /// Get info about the current Windows version. Only differentiates between - /// Windows versions that have different virtual desktop interfaces. - /// - /// # Determining Windows Version - /// - /// We could use the [`GetVersionExW` function - /// (sysinfoapi.h)](https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getversionexw), - /// but it is deprecated after Windows 8.1. It also changes behavior depending - /// on what manifest is embedded in the executable. - /// - /// That pages links to [Version Helper functions - Win32 - /// apps](https://learn.microsoft.com/en-us/windows/win32/sysinfo/version-helper-apis) - /// where we are linked to the [`IsWindowsVersionOrGreater` function - /// (versionhelpers.h)](https://learn.microsoft.com/en-us/windows/win32/api/VersionHelpers/nf-versionhelpers-iswindowsversionorgreater) - /// and the [`VerifyVersionInfoA` function - /// (winbase.h)](https://learn.microsoft.com/en-us/windows/win32/api/Winbase/nf-winbase-verifyversioninfoa) - /// that it uses internally (though the later function is deprecated in Windows - /// 10). - /// - /// We can use `RtlGetVersion` [RtlGetVersion function (wdm.h) - Windows - /// drivers](https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-rtlgetversion?redirectedfrom=MSDN) - /// as mentioned at [c++ - Detecting Windows 10 version - Stack - /// Overflow](https://stackoverflow.com/questions/36543301/detecting-windows-10-version/36545162#36545162). - /// - /// # `windows` API References - /// - /// - [GetVersionExW in windows::Win32::System::SystemInformation - - /// Rust](https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/System/SystemInformation/fn.GetVersionExW.html) - /// - Affected by manifest. - /// - [RtlGetVersion in windows::Wdk::System::SystemServices - - /// Rust](https://microsoft.github.io/windows-docs-rs/doc/windows/Wdk/System/SystemServices/fn.RtlGetVersion.html) - /// - Always returns the correct version. - pub fn get() -> Self { - static INIT: std::sync::OnceLock = std::sync::OnceLock::new(); - *INIT.get_or_init(|| { - let mut version: windows::Win32::System::SystemInformation::OSVERSIONINFOW = - Default::default(); - version.dwOSVersionInfoSize = core::mem::size_of_val(&version) as u32; - let res = unsafe { windows::Wdk::System::SystemServices::RtlGetVersion(&mut version) }; - if res.is_err() { - return Default::default(); - } - if version.dwBuildNumber < 22000 { - WindowsVersion::Build10240 - } else { - WindowsVersion::Build22000 - } - }) - } -} - -/// Do an action with the type of the actual COM Interface on this Windows -/// version. -/// -/// This is implemented for the more generic COM interfaces that don't know -/// their IID at compile time. Those implementations will put a bound on `F` so -/// that it must accept all concrete COM types that might be used. -pub trait WithVersionedType { - /// Invokes the callback with the COM interface type of this Windows - /// version. Return `None` if the interface doesn't exist on this platform. - fn with_versioned_type(callback: F) -> Option; -} -/// A callback that will be invoked with the actual COM interface type for a -/// specific Windows version. -/// -/// Implement this when you want to make use of a concrete COM interface type. -pub trait WithVersionedTypeCallback { - fn call(self) -> R; -} - -/// Generates support code for a COM interface. -/// -/// Syntax is: `as CreatedEnumName for InterfaceName in $(all)? [version_module_1, version_module_2 $(,)?]` -macro_rules! support_interface { - (@inner {$dollar:tt} as $state:ident for $name:ident in $(all $(@ $all:tt)?)? [$($version:ident),* $(,)?]) => { - $( - // assert_eq_size from static_assertions crate - const _: fn() = || { - // We need this since we transmute and pointer cast between the two types. - let _ = core::mem::transmute::<$name, self::$version::$name>; - }; - )* - - // Maybe enforce that all build versions are supported by this interface: - #[allow(unreachable_patterns)] - const _: fn(WindowsVersion) = |version: WindowsVersion| { - match version { - $(WindowsVersion::$version => (),)* - // If there is no "all" word in the macro input then: - // all() => true - // Otherwise: - // all(false) => false - // any() => false - // all(any()) => false - // And the default macro arm will be hidden. - #[cfg(all($(any() $($all)?)?))] - _ => (), - } - }; - - /// An enum with one variant per Windows version that is supported by - /// this interface. Use the `from_typed` function to construct this - /// type. - #[allow(non_camel_case_types)] - enum $state<'a> { - $( $version(ComIn<'a, self::$version::$name>) ),* - } - impl<'a> $state<'a> { - fn from_typed(data: &'a $name) -> Self { - unsafe { Self::from_raw(&data.0) } - } - /// # Safety - /// - /// The COM object must implement the expected interface. - #[allow(unreachable_patterns)] - unsafe fn from_raw(data: &'a IUnknown) -> Self { - let win_ver = WindowsVersion::get(); - match win_ver { - $(WindowsVersion::$version => $state::$version(core::mem::transmute_copy::>(data)),)* - _ => unreachable!("Tried to cast into a COM interface that wasn't available for the current Windows version"), - } - } - } - impl $name { - /// Convert from a raw pointer to the COM interface. - /// - /// # Safety - /// - /// The pointer must be an instance of the COM interface indicated - /// by the `IID` method. - pub unsafe fn from_raw(ptr: *mut c_void) -> Self { - Self(IUnknown::from_raw(ptr)) - } - /// The IID for the COM interface that is supported by this - /// platform, return a zeroed GUID if the interface isn't supported. - #[allow(non_snake_case, unreachable_patterns)] - pub fn IID() -> GUID { - match WindowsVersion::get() { - $(WindowsVersion::$version => self::$version::$name::IID,)* - _ => GUID::zeroed(), - } - } - } - /// Allow direct access to the wrapped COM interface type if required. - impl WithVersionedType for $name - where - $( - F: WithVersionedTypeCallback, - )* - { - #[allow(unreachable_patterns)] - fn with_versioned_type(callback: F) -> Option { - match WindowsVersion::get() { - $(WindowsVersion::$version => Some(>::call(callback)),)* - _ => None, - } - } - } - $( - /// Version specific -> Generic interface - impl From for $name { - fn from(v: self::$version::$name) -> Self { - debug_assert_eq!( - WindowsVersion::get(), - WindowsVersion::$version, - "if we have an COM interface for a specific Windows version then we must already have ensured that it is actually the Windows version the user has" - ); - Self(v.into()) - } - } - /// Reference to version specific -> Reference to generic interface - impl<'a> From<&'a self::$version::$name> for &'a $name { - fn from(v: &'a self::$version::$name) -> Self { - debug_assert_eq!( - WindowsVersion::get(), - WindowsVersion::$version, - "if we have an COM interface for a specific Windows version then we must already have ensured that it is actually the Windows version the user has" - ); - // Safety: both types are just transparent wrappers over a - // raw pointer and we don't drop either of them. - unsafe { - &*(v as *const self::$version::$name as *const $name) - } - } - } - /// Fallible conversion from generic interface to version specific - /// interface. - impl From<$name> for self::$version::$name { - fn from(v: $name) -> Self { - assert_eq!(WindowsVersion::get(), WindowsVersion::$version); - // Safety: interpret the wrapped raw pointer as the specific COM interface. - unsafe { core::mem::transmute(v.0) } - } - } - impl<'a> From<&'a $name> for ComIn<'a, self::$version::$name> { - #[allow(irrefutable_let_patterns)] - fn from(v: &'a $name) -> Self { - if let $state::$version(v) = $state::from_typed(v) { - v - } else { - unreachable!("requested a COM interface for a different Windows version than the one that was installed"); - } - } - } - )* - /// Preform the same action for each version of the wrapped COM interface. - /// - /// Syntax: GeneralType, |versioned: versioned_mod::VersionedType| block_of_code - /// - /// Note: named the same as the interface to allow for easier usage with macros. - #[allow(unused_macros)] - macro_rules! $name { - ( - $dollar this:expr, - |$dollar arg:ident - $dollar ( - : - $dollar module_name:ident - :: - $dollar arg_ty:ident - )? - | - $dollar ($dollar body:tt)* - ) => { - match $state::from_typed(&$dollar this) { - $( - $state::$version($dollar arg) => { - $dollar ( - #[allow(unused_imports)] - use self::$version as $dollar module_name; - #[allow(unused_imports)] - use self::$version::$name as $dollar arg_ty; - )? - $dollar ($dollar body)* - }, - )* - } - } - } - }; - // Pass an escaped dollar sign to the real macro so that we can construct a - // new macro later: - (as $state:ident for $name:ident in $($in:tt)*) => { - support_interface! { @inner {$} as $state for $name in $($in)* } - }; -} - -/// Implement a method by calling the same method on the Windows version -/// dependant COM interface. -macro_rules! forward_call { - ( - #[forward_for = $name:ident] - $( #[$attr:meta] )* - $pub:vis - $(unsafe $(@ $unsafe:tt)?)? - fn $fname:ident ( - &$self_:ident $(,)? $( $arg_name:ident : $ArgTy:ty ),* $(,)? - ) -> $RetTy:ty; - ) => ( - $( #[$attr] )* - #[allow(unused_parens)] - $pub - $(unsafe $($unsafe)?)? - fn $fname ( - &$self_, $( $arg_name : $ArgTy ),* - ) -> $RetTy - { - unsafe { - $name!( - $self_, - |v| v.$fname( $( - Into::into($arg_name) - ),*) - ) - } - } - ); - ( - $( #[$attr:meta] )* - impl $name:ident { - $($item:item)* - } - ) => { - $(#[$attr])* - impl $name { - $( - #[apply(forward_call)] - #[forward_for = $name] - $item - )* - } - }; -} - -support_interface!(as IApplicationViewInner for IApplicationView in all [build_10240, build_22000]); - -#[derive(Debug, Clone, PartialEq, Eq)] -#[repr(transparent)] -pub struct IApplicationView(IUnknown); -impl IApplicationView { - /* IInspecateble */ - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn get_iids( - &self, - out_iid_count: *mut ULONG, - out_opt_iid_array_ptr: *mut *mut GUID, - ) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn get_runtime_class_name(&self, out_opt_class_name: *mut HSTRING) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn get_trust_level(&self, ptr_trust_level: LPVOID) -> HRESULT; - - /* IApplicationView methods */ - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub fn set_focus(&self) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub fn switch_to(&self) -> HRESULT; - - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn try_invoke_back(&self, ptr_async_callback: IAsyncCallback) -> HRESULT; - pub fn get_thumbnail_window(&self, out_hwnd: &mut HWND) -> HRESULT { - unsafe { IApplicationView!(self, |i| i.get_thumbnail_window(out_hwnd)) } - } - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn get_monitor(&self, out_monitors: *mut *mut IImmersiveMonitor) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn get_visibility(&self, out_int: LPVOID) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn set_cloak( - &self, - application_view_cloak_type: APPLICATION_VIEW_CLOAK_TYPE, - unknown: INT, - ) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn get_position( - &self, - unknowniid: *const GUID, - unknown_array_ptr: LPVOID, - ) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn set_position(&self, view_position: *mut IApplicationViewPosition) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn insert_after_window(&self, window: HWND) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn get_extended_frame_position(&self, rect: *mut RECT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn get_app_user_model_id(&self, id: *mut PWSTR) -> HRESULT; // Proc17 - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn set_app_user_model_id(&self, id: PCWSTR) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn is_equal_by_app_user_model_id(&self, id: PCWSTR, out_result: *mut INT) - -> HRESULT; - - /*** IApplicationView methods ***/ - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn get_view_state(&self, out_state: *mut UINT) -> HRESULT; // Proc20 - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn set_view_state(&self, state: UINT) -> HRESULT; // Proc21 - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn get_neediness(&self, out_neediness: *mut INT) -> HRESULT; // Proc22 - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn get_last_activation_timestamp(&self, out_timestamp: *mut ULONGLONG) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn set_last_activation_timestamp(&self, timestamp: ULONGLONG) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn get_virtual_desktop_id(&self, out_desktop_guid: *mut GUID) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn set_virtual_desktop_id(&self, desktop_guid: *const GUID) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn get_show_in_switchers(&self, out_show: *mut INT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn set_show_in_switchers(&self, show: INT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn get_scale_factor(&self, out_scale_factor: *mut INT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn can_receive_input(&self, out_can: *mut BOOL) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn get_compatibility_policy_type( - &self, - out_policy_type: *mut APPLICATION_VIEW_COMPATIBILITY_POLICY, - ) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn set_compatibility_policy_type( - &self, - policy_type: APPLICATION_VIEW_COMPATIBILITY_POLICY, - ) -> HRESULT; - - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn get_size_constraints( - &self, - monitor: *mut IImmersiveMonitor, - out_size1: *mut SIZE, - out_size2: *mut SIZE, - ) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn get_size_constraints_for_dpi( - &self, - dpi: UINT, - out_size1: *mut SIZE, - out_size2: *mut SIZE, - ) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn set_size_constraints_for_dpi( - &self, - dpi: *const UINT, - size1: *const SIZE, - size2: *const SIZE, - ) -> HRESULT; - - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn on_min_size_preferences_updated(&self, window: HWND) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn apply_operation(&self, operation: *mut IApplicationViewOperation) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn is_tray(&self, out_is: *mut BOOL) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn is_in_high_zorder_band(&self, out_is: *mut BOOL) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn is_splash_screen_presented(&self, out_is: *mut BOOL) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn flash(&self) -> HRESULT; - pub unsafe fn get_root_switchable_owner(&self, app_view: *mut IApplicationView) -> HRESULT { - // proc45 - IApplicationView!(self, |inner| inner - .get_root_switchable_owner(app_view as *mut _)) - } - - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn enumerate_ownership_tree(&self, objects: *mut IObjectArray) -> HRESULT; // proc46 - - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn get_enterprise_id(&self, out_id: *mut PWSTR) -> HRESULT; // proc47 - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn is_mirrored(&self, out_is: *mut BOOL) -> HRESULT; // - - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn unknown1(&self, arg: *mut INT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn unknown2(&self, arg: *mut INT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn unknown3(&self, arg: *mut INT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn unknown4(&self, arg: INT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn unknown5(&self, arg: *mut INT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn unknown6(&self, arg: INT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn unknown7(&self) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn unknown8(&self, arg: *mut INT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn unknown9(&self, arg: INT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn unknown10(&self, arg: INT, arg2: INT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn unknown11(&self, arg: INT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn unknown12(&self, arg: *mut SIZE) -> HRESULT; -} - -support_interface!(as IVirtualDesktopInner for IVirtualDesktop in [build_10240, build_22000]); - -#[derive(Debug, Clone, PartialEq, Eq)] -#[repr(transparent)] -pub struct IVirtualDesktop(IUnknown); -impl IVirtualDesktop { - pub fn is_view_visible(&self, p_view: &IApplicationView, out_bool: &mut u32) -> HRESULT { - unsafe { IVirtualDesktop!(self, |inner| inner.is_view_visible(p_view.into(), out_bool)) } - } - pub fn get_id(&self, out_guid: &mut GUID) -> HRESULT { - unsafe { IVirtualDesktop!(self, |inner| inner.get_id(out_guid)) } - } - - pub fn get_name(&self, out_string: &mut HSTRING) -> HRESULT { - match IVirtualDesktopInner::from_typed(self) { - IVirtualDesktopInner::build_10240(_) => E_NOTIMPL, - IVirtualDesktopInner::build_22000(this) => unsafe { this.get_name(out_string) }, - } - } - pub fn get_wallpaper(&self, out_string: &mut HSTRING) -> HRESULT { - match IVirtualDesktopInner::from_typed(self) { - IVirtualDesktopInner::build_10240(_) => E_NOTIMPL, - IVirtualDesktopInner::build_22000(this) => unsafe { this.get_wallpaper(out_string) }, - } - } -} - -support_interface!(as IApplicationViewCollectionInner for IApplicationViewCollection in all [build_10240, build_22000]); - -#[derive(Debug, Clone, PartialEq, Eq)] -#[repr(transparent)] -pub struct IApplicationViewCollection(IUnknown); -impl IApplicationViewCollection { - #[apply(forward_call)] - #[forward_for = IApplicationViewCollection] - pub unsafe fn get_views(&self, out_views: *mut IObjectArray) -> HRESULT; - - #[apply(forward_call)] - #[forward_for = IApplicationViewCollection] - pub unsafe fn get_views_by_zorder(&self, out_views: *mut IObjectArray) -> HRESULT; - - #[apply(forward_call)] - #[forward_for = IApplicationViewCollection] - pub unsafe fn get_views_by_app_user_model_id( - &self, - id: PCWSTR, - out_views: *mut IObjectArray, - ) -> HRESULT; - - pub unsafe fn get_view_for_hwnd( - &self, - window: HWND, - out_view: *mut Option, - ) -> HRESULT { - IApplicationViewCollection!(self, |inner| inner - .get_view_for_hwnd(window, out_view as *mut _)) - } - - pub unsafe fn get_view_for_application( - &self, - app: IImmersiveApplication, - out_view: *mut IApplicationView, - ) -> HRESULT { - IApplicationViewCollection!(self, |inner| inner - .get_view_for_application(app, out_view as *mut _)) - } - - pub unsafe fn get_view_for_app_user_model_id( - &self, - id: PCWSTR, - out_view: *mut IApplicationView, - ) -> HRESULT { - IApplicationViewCollection!(self, |inner| inner - .get_view_for_app_user_model_id(id, out_view as *mut _)) - } - - pub fn get_view_in_focus(&self, out_view: &mut Option) -> HRESULT { - unsafe { - IApplicationViewCollection!(self, |inner| inner - .get_view_in_focus(out_view as *mut Option<_> as *mut _)) - } - } - - pub fn try_get_last_active_visible_view( - &self, - out_view: &mut Option, - ) -> HRESULT { - unsafe { - match IApplicationViewCollectionInner::from_typed(self) { - IApplicationViewCollectionInner::build_10240(_) => E_NOTIMPL, - IApplicationViewCollectionInner::build_22000(this) => { - this.try_get_last_active_visible_view(out_view as *mut Option<_> as *mut _) - } - } - } - } - - #[apply(forward_call)] - #[forward_for = IApplicationViewCollection] - pub unsafe fn refresh_collection(&self) -> HRESULT; - - pub fn register_for_application_view_changes( - &self, - listener: IApplicationViewChangeListener, - out_id: &mut DWORD, - ) -> HRESULT { - unsafe { - IApplicationViewCollection!(self, |inner| inner - .register_for_application_view_changes(listener, out_id)) - } - } - - #[apply(forward_call)] - #[forward_for = IApplicationViewCollection] - pub fn unregister_for_application_view_changes(&self, id: DWORD) -> HRESULT; -} - -support_interface!(as IVirtualDesktopNotificationInner for IVirtualDesktopNotification in all [build_10240, build_22000]); - -#[derive(Debug, Clone, PartialEq, Eq)] -#[repr(transparent)] -pub struct IVirtualDesktopNotification(IUnknown); -impl IVirtualDesktopNotification { - pub fn as_raw(&self) -> *mut c_void { - self.0.as_raw() - } -} -impl From for IVirtualDesktopNotification -where - T: IVirtualDesktopNotification_Impl, -{ - fn from(value: T) -> Self { - match WindowsVersion::get() { - WindowsVersion::Build10240 => build_10240::IVirtualDesktopNotification::from( - build_10240::VirtualDesktopNotificationAdaptor { inner: value }, - ) - .into(), - WindowsVersion::Build22000 => build_22000::IVirtualDesktopNotification::from( - build_22000::VirtualDesktopNotificationAdaptor { inner: value }, - ) - .into(), - } - } -} -#[allow(non_camel_case_types)] -pub trait IVirtualDesktopNotification_Impl { - fn virtual_desktop_created(&self, desktop: &IVirtualDesktop) -> HRESULT; - - fn virtual_desktop_destroy_begin( - &self, - desktop_destroyed: &IVirtualDesktop, - desktop_fallback: &IVirtualDesktop, - ) -> HRESULT; - - fn virtual_desktop_destroy_failed( - &self, - desktop_destroyed: &IVirtualDesktop, - desktop_fallback: &IVirtualDesktop, - ) -> HRESULT; - - fn virtual_desktop_destroyed( - &self, - desktop_destroyed: &IVirtualDesktop, - desktop_fallback: &IVirtualDesktop, - ) -> HRESULT; - - fn virtual_desktop_moved( - &self, - desktop: &IVirtualDesktop, - old_index: i64, - new_index: i64, - ) -> HRESULT; - - fn virtual_desktop_name_changed(&self, desktop: &IVirtualDesktop, name: HSTRING) -> HRESULT; - - fn view_virtual_desktop_changed(&self, view: &IApplicationView) -> HRESULT; - - fn current_virtual_desktop_changed( - &self, - desktop_old: &IVirtualDesktop, - desktop_new: &IVirtualDesktop, - ) -> HRESULT; - - fn virtual_desktop_wallpaper_changed( - &self, - desktop: &IVirtualDesktop, - name: HSTRING, - ) -> HRESULT; - - fn virtual_desktop_switched(&self, desktop: &IVirtualDesktop) -> HRESULT; - - fn remote_virtual_desktop_connected(&self, desktop: &IVirtualDesktop) -> HRESULT; -} - -support_interface!(as IVirtualDesktopNotificationServiceInner for IVirtualDesktopNotificationService in all [build_10240, build_22000]); - -#[derive(Debug, Clone, PartialEq, Eq)] -#[repr(transparent)] -pub struct IVirtualDesktopNotificationService(IUnknown); - -impl IVirtualDesktopNotificationService { - pub fn register( - &self, - notification: &IVirtualDesktopNotification, - out_cookie: &mut DWORD, - ) -> HRESULT { - unsafe { - IVirtualDesktopNotificationService!(self, |inner| inner - .register(notification.as_raw(), out_cookie)) - } - } - - #[apply(forward_call)] - #[forward_for = IVirtualDesktopNotificationService] - pub fn unregister(&self, cookie: u32) -> HRESULT; -} - -support_interface!(as IVirtualDesktopManagerInternalInner for IVirtualDesktopManagerInternal in all [build_10240, build_22000]); - -#[derive(Debug, Clone, PartialEq, Eq)] -#[repr(transparent)] -pub struct IVirtualDesktopManagerInternal(IUnknown); -impl IVirtualDesktopManagerInternal { - pub fn get_desktop_count(&self, out_count: &mut UINT) -> HRESULT { - unsafe { IVirtualDesktopManagerInternal!(self, |i| i.get_desktop_count(out_count)) } - } - - #[apply(forward_call)] - #[forward_for = IVirtualDesktopManagerInternal] - pub fn move_view_to_desktop( - &self, - view: &IApplicationView, - desktop: &IVirtualDesktop, - ) -> HRESULT; - - pub fn can_move_view_between_desktops( - &self, - view: &IApplicationView, - can_move: &mut i32, - ) -> HRESULT { - unsafe { - IVirtualDesktopManagerInternal!(self, |i| i - .can_move_view_between_desktops(view.into(), can_move)) - } - } - - pub fn get_current_desktop(&self, out_desktop: &mut Option) -> HRESULT { - unsafe { - IVirtualDesktopManagerInternal!(self, |inner| { - inner.get_current_desktop(out_desktop as *mut Option<_> as *mut Option<_>) - }) - } - } - - pub fn get_desktops(&self, out_desktops: &mut Option) -> HRESULT { - unsafe { IVirtualDesktopManagerInternal!(self, |inner| inner.get_desktops(out_desktops)) } - } - - /// Get next or previous desktop - /// - /// Direction values: - /// 3 = Left direction - /// 4 = Right direction - pub fn get_adjacent_desktop( - &self, - in_desktop: &IVirtualDesktop, - direction: UINT, - out_pp_desktop: &mut Option, - ) -> HRESULT { - unsafe { - IVirtualDesktopManagerInternal!(self, |inner| inner.get_adjacent_desktop( - in_desktop.into(), - direction, - out_pp_desktop as *mut Option<_> as *mut Option<_>, - )) - } - } - - #[apply(forward_call)] - #[forward_for = IVirtualDesktopManagerInternal] - pub fn switch_desktop(&self, desktop: &IVirtualDesktop) -> HRESULT; - - pub fn create_desktop(&self, out_desktop: &mut Option) -> HRESULT { - unsafe { - IVirtualDesktopManagerInternal!(self, |inner| inner - .create_desktop(out_desktop as *mut Option<_> as *mut Option<_>)) - } - } - - #[apply(forward_call)] - #[forward_for = IVirtualDesktopManagerInternal] - pub fn move_desktop(&self, in_desktop: &IVirtualDesktop, index: UINT) -> HRESULT; - - #[apply(forward_call)] - #[forward_for = IVirtualDesktopManagerInternal] - pub fn remove_desktop( - &self, - destroy_desktop: &IVirtualDesktop, - fallback_desktop: &IVirtualDesktop, - ) -> HRESULT; - - pub fn find_desktop(&self, guid: &GUID, out_desktop: &mut Option) -> HRESULT { - unsafe { - IVirtualDesktopManagerInternal!(self, |inner| { - inner.find_desktop(guid, out_desktop as *mut Option<_> as *mut Option<_>) - }) - } - } - - pub fn get_desktop_switch_include_exclude_views( - &self, - desktop: &IVirtualDesktop, - out_pp_desktops1: &mut Option, - out_pp_desktops2: &mut Option, - ) -> HRESULT { - unsafe { - IVirtualDesktopManagerInternal!(self, |inner| inner - .get_desktop_switch_include_exclude_views( - desktop.into(), - out_pp_desktops1 as *mut Option<_> as *mut _, - out_pp_desktops2 as *mut Option<_> as *mut _ - )) - } - } - - #[apply(forward_call)] - #[forward_for = IVirtualDesktopManagerInternal] - pub fn set_name(&self, desktop: &IVirtualDesktop, name: HSTRING) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IVirtualDesktopManagerInternal] - pub fn set_wallpaper(&self, desktop: &IVirtualDesktop, name: HSTRING) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IVirtualDesktopManagerInternal] - pub fn update_wallpaper_for_all(&self, name: HSTRING) -> HRESULT; -} - -support_interface!(as IVirtualDesktopPinnedAppsInner for IVirtualDesktopPinnedApps in all [build_10240, build_22000]); - -#[derive(Debug, Clone, PartialEq, Eq)] -#[repr(transparent)] -pub struct IVirtualDesktopPinnedApps(IUnknown); - -impl IVirtualDesktopPinnedApps { - #[apply(forward_call)] - #[forward_for = IVirtualDesktopPinnedApps] - pub unsafe fn is_app_pinned(&self, app_id: PCWSTR, out_iss: *mut bool) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IVirtualDesktopPinnedApps] - pub unsafe fn pin_app(&self, app_id: PCWSTR) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IVirtualDesktopPinnedApps] - pub unsafe fn unpin_app(&self, app_id: PCWSTR) -> HRESULT; - - pub fn is_view_pinned(&self, view: &IApplicationView, out_iss: &mut bool) -> HRESULT { - unsafe { - IVirtualDesktopPinnedApps!(self, |inner| inner.is_view_pinned(view.into(), out_iss)) - } - } - #[apply(forward_call)] - #[forward_for = IVirtualDesktopPinnedApps] - pub fn pin_view(&self, view: &IApplicationView) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IVirtualDesktopPinnedApps] - pub fn unpin_view(&self, view: &IApplicationView) -> HRESULT; -} - -// Bellow are helper methods that accesses the real COM interfaces. We could -// avoid the need for these helper methods by working with the IUnknown -// interface or implementing ComInterface for our abstraction types with the -// `IUnknown` IDD, even if that might get confusing. - -struct IObjectArrayGetAtCallback<'a, T>(&'a IObjectArray, UINT, PhantomData); -impl WithVersionedTypeCallback> - for IObjectArrayGetAtCallback<'_, T> -where - // The COM interface for this specific Windows version: - COM: ComInterface, - // Should be possible to convert it into the more generic type: - T: From, -{ - fn call(self) -> Result { - let com: COM = unsafe { self.0.GetAt::(self.1)? }; - Ok(From::from(com)) - } -} - -/// Same as `GetAt` for `IObjectArray` but works even when we don't know the IID -/// of a COM interface at compile time. -#[allow(non_snake_case, private_bounds)] -pub unsafe fn IObjectArrayGetAt<'a, T>( - object_array: &'a IObjectArray, - index: UINT, -) -> Result -where - T: WithVersionedType, Result>, -{ - T::with_versioned_type(IObjectArrayGetAtCallback(object_array, index, PhantomData)) - .ok_or_else(|| windows::core::Error::from(E_NOTIMPL))? -} diff --git a/src/listener.rs b/src/listener.rs index e373397..6467d99 100644 --- a/src/listener.rs +++ b/src/listener.rs @@ -4,14 +4,14 @@ use std::time::Duration; use crate::comobjects::ComObjects; use crate::interfaces::{ - IApplicationView, IVirtualDesktop, IVirtualDesktopNotification, + ComIn, IApplicationView, IVirtualDesktop, IVirtualDesktopNotification, IVirtualDesktopNotification_Impl, }; use crate::log::log_output; use crate::DesktopEventSender; use crate::{DesktopEvent, Result}; -use windows::core::{HRESULT, HSTRING}; +use windows::core::{Interface, HRESULT, HSTRING}; use windows::Win32::Foundation::HWND; use windows::Win32::System::Threading::{ GetCurrentThread, SetThreadPriority, THREAD_PRIORITY_TIME_CRITICAL, @@ -141,9 +141,9 @@ impl<'a> VirtualDesktopNotificationWrapper<'a> { sender: Box, ) -> Result>> { let ptr: Pin> = - Box::pin(VirtualDesktopNotification { sender }.into()); + Pin::new(Box::new(VirtualDesktopNotification { sender }.into())); let raw_ptr = ptr.as_raw(); - let cookie = com_objects.register_for_notifications(&ptr)?; + let cookie = com_objects.register_for_notifications(raw_ptr)?; let notification = Pin::new(Box::new(VirtualDesktopNotificationWrapper { com_objects, cookie, @@ -173,6 +173,7 @@ impl<'a> Drop for VirtualDesktopNotificationWrapper<'a> { } } +#[windows::core::implement(IVirtualDesktopNotification)] struct VirtualDesktopNotification { sender: Box, } @@ -191,10 +192,10 @@ fn eat_error(func: impl FnOnce() -> Result) -> Option { // Allow unused variable warnings #[allow(unused_variables)] impl IVirtualDesktopNotification_Impl for VirtualDesktopNotification { - fn current_virtual_desktop_changed( + unsafe fn current_virtual_desktop_changed( &self, - desktop_old: &IVirtualDesktop, - desktop_new: &IVirtualDesktop, + desktop_old: ComIn, + desktop_new: ComIn, ) -> HRESULT { eat_error(|| { Ok((self.sender)(DesktopEvent::DesktopChanged { @@ -205,9 +206,9 @@ impl IVirtualDesktopNotification_Impl for VirtualDesktopNotification { HRESULT(0) } - fn virtual_desktop_wallpaper_changed( + unsafe fn virtual_desktop_wallpaper_changed( &self, - desktop: &IVirtualDesktop, + desktop: ComIn, name: HSTRING, ) -> HRESULT { eat_error(|| { @@ -219,7 +220,7 @@ impl IVirtualDesktopNotification_Impl for VirtualDesktopNotification { HRESULT(0) } - fn virtual_desktop_created(&self, desktop: &IVirtualDesktop) -> HRESULT { + unsafe fn virtual_desktop_created(&self, desktop: ComIn) -> HRESULT { eat_error(|| { Ok((self.sender)(DesktopEvent::DesktopCreated( desktop.try_into()?, @@ -228,26 +229,26 @@ impl IVirtualDesktopNotification_Impl for VirtualDesktopNotification { HRESULT(0) } - fn virtual_desktop_destroy_begin( + unsafe fn virtual_desktop_destroy_begin( &self, - desktop_destroyed: &IVirtualDesktop, - desktop_fallback: &IVirtualDesktop, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, ) -> HRESULT { HRESULT(0) } - fn virtual_desktop_destroy_failed( + unsafe fn virtual_desktop_destroy_failed( &self, - desktop_destroyed: &IVirtualDesktop, - desktop_fallback: &IVirtualDesktop, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, ) -> HRESULT { HRESULT(0) } - fn virtual_desktop_destroyed( + unsafe fn virtual_desktop_destroyed( &self, - desktop_destroyed: &IVirtualDesktop, - desktop_fallback: &IVirtualDesktop, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, ) -> HRESULT { // Desktop destroyed is not anymore in the stack eat_error(|| { @@ -259,9 +260,9 @@ impl IVirtualDesktopNotification_Impl for VirtualDesktopNotification { HRESULT(0) } - fn virtual_desktop_moved( + unsafe fn virtual_desktop_moved( &self, - desktop: &IVirtualDesktop, + desktop: ComIn, old_index: i64, new_index: i64, ) -> HRESULT { @@ -275,9 +276,9 @@ impl IVirtualDesktopNotification_Impl for VirtualDesktopNotification { HRESULT(0) } - fn virtual_desktop_name_changed( + unsafe fn virtual_desktop_name_changed( &self, - desktop: &IVirtualDesktop, + desktop: ComIn, name: HSTRING, ) -> HRESULT { eat_error(|| { @@ -289,18 +290,18 @@ impl IVirtualDesktopNotification_Impl for VirtualDesktopNotification { HRESULT(0) } - fn view_virtual_desktop_changed(&self, view: &IApplicationView) -> HRESULT { + unsafe fn view_virtual_desktop_changed(&self, view: ComIn) -> HRESULT { let mut hwnd = HWND::default(); let _ = view.get_thumbnail_window(&mut hwnd); (self.sender)(DesktopEvent::WindowChanged(hwnd)); HRESULT(0) } - fn virtual_desktop_switched(&self, desktop: &IVirtualDesktop) -> HRESULT { + unsafe fn virtual_desktop_switched(&self, desktop: ComIn) -> HRESULT { HRESULT(0) } - fn remote_virtual_desktop_connected(&self, desktop: &IVirtualDesktop) -> HRESULT { + unsafe fn remote_virtual_desktop_connected(&self, desktop: ComIn) -> HRESULT { HRESULT(0) } } From 88801df72d021eb28499ae79c4dd769cd6d2d769 Mon Sep 17 00:00:00 2001 From: Lej77 <31554212+Lej77@users.noreply.github.com> Date: Tue, 2 Apr 2024 00:13:25 +0200 Subject: [PATCH 02/11] style: fix clippy lints --- src/comobjects.rs | 33 ++++++++++++++++++--------------- src/desktop.rs | 14 +++++++------- src/listener.rs | 2 +- 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/comobjects.rs b/src/comobjects.rs index 94becd9..93516e0 100644 --- a/src/comobjects.rs +++ b/src/comobjects.rs @@ -1,4 +1,7 @@ -/// This module contains COM object for accessing the Windows Virtual Desktop API +//! This module contains COM object for accessing the Windows Virtual Desktop API +#![allow(clippy::bool_assert_comparison)] +#![allow(clippy::upper_case_acronyms)] + use super::interfaces::*; use super::Result; use std::convert::TryFrom; @@ -263,7 +266,7 @@ impl ComObjects { provider .as_ref() - .map(|v| Rc::clone(&v)) + .map(Rc::clone) .ok_or(Error::ComAllocatedNullPtr) } @@ -289,7 +292,7 @@ impl ComObjects { } manager .as_ref() - .map(|v| Rc::clone(&v)) + .map(Rc::clone) .ok_or(Error::ComAllocatedNullPtr) } @@ -317,7 +320,7 @@ impl ComObjects { } manager_internal .as_ref() - .map(|v| Rc::clone(&v)) + .map(Rc::clone) .ok_or(Error::ComAllocatedNullPtr) } @@ -345,7 +348,7 @@ impl ComObjects { } notification_service .as_ref() - .map(|v| Rc::clone(&v)) + .map(Rc::clone) .ok_or(Error::ComAllocatedNullPtr) } @@ -372,7 +375,7 @@ impl ComObjects { pinned_apps .as_ref() .ok_or(Error::ComAllocatedNullPtr) - .map(|a| Rc::clone(a)) + .map(Rc::clone) } fn get_view_collection(&self) -> Result> { @@ -399,7 +402,7 @@ impl ComObjects { } view_collection .as_ref() - .map(|v| Rc::clone(&v)) + .map(Rc::clone) .ok_or(Error::ComAllocatedNullPtr) } @@ -538,7 +541,7 @@ impl ComObjects { let mut view = None; unsafe { self.get_view_collection()? - .get_view_for_hwnd(hwnd.clone(), &mut view) + .get_view_for_hwnd(*hwnd, &mut view) .as_result() .map_err(|er| { if er == Error::ComElementNotFound { @@ -649,7 +652,7 @@ impl ComObjects { #[apply(retry_function)] pub fn is_window_on_desktop(&self, window: &HWND, desktop: &DesktopInternal) -> Result { let desktop_win = self.get_desktop_by_window(window)?; - Ok(self.get_desktop_id(&desktop_win)? == self.get_desktop_id(&*desktop)?) + Ok(self.get_desktop_id(&desktop_win)? == self.get_desktop_id(desktop)?) } #[apply(retry_function)] @@ -657,7 +660,7 @@ impl ComObjects { unsafe { let mut value = false; self.get_manager()? - .is_window_on_current_desktop(window.clone(), &mut value) + .is_window_on_current_desktop(*window, &mut value) .as_result() .map_err(|er| match er { // Window does not exist @@ -689,7 +692,7 @@ impl ComObjects { let mut desktop = GUID::default(); unsafe { self.get_manager()? - .get_desktop_by_window(window.clone(), &mut desktop) + .get_desktop_by_window(*window, &mut desktop) .as_result() .map_err(|er| match er { // Window does not exist @@ -795,7 +798,7 @@ impl ComObjects { #[apply(retry_function)] pub fn get_desktop_name(&self, desktop: &DesktopInternal) -> Result { - let desktop = self.get_idesktop(&desktop)?; + let desktop = self.get_idesktop(desktop)?; let mut name = HSTRING::default(); unsafe { desktop.get_name(&mut name).as_result()?; @@ -805,7 +808,7 @@ impl ComObjects { #[apply(retry_function)] pub fn set_desktop_name(&self, desktop: &DesktopInternal, name: &str) -> Result<()> { - let desktop = self.get_idesktop(&desktop)?; + let desktop = self.get_idesktop(desktop)?; let manager_internal = self.get_manager_internal()?; unsafe { @@ -817,7 +820,7 @@ impl ComObjects { #[apply(retry_function)] pub fn get_desktop_wallpaper(&self, desktop: &DesktopInternal) -> Result { - let desktop = self.get_idesktop(&desktop)?; + let desktop = self.get_idesktop(desktop)?; let mut path = HSTRING::default(); unsafe { desktop.get_wallpaper(&mut path).as_result()?; @@ -864,5 +867,5 @@ where // }); // return COM_OBJECTS.with(|c| run_function_and_retry(&f, &c)); - return COM_OBJECTS.with(|c| f(&c)); + COM_OBJECTS.with(|c| f(c)) } diff --git a/src/desktop.rs b/src/desktop.rs index a5f5a50..0130e7e 100644 --- a/src/desktop.rs +++ b/src/desktop.rs @@ -95,37 +95,37 @@ impl<'a> TryFrom> for Desktop { impl Desktop { /// Get the GUID of the desktop pub fn get_id(&self) -> Result { - let internal = self.0.clone(); + let internal = self.0; with_com_objects(move |o| o.get_desktop_id(&internal)) } pub fn get_index(&self) -> Result { - let internal = self.0.clone(); + let internal = self.0; with_com_objects(move |o| o.get_desktop_index(&internal)) } /// Get desktop name pub fn get_name(&self) -> Result { - let internal = self.0.clone(); + let internal = self.0; with_com_objects(move |o| o.get_desktop_name(&internal)) } /// Set desktop name pub fn set_name(&self, name: &str) -> Result<()> { - let internal = self.0.clone(); + let internal = self.0; let name_ = name.to_owned(); with_com_objects(move |o| o.set_desktop_name(&internal, &name_)) } /// Get desktop wallpaper path pub fn get_wallpaper(&self) -> Result { - let internal = self.0.clone(); + let internal = self.0; with_com_objects(move |o| o.get_desktop_wallpaper(&internal)) } /// Set desktop wallpaper path pub fn set_wallpaper(&self, path: &str) -> Result<()> { - let internal = self.0.clone(); + let internal = self.0; let path_ = path.to_owned(); with_com_objects(move |o| o.set_desktop_wallpaper(&internal, &path_)) } @@ -181,7 +181,7 @@ where T: Into, T: Send + 'static + Copy, { - let hwnd = hwnd.clone(); + let hwnd = *hwnd; with_com_objects(move |o| o.move_window_to_desktop(&hwnd, &desktop.into().into())) } diff --git a/src/listener.rs b/src/listener.rs index 6467d99..b427447 100644 --- a/src/listener.rs +++ b/src/listener.rs @@ -141,7 +141,7 @@ impl<'a> VirtualDesktopNotificationWrapper<'a> { sender: Box, ) -> Result>> { let ptr: Pin> = - Pin::new(Box::new(VirtualDesktopNotification { sender }.into())); + Box::pin(VirtualDesktopNotification { sender }.into()); let raw_ptr = ptr.as_raw(); let cookie = com_objects.register_for_notifications(raw_ptr)?; let notification = Pin::new(Box::new(VirtualDesktopNotificationWrapper { From a4f1d3ebd8551c926c5e4e8d53212d97e01700e4 Mon Sep 17 00:00:00 2001 From: Lej77 <31554212+Lej77@users.noreply.github.com> Date: Tue, 2 Apr 2024 00:14:24 +0200 Subject: [PATCH 03/11] feat: better logging of errors in debug builds --- src/comobjects.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/comobjects.rs b/src/comobjects.rs index 93516e0..59ea8d7 100644 --- a/src/comobjects.rs +++ b/src/comobjects.rs @@ -171,7 +171,7 @@ pub struct ComObjects { view_collection: RefCell>>, } -fn retry_function(com_objects: &ComObjects, f: F) -> Result +fn retry_function(com_objects: &ComObjects, f: F, fn_name: &str) -> Result where F: Fn() -> Result, { @@ -186,7 +186,7 @@ where || er == &Error::ComNotInitialized => { #[cfg(debug_assertions)] - log_output(&format!("Retry the function after {:?}", er)); + log_output(&format!("Retry the function \"{fn_name}\" after {:?}", er)); if er == &Error::ComNotInitialized { let _ = unsafe { CoIncrementMTAUsage() }; @@ -208,7 +208,10 @@ where #[cfg(debug_assertions)] if let Err(er) = &value { - log_output(&format!("Com_objects function failed with {:?}", er)); + log_output(&format!( + "Com_objects function \"{fn_name}\" failed with {:?}", + er + )); } value @@ -236,7 +239,7 @@ macro_rules! retry_function {( { retry_function(&$self_, || -> $RetTy { $body - }) + }, stringify!($fname)) } )} From eec436886a1aac28840bd8fd602f9dae8af612db Mon Sep 17 00:00:00 2001 From: Lej77 <31554212+Lej77@users.noreply.github.com> Date: Tue, 2 Apr 2024 00:14:53 +0200 Subject: [PATCH 04/11] feat: include more error variants in the error enum --- src/comobjects.rs | 59 +++++++++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 20 deletions(-) diff --git a/src/comobjects.rs b/src/comobjects.rs index 59ea8d7..6b283f9 100644 --- a/src/comobjects.rs +++ b/src/comobjects.rs @@ -52,6 +52,15 @@ pub enum Error { /// Generic element not found ComElementNotFound, + /// A requested interface was not supported. Windows might have changed the + /// definitions of some unstable virtual desktop interfaces used by this + /// library. + ComNoInterface, + + /// Not implemented. When supporting multiple Windows versions this is + /// returned for methods that don't exist in the current version. + ComNotImplemented, + /// Some unhandled COM error ComError(HRESULT), @@ -71,27 +80,37 @@ trait HRESULTHelpers { impl HRESULTHelpers for ::windows::core::HRESULT { fn as_error(&self) -> Error { - if self.0 == -2147221164 { - // 0x80040154 - return Error::ClassNotRegistered; - } - if self.0 == -2147023174 { - // 0x800706BA - return Error::RpcServerNotAvailable; - } - if self.0 == -2147220995 { - // 0x800401FD - return Error::ComObjectNotConnected; - } - if self.0 == -2147319765 { - // 0x8002802B - return Error::ComElementNotFound; - } - if self.0 == -2147221008 { - // 0x800401F0 - return Error::ComNotInitialized; + match self.0 { + -2147221164 => { + // 0x80040154 + Error::ClassNotRegistered + } + -2147023174 => { + // 0x800706BA + Error::RpcServerNotAvailable + } + -2147220995 => { + // 0x800401FD + Error::ComObjectNotConnected + } + -2147319765 => { + // 0x8002802B + Error::ComElementNotFound + } + -2147221008 => { + // 0x800401F0 + Error::ComNotInitialized + } + -2147467262 => { + // 0x80004002 + Error::ComNoInterface + } + -2147467263 => { + // 0x80004001 + Error::ComNotImplemented + } + _ => Error::ComError(*self), } - Error::ComError(self.clone()) } fn as_result(&self) -> Result<()> { From 5610a770e717e8b165cc41f0d76eefbee324b3da Mon Sep 17 00:00:00 2001 From: Lej77 <31554212+Lej77@users.noreply.github.com> Date: Tue, 2 Apr 2024 02:32:10 +0200 Subject: [PATCH 05/11] refactor: support for multiple Windows versions now minimizes the changes in unrelated code --- Cargo.toml | 4 + src/comobjects.rs | 65 +- src/desktop.rs | 5 +- src/interfaces.rs | 152 +++- src/interfaces_multi.rs | 303 ++++++++ src/interfaces_multi/build_10240.rs | 427 ++++++++++ src/interfaces_multi/build_22000.rs | 340 ++++++++ src/interfaces_multi/build_dyn.rs | 1112 +++++++++++++++++++++++++++ src/lib.rs | 9 + src/listener.rs | 5 +- testbin/Cargo.toml | 3 + 11 files changed, 2327 insertions(+), 98 deletions(-) create mode 100644 src/interfaces_multi.rs create mode 100644 src/interfaces_multi/build_10240.rs create mode 100644 src/interfaces_multi/build_22000.rs create mode 100644 src/interfaces_multi/build_dyn.rs diff --git a/Cargo.toml b/Cargo.toml index 650384c..44d210c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,10 @@ path = "src/lib.rs" [features] integration-tests = [] +multiple-windows-versions = [ + "windows/Win32_System_SystemInformation", # For RtlGetVersion return type + "windows/Wdk_System_SystemServices", # For RtlGetVersion +] [package.metadata.docs.rs] default-target = "x86_64-pc-windows-msvc" diff --git a/src/comobjects.rs b/src/comobjects.rs index 6b283f9..1094238 100644 --- a/src/comobjects.rs +++ b/src/comobjects.rs @@ -1,8 +1,7 @@ //! This module contains COM object for accessing the Windows Virtual Desktop API -#![allow(clippy::bool_assert_comparison)] #![allow(clippy::upper_case_acronyms)] -use super::interfaces::*; +use super::interfaces_multi::*; use super::Result; use std::convert::TryFrom; use std::rc::Rc; @@ -73,7 +72,7 @@ pub enum Error { InternalBorrowError, } -trait HRESULTHelpers { +pub(crate) trait HRESULTHelpers { fn as_error(&self) -> Error; fn as_result(&self) -> Result<()>; } @@ -324,20 +323,9 @@ impl ComObjects { .try_borrow_mut() .map_err(|_| Error::InternalBorrowError)?; if manager_internal.is_none() { - let mut obj = std::ptr::null_mut::(); let provider = self.get_provider()?; - unsafe { - provider - .query_service( - &CLSID_VirtualDesktopManagerInternal, - &IVirtualDesktopManagerInternal::IID, - &mut obj, - ) - .as_result()?; - } - assert_eq!(obj.is_null(), false); *manager_internal = Some(Rc::new(unsafe { - IVirtualDesktopManagerInternal::from_raw(obj) + IVirtualDesktopManagerInternal::query_service(&provider)? })); } manager_internal @@ -353,19 +341,8 @@ impl ComObjects { .map_err(|_| Error::InternalBorrowError)?; if notification_service.is_none() { let provider = self.get_provider()?; - let mut obj = std::ptr::null_mut::(); - unsafe { - provider - .query_service( - &CLSID_IVirtualNotificationService, - &IVirtualDesktopNotificationService::IID, - &mut obj, - ) - .as_result()?; - } - assert_eq!(obj.is_null(), false); *notification_service = Some(Rc::new(unsafe { - IVirtualDesktopNotificationService::from_raw(obj) + IVirtualDesktopNotificationService::query_service(&provider)? })); } notification_service @@ -381,18 +358,7 @@ impl ComObjects { .map_err(|_| Error::InternalBorrowError)?; if pinned_apps.is_none() { let provider = self.get_provider()?; - let mut obj = std::ptr::null_mut::(); - unsafe { - provider - .query_service( - &CLSID_VirtualDesktopPinnedApps, - &IVirtualDesktopPinnedApps::IID, - &mut obj, - ) - .as_result()?; - } - assert_eq!(obj.is_null(), false); - *pinned_apps = Some(Rc::new(unsafe { IVirtualDesktopPinnedApps::from_raw(obj) })); + *pinned_apps = Some(Rc::new(unsafe { IVirtualDesktopPinnedApps::query_service(&provider)? })); } pinned_apps .as_ref() @@ -407,19 +373,8 @@ impl ComObjects { .map_err(|_| Error::InternalBorrowError)?; if view_collection.is_none() { let provider = self.get_provider()?; - let mut obj = std::ptr::null_mut::(); - unsafe { - provider - .query_service( - &IApplicationViewCollection::IID, - &IApplicationViewCollection::IID, - &mut obj, - ) - .as_result()?; - } - assert_eq!(obj.is_null(), false); *view_collection = Some(Rc::new(unsafe { - IApplicationViewCollection::from_raw(obj) + IApplicationViewCollection::query_service(&provider)? })); } view_collection @@ -492,7 +447,7 @@ impl ComObjects { let desktops = self.get_idesktops_array()?; let count = unsafe { desktops.GetCount()? }; for i in 0..count { - let desktop_id: GUID = get_idesktop_guid(&unsafe { desktops.GetAt(i)? })?; + let desktop_id: GUID = get_idesktop_guid(&unsafe { IObjectArrayGetAt(&desktops, i)? })?; if desktop_id == *id { return Ok(i); } @@ -506,7 +461,7 @@ impl ComObjects { if id >= count { return Err(Error::DesktopNotFound); } - get_idesktop_guid(&unsafe { desktops.GetAt(id)? }) + get_idesktop_guid(&unsafe { IObjectArrayGetAt(&desktops, id)? }) } fn get_idesktop(&self, desktop: &DesktopInternal) -> Result { @@ -517,7 +472,7 @@ impl ComObjects { if *id >= count { return Err(Error::DesktopNotFound); } - Ok(unsafe { desktops.GetAt(*id)? }) + Ok(unsafe { IObjectArrayGetAt(&desktops, *id)? }) } DesktopInternal::Guid(id) => { let manager = self.get_manager_internal()?; @@ -600,7 +555,7 @@ impl ComObjects { let count = unsafe { desktops.GetCount()? }; let mut result = Vec::with_capacity(count as usize); for i in 0..count { - let desktop = unsafe { desktops.GetAt(i)? }; + let desktop = unsafe { IObjectArrayGetAt(&desktops, i)? }; let id = get_idesktop_guid(&desktop)?; result.push(DesktopInternal::IndexGuid(i, id)); } diff --git a/src/desktop.rs b/src/desktop.rs index 0130e7e..10b52ae 100644 --- a/src/desktop.rs +++ b/src/desktop.rs @@ -1,7 +1,6 @@ -use crate::interfaces::ComIn; - use super::comobjects::*; -use super::{interfaces::IVirtualDesktop, *}; +use super::interfaces_multi::{ComIn, IVirtualDesktop}; +use super::*; use std::{convert::TryFrom, fmt::Debug}; use windows::{core::GUID, Win32::Foundation::HWND}; diff --git a/src/interfaces.rs b/src/interfaces.rs index 34d7035..8eac1b8 100644 --- a/src/interfaces.rs +++ b/src/interfaces.rs @@ -1,44 +1,46 @@ -/// Interface definitions for the Virtual Desktop API -/// -/// Most of the functions are not tested or used, beware if you try to use these -/// for something else. Notably I know that most out parameters defined as `*mut -/// IMyObject` are incorrect, they probably should be *mut Option. -/// -/// Generally these are the rules: -/// 1. InOpt = `Option>` or `Option>` -/// 2. In = `ComIn` or `ManuallyDrop` -/// 3. Out = `*mut Option` -/// 4. OutOpt = `*mut Option` -/// -/// Last two are same intentionally. -/// -/// ## The summary of COM object lifetime rules: -/// -/// > 1. When a COM object is passed from caller to callee as an input parameter -/// > to a method, the caller is expected to keep a reference on the object -/// > for the duration of the method call. The callee shouldn't need to call -/// > `AddRef` or `Release` for the synchronous duration of that method call. -/// > -/// > 2. When a COM object is passed from callee to caller as an out parameter -/// > from a method the object is provided to the caller with a reference -/// > already taken and the caller owns the reference. Which is to say, it is -/// > the caller's responsibility to call `Release` when they're done with -/// > the object. -/// > -/// > 3. When making a copy of a COM object pointer you need to call `AddRef` -/// > and `Release`. The `AddRef` must be called before you call `Release` on -/// > the original COM object pointer. -/// -/// Rules as [written by David -/// Risney](https://github.com/MicrosoftEdge/WebView2Feedback/issues/2133). -/// -/// If you read the rules carefully, ComIn is most common usecase in Rust -/// API definitions as most parameters are `In` parameters. -#[allow(non_upper_case_globals)] +//! Interface definitions for the Virtual Desktop API +//! +//! Most of the functions are not tested or used, beware if you try to use these +//! for something else. Notably I know that most out parameters defined as `*mut +//! IMyObject` are incorrect, they probably should be *mut Option. +//! +//! Generally these are the rules: +//! 1. InOpt = `Option>` or `Option>` +//! 2. In = `ComIn` or `ManuallyDrop` +//! 3. Out = `*mut Option` +//! 4. OutOpt = `*mut Option` +//! +//! Last two are same intentionally. +//! +//! ## The summary of COM object lifetime rules: +//! +//! > 1. When a COM object is passed from caller to callee as an input parameter +//! > to a method, the caller is expected to keep a reference on the object +//! > for the duration of the method call. The callee shouldn't need to call +//! > `AddRef` or `Release` for the synchronous duration of that method call. +//! > +//! > 2. When a COM object is passed from callee to caller as an out parameter +//! > from a method the object is provided to the caller with a reference +//! > already taken and the caller owns the reference. Which is to say, it is +//! > the caller's responsibility to call `Release` when they're done with +//! > the object. +//! > +//! > 3. When making a copy of a COM object pointer you need to call `AddRef` +//! > and `Release`. The `AddRef` must be called before you call `Release` on +//! > the original COM object pointer. +//! +//! Rules as [written by David +//! Risney](https://github.com/MicrosoftEdge/WebView2Feedback/issues/2133). +//! +//! If you read the rules carefully, ComIn is most common usecase in Rust +//! API definitions as most parameters are `In` parameters. +#![allow(non_upper_case_globals)] + +use crate::comobjects::HRESULTHelpers; use std::ffi::c_void; use std::ops::Deref; use windows::{ - core::{ComInterface, IUnknown, IUnknown_Vtbl, GUID, HRESULT, HSTRING}, + core::{ComInterface, IUnknown, IUnknown_Vtbl, Interface, GUID, HRESULT, HSTRING}, Win32::{Foundation::HWND, UI::Shell::Common::IObjectArray}, }; @@ -369,6 +371,22 @@ pub unsafe trait IApplicationViewCollection: IUnknown { pub unsafe fn unregister_for_application_view_changes(&self, id: DWORD) -> HRESULT; } +impl IApplicationViewCollection { + pub unsafe fn query_service(provider: &IServiceProvider) -> crate::Result { + let mut obj = std::ptr::null_mut::(); + unsafe { + provider + .query_service( + &IApplicationViewCollection::IID, + &IApplicationViewCollection::IID, + &mut obj, + ) + .as_result()?; + } + assert_eq!(obj.is_null(), false); + unsafe { Ok(IApplicationViewCollection::from_raw(obj)) } + } +} #[windows_interface::interface("B9E5E94D-233E-49AB-AF5C-2B4541C3AADE")] pub unsafe trait IVirtualDesktopNotification: IUnknown { @@ -437,6 +455,22 @@ pub unsafe trait IVirtualDesktopNotificationService: IUnknown { pub unsafe fn unregister(&self, cookie: u32) -> HRESULT; } +impl IVirtualDesktopNotificationService { + pub unsafe fn query_service(provider: &IServiceProvider) -> crate::Result { + let mut obj = std::ptr::null_mut::(); + unsafe { + provider + .query_service( + &CLSID_IVirtualNotificationService, + &IVirtualDesktopNotificationService::IID, + &mut obj, + ) + .as_result()?; + } + assert_eq!(obj.is_null(), false); + unsafe { Ok(IVirtualDesktopNotificationService::from_raw(obj)) } + } +} #[windows_interface::interface("53F5CA0B-158F-4124-900C-057158060B27")] pub unsafe trait IVirtualDesktopManagerInternal: IUnknown { @@ -499,6 +533,22 @@ pub unsafe trait IVirtualDesktopManagerInternal: IUnknown { pub unsafe fn set_wallpaper(&self, desktop: ComIn, name: HSTRING) -> HRESULT; pub unsafe fn update_wallpaper_for_all(&self, name: HSTRING) -> HRESULT; } +impl IVirtualDesktopManagerInternal { + pub unsafe fn query_service(provider: &IServiceProvider) -> crate::Result { + let mut obj = std::ptr::null_mut::(); + unsafe { + provider + .query_service( + &CLSID_VirtualDesktopManagerInternal, + &IVirtualDesktopManagerInternal::IID, + &mut obj, + ) + .as_result()?; + } + assert_eq!(obj.is_null(), false); + unsafe { Ok(IVirtualDesktopManagerInternal::from_raw(obj)) } + } +} #[windows_interface::interface("4CE81583-1E4C-4632-A621-07A53543148F")] pub unsafe trait IVirtualDesktopPinnedApps: IUnknown { @@ -514,3 +564,29 @@ pub unsafe trait IVirtualDesktopPinnedApps: IUnknown { pub unsafe fn pin_view(&self, view: ComIn) -> HRESULT; pub unsafe fn unpin_view(&self, view: ComIn) -> HRESULT; } +impl IVirtualDesktopPinnedApps { + pub unsafe fn query_service(provider: &IServiceProvider) -> crate::Result { + let mut obj = std::ptr::null_mut::(); + unsafe { + provider + .query_service( + &CLSID_VirtualDesktopPinnedApps, + &IVirtualDesktopPinnedApps::IID, + &mut obj, + ) + .as_result()?; + } + assert_eq!(obj.is_null(), false); + unsafe { Ok(IVirtualDesktopPinnedApps::from_raw(obj)) } + } +} + +/// Re-export of [`IObjectArray::GetAt`] to match API of the +/// [`crate::interfaces_multi`] module. +#[allow(non_snake_case)] +pub unsafe fn IObjectArrayGetAt( + array: &IObjectArray, + index: UINT, +) -> windows::core::Result { + array.GetAt(index) +} diff --git a/src/interfaces_multi.rs b/src/interfaces_multi.rs new file mode 100644 index 0000000..4f41730 --- /dev/null +++ b/src/interfaces_multi.rs @@ -0,0 +1,303 @@ +//! This is a version of the `interface` module that works for multiple +//! different Windows version by using different COM interfaces depending on the +//! version that the program is running on. +//! +//! See the docs for the normal [`crate::interfaces`] module for more info about +//! the bindings themselves. +//! +//! We manage Virtual Desktops using unstable COM interfaces which change their +//! ids and definitions regularly. +//! +//! # References +//! +//! - Interface ids at [VirtualDesktop/src/VirtualDesktop/app.config at 7e37b9848aef681713224dae558d2e51960cf41e · mzomparelli/VirtualDesktop](https://github.com/mzomparelli/VirtualDesktop/blob/7e37b9848aef681713224dae558d2e51960cf41e/src/VirtualDesktop/app.config) +//! - Bindings at [VirtualDesktop/src/VirtualDesktop/Interop at 7e37b9848aef681713224dae558d2e51960cf41e · mzomparelli/VirtualDesktop](https://github.com/mzomparelli/VirtualDesktop/tree/7e37b9848aef681713224dae558d2e51960cf41e/src/VirtualDesktop/Interop) +//! - These are actually compiled when the app is executed by the `ComInterfaceAssemblyBuilder.CreateAssembly` method at: [VirtualDesktop/src/VirtualDesktop/Interop/ComInterfaceAssemblyBuilder.cs at 7e37b9848aef681713224dae558d2e51960cf41e · mzomparelli/VirtualDesktop](https://github.com/mzomparelli/VirtualDesktop/blob/7e37b9848aef681713224dae558d2e51960cf41e/src/VirtualDesktop/Interop/ComInterfaceAssemblyBuilder.cs#L84-L153) +//! - Bindings at [MScholtes/VirtualDesktop at 6de804dced760778450ae3cd1481f8969f75fb39](https://github.com/MScholtes/VirtualDesktop/tree/6de804dced760778450ae3cd1481f8969f75fb39) + + +#![allow(non_upper_case_globals, clippy::upper_case_acronyms)] + +use std::ffi::c_void; +use std::ops::Deref; +use windows::{ + core::{ComInterface, IUnknown, IUnknown_Vtbl, GUID, HRESULT, HSTRING}, + Win32::{Foundation::HWND, UI::Shell::Common::IObjectArray}, +}; + +/// This macro allows us to access the version names in other macros. +macro_rules! declare_versions { + (@inner { + dollar = {$dollar:tt}, + versions = {$($version:ident),* $(,)?}, + }) => { + macro_rules! _with_versions { + ($dollar macro_callback:path $dollar (, $dollar ( $dollar state:tt )* )?) => { + $dollar macro_callback! { + $dollar ($dollar ( $dollar state )* )? + versions = {$($version,)*}, + } + }; + } + #[allow(unused_imports)] + use _with_versions as with_versions; + }; + ($( + $(#[ $($attr:tt)* ])* + mod $version:ident $({ $($code:tt)* })? $(; $(<= $semi:tt)?)? + )*) => { + $( + $(#[ $($attr)* ])* + mod $version $({ $($code)* })? $(; $($semi)?)? + )* + declare_versions! {@inner { + dollar = {$}, + versions = {$($version,)*}, + }} + }; +} +declare_versions!( + mod build_10240; + mod build_22000; +); +mod build_dyn; + +// We only consume the COM interfaces in a way where we don't depend on the +// exact Windows version: +pub use build_dyn::*; + +/// Use when defining a COM interface to allow re-defining it later with a +/// different IID. +/// +/// This defines a macro with the same name as the interface that can be invoked +/// with a string literal representing a new IID. +macro_rules! _reusable_com_interface { + (@inner { + dollar = {$dollar:tt}, + interface = {$($interface:tt)*}, + export_as = {$name:ident}, + temp_macro_name = {$temp_name:ident}, + initial_iid = {$initial_iid:literal}, + }) => { + // Allow re-use of the declaration with different COM interface iid: + macro_rules! $temp_name { + ($dollar iid:literal) => { + $crate::interfaces_multi::reusable_com_interface!( + MacroOptions { + temp_macro_name: $temp_name, + iid: $dollar iid, + }, + { + $($interface)* + } + ); + } + } + #[allow(unused_imports)] + pub(crate) use $temp_name as $name; + + // Declare the COM interface at least once: + #[windows_interface::interface($initial_iid)] + $($interface)* + }; + // This syntax was chosen so that rustfmt would still work on macro context + // (rustfmt only formats macros invoked using parenthesis not other + // brackets.) + (MacroOptions { + temp_macro_name: $temp_name:ident, + iid: $initial_iid:literal $(,)? + }, { + $(#[$($attr:tt)*])* + $pub:vis $(unsafe $(@ $unsafe:ident)?)? trait $name:ident $($interface:tt)* + }) => { + $crate::interfaces_multi::reusable_com_interface! {@inner { + dollar = {$}, + interface = { + $(#[$($attr)*])* + $pub $(unsafe $(@ $unsafe)?)? trait $name + $($interface)* + }, + export_as = {$name}, + temp_macro_name = {$temp_name}, + initial_iid = {$initial_iid}, + }} + }; +} +// Allow normal imports to work for macro: +use _reusable_com_interface as reusable_com_interface; + + +/// Type that can be cast into [`ComIn`] +/// +/// # Safety +/// +/// - Can cast from `*mut c_void` to `Self`. (`Self` is a transparent type over +/// a raw pointer.) +/// - The returned pointer is valid while the reference it was created from is +/// valid. +pub unsafe trait PointerRepr { + fn as_pointer_repr(&self) -> *mut c_void; +} +unsafe impl PointerRepr for T { + fn as_pointer_repr(&self) -> *mut c_void { + windows::core::Interface::as_raw(self) + } +} + +/// ComIn is a wrapper for COM objects that are passed as input parameters. It +/// allows to keep the life of the COM object for the duration of the function +/// call. +/// +/// Imagine following situation: +/// +/// First you call an API function that gives COM object as out parameter. And +/// you want to pass it to another function that takes the COM object as an +/// input parameter. If you were to use ManuallyDrop then you'd have to call the +/// drop manually after the second function call. +/// +/// E.g. +/// +/// ```rust +/// fn get_current_desktop(&mut self, desktop: &mut Option) -> HRESULT; +/// fn switch_desktop(&self, desktop: ManuallyDrop) -> HRESULT; +/// +/// let mut desktop: Option = None; +/// get_current_desktop(&mut desktop); +/// if let Some(desktop) = desktop { +/// let input = ManuallyDrop::new(desktop); +/// switch_desktop(input); +/// ManuallyDrop::drop(input); +/// } +/// ``` +/// +/// To make things safer and easier to use, ComIn is used instead. +/// +/// ```rust +/// fn get_current_desktop(&mut self, desktop: &mut Option) -> HRESULT; +/// fn switch_desktop(&self, desktop: ComIn) -> HRESULT; +/// +/// let mut desktop: Option = None; +/// if let Some(desktop) = desktop { +/// get_current_desktop(&mut desktop); +/// switch_desktop(ComIn::new(&input)); +/// } +/// ``` +#[repr(transparent)] +pub struct ComIn<'a, T> { + data: *mut c_void, + _phantom: std::marker::PhantomData<&'a T>, +} +impl<'a, T: PointerRepr> ComIn<'a, T> { + pub fn new(t: &'a T) -> Self { + Self { + // Copies the raw Inteface pointer + data: t.as_pointer_repr(), + _phantom: std::marker::PhantomData, + } + } +} +impl<'a, T> ComIn<'a, T> { + pub fn into_ref(this: &Self) -> &'a T { + // Safety: A ComInterface type `T` is just a transparent type over a raw pointer + unsafe { &*(&this.data as *const *mut c_void as *const T) } + } +} +impl<'a, T> Deref for ComIn<'a, T> { + type Target = T; + fn deref(&self) -> &Self::Target { + Self::into_ref(self) + } +} + +#[allow(non_upper_case_globals)] +pub const CLSID_ImmersiveShell: GUID = GUID::from_u128(0xC2F03A33_21F5_47FA_B4BB_156362A2F239); + +#[allow(dead_code)] +#[allow(non_upper_case_globals)] +pub const CLSID_IVirtualNotificationService: GUID = + GUID::from_u128(0xA501FDEC_4A09_464C_AE4E_1B9C21B84918); + +#[allow(non_upper_case_globals)] +pub const CLSID_VirtualDesktopManagerInternal: GUID = + GUID::from_u128(0xC5E0CDCA_7B6E_41B2_9FC4_D93975CC467B); + +#[allow(non_upper_case_globals)] +pub const CLSID_VirtualDesktopPinnedApps: GUID = + GUID::from_u128(0xb5a399e7_1c87_46b8_88e9_fc5747b171bd); + +type BOOL = i32; +type DWORD = u32; +type INT = i32; +type LPVOID = *mut c_void; +type UINT = u32; +type ULONG = u32; +type WCHAR = u16; +type PCWSTR = *const WCHAR; +type PWSTR = *mut WCHAR; +type ULONGLONG = u64; +type LONG = i32; + +type IAsyncCallback = UINT; +type IImmersiveMonitor = UINT; +type IApplicationViewOperation = UINT; +type IApplicationViewPosition = UINT; +type IShellPositionerPriority = *mut c_void; +type IImmersiveApplication = UINT; +type IApplicationViewChangeListener = UINT; +#[allow(non_camel_case_types)] +type APPLICATION_VIEW_COMPATIBILITY_POLICY = UINT; +#[allow(non_camel_case_types)] +type APPLICATION_VIEW_CLOAK_TYPE = UINT; + +#[allow(dead_code)] +#[repr(C)] +pub struct RECT { + left: LONG, + top: LONG, + right: LONG, + bottom: LONG, +} + +#[allow(dead_code)] +#[repr(C)] +pub struct SIZE { + cx: LONG, + cy: LONG, +} + +// These COM interfaces are not different between different Windows versions: + +#[windows_interface::interface("6D5140C1-7436-11CE-8034-00AA006009FA")] +pub unsafe trait IServiceProvider: IUnknown { + pub unsafe fn query_service( + &self, + guid_service: *const GUID, + riid: *const GUID, + ppv_object: *mut *mut c_void, + ) -> HRESULT; + // unsafe fn remote_query_service( + // &self, + // guidService: *const DesktopID, + // riid: *const IID, + // ppvObject: *mut *mut c_void, + // ) -> HRESULT; +} + +#[windows_interface::interface("A5CD92FF-29BE-454C-8D04-D82879FB3F1B")] +pub unsafe trait IVirtualDesktopManager: IUnknown { + pub unsafe fn is_window_on_current_desktop( + &self, + top_level_window: HWND, + out_on_current_desktop: *mut bool, + ) -> HRESULT; + pub unsafe fn get_desktop_by_window( + &self, + top_level_window: HWND, + out_desktop_id: *mut GUID, + ) -> HRESULT; + pub unsafe fn move_window_to_desktop( + &self, + top_level_window: HWND, + desktop_id: *const GUID, + ) -> HRESULT; +} diff --git a/src/interfaces_multi/build_10240.rs b/src/interfaces_multi/build_10240.rs new file mode 100644 index 0000000..e108eb4 --- /dev/null +++ b/src/interfaces_multi/build_10240.rs @@ -0,0 +1,427 @@ +//! Support for Windows 10. +//! +//! These definitions should be valid from Windows version `10240` (inclusive) to `22000` (exclusive). +use super::*; + +reusable_com_interface!( + MacroOptions { + temp_macro_name: _IApplicationView, + iid: "871F602A-2B58-42B4-8C4B-6C43D642C06F", + }, + { + pub unsafe trait IApplicationView: IUnknown { + /* IInspecateble */ + pub unsafe fn get_iids( + &self, + out_iid_count: *mut ULONG, + out_opt_iid_array_ptr: *mut *mut GUID, + ) -> HRESULT; + pub unsafe fn get_runtime_class_name( + &self, + out_opt_class_name: *mut HSTRING, + ) -> HRESULT; + pub unsafe fn get_trust_level(&self, ptr_trust_level: LPVOID) -> HRESULT; + + /* IApplicationView methods */ + pub unsafe fn set_focus(&self) -> HRESULT; + pub unsafe fn switch_to(&self) -> HRESULT; + + pub unsafe fn try_invoke_back(&self, ptr_async_callback: IAsyncCallback) -> HRESULT; + pub unsafe fn get_thumbnail_window(&self, out_hwnd: *mut HWND) -> HRESULT; + pub unsafe fn get_monitor(&self, out_monitors: *mut *mut IImmersiveMonitor) -> HRESULT; + pub unsafe fn get_visibility(&self, out_int: LPVOID) -> HRESULT; + pub unsafe fn set_cloak( + &self, + application_view_cloak_type: APPLICATION_VIEW_CLOAK_TYPE, + unknown: INT, + ) -> HRESULT; + pub unsafe fn get_position( + &self, + unknowniid: *const GUID, + unknown_array_ptr: LPVOID, + ) -> HRESULT; + pub unsafe fn set_position( + &self, + view_position: *mut IApplicationViewPosition, + ) -> HRESULT; + pub unsafe fn insert_after_window(&self, window: HWND) -> HRESULT; + pub unsafe fn get_extended_frame_position(&self, rect: *mut RECT) -> HRESULT; + pub unsafe fn get_app_user_model_id(&self, id: *mut PWSTR) -> HRESULT; // Proc17 + pub unsafe fn set_app_user_model_id(&self, id: PCWSTR) -> HRESULT; + pub unsafe fn is_equal_by_app_user_model_id( + &self, + id: PCWSTR, + out_result: *mut INT, + ) -> HRESULT; + + /*** IApplicationView methods ***/ + pub unsafe fn get_view_state(&self, out_state: *mut UINT) -> HRESULT; // Proc20 + pub unsafe fn set_view_state(&self, state: UINT) -> HRESULT; // Proc21 + pub unsafe fn get_neediness(&self, out_neediness: *mut INT) -> HRESULT; // Proc22 + pub unsafe fn get_last_activation_timestamp( + &self, + out_timestamp: *mut ULONGLONG, + ) -> HRESULT; + pub unsafe fn set_last_activation_timestamp(&self, timestamp: ULONGLONG) -> HRESULT; + pub unsafe fn get_virtual_desktop_id(&self, out_desktop_guid: *mut GUID) -> HRESULT; + pub unsafe fn set_virtual_desktop_id(&self, desktop_guid: *const GUID) -> HRESULT; + pub unsafe fn get_show_in_switchers(&self, out_show: *mut INT) -> HRESULT; + pub unsafe fn set_show_in_switchers(&self, show: INT) -> HRESULT; + pub unsafe fn get_scale_factor(&self, out_scale_factor: *mut INT) -> HRESULT; + pub unsafe fn can_receive_input(&self, out_can: *mut BOOL) -> HRESULT; + pub unsafe fn get_compatibility_policy_type( + &self, + out_policy_type: *mut APPLICATION_VIEW_COMPATIBILITY_POLICY, + ) -> HRESULT; + pub unsafe fn set_compatibility_policy_type( + &self, + policy_type: APPLICATION_VIEW_COMPATIBILITY_POLICY, + ) -> HRESULT; + pub unsafe fn get_position_priority( + &self, + out_priority: *mut IShellPositionerPriority, + ) -> HRESULT; + pub unsafe fn set_position_priority( + &self, + priority: IShellPositionerPriority, + ) -> HRESULT; + + pub unsafe fn get_size_constraints( + &self, + monitor: *mut IImmersiveMonitor, + out_size1: *mut SIZE, + out_size2: *mut SIZE, + ) -> HRESULT; + pub unsafe fn get_size_constraints_for_dpi( + &self, + dpi: UINT, + out_size1: *mut SIZE, + out_size2: *mut SIZE, + ) -> HRESULT; + pub unsafe fn set_size_constraints_for_dpi( + &self, + dpi: *const UINT, + size1: *const SIZE, + size2: *const SIZE, + ) -> HRESULT; + + pub unsafe fn query_size_constraints_from_app(&self) -> HRESULT; + pub unsafe fn on_min_size_preferences_updated(&self, window: HWND) -> HRESULT; + pub unsafe fn apply_operation( + &self, + operation: *mut IApplicationViewOperation, + ) -> HRESULT; + pub unsafe fn is_tray(&self, out_is: *mut BOOL) -> HRESULT; + pub unsafe fn is_in_high_zorder_band(&self, out_is: *mut BOOL) -> HRESULT; + pub unsafe fn is_splash_screen_presented(&self, out_is: *mut BOOL) -> HRESULT; + pub unsafe fn flash(&self) -> HRESULT; + pub unsafe fn get_root_switchable_owner( + &self, + app_view: *mut IApplicationView, + ) -> HRESULT; // proc45 + pub unsafe fn enumerate_ownership_tree(&self, objects: *mut IObjectArray) -> HRESULT; // proc46 + + pub unsafe fn get_enterprise_id(&self, out_id: *mut PWSTR) -> HRESULT; // proc47 + pub unsafe fn is_mirrored(&self, out_is: *mut BOOL) -> HRESULT; // + + pub unsafe fn unknown1(&self, arg: *mut INT) -> HRESULT; + pub unsafe fn unknown2(&self, arg: *mut INT) -> HRESULT; + pub unsafe fn unknown3(&self, arg: *mut INT) -> HRESULT; + pub unsafe fn unknown4(&self, arg: INT) -> HRESULT; + pub unsafe fn unknown5(&self, arg: *mut INT) -> HRESULT; + pub unsafe fn unknown6(&self, arg: INT) -> HRESULT; + pub unsafe fn unknown7(&self) -> HRESULT; + pub unsafe fn unknown8(&self, arg: *mut INT) -> HRESULT; + pub unsafe fn unknown9(&self, arg: INT) -> HRESULT; + pub unsafe fn unknown10(&self, arg: INT, arg2: INT) -> HRESULT; + pub unsafe fn unknown11(&self, arg: INT) -> HRESULT; + pub unsafe fn unknown12(&self, arg: *mut SIZE) -> HRESULT; + } + } +); + +reusable_com_interface!( + MacroOptions { + temp_macro_name: _IApplicationViewCollection, + iid: "1841C6D7-4F9D-42C0-AF41-8747538F10E5", + }, + { + pub unsafe trait IApplicationViewCollection: IUnknown { + pub unsafe fn get_views(&self, out_views: *mut IObjectArray) -> HRESULT; + + pub unsafe fn get_views_by_zorder(&self, out_views: *mut IObjectArray) -> HRESULT; + + pub unsafe fn get_views_by_app_user_model_id( + &self, + id: PCWSTR, + out_views: *mut IObjectArray, + ) -> HRESULT; + + pub unsafe fn get_view_for_hwnd( + &self, + window: HWND, + out_view: *mut Option, + ) -> HRESULT; + + pub unsafe fn get_view_for_application( + &self, + app: IImmersiveApplication, + out_view: *mut IApplicationView, + ) -> HRESULT; + + pub unsafe fn get_view_for_app_user_model_id( + &self, + id: PCWSTR, + out_view: *mut IApplicationView, + ) -> HRESULT; + + pub unsafe fn get_view_in_focus(&self, out_view: *mut IApplicationView) -> HRESULT; + + pub unsafe fn refresh_collection(&self) -> HRESULT; + + pub unsafe fn register_for_application_view_changes( + &self, + listener: IApplicationViewChangeListener, + out_id: *mut DWORD, + ) -> HRESULT; + + pub unsafe fn register_for_application_view_position_changes( + &self, + listener: IApplicationViewChangeListener, + out_id: *mut DWORD, + ) -> HRESULT; + + pub unsafe fn unregister_for_application_view_changes(&self, id: DWORD) -> HRESULT; + } + } +); + +reusable_com_interface!( + MacroOptions { + temp_macro_name: _IVirtualDesktop, + iid: "FF72FFDD-BE7E-43FC-9C03-AD81681E88E4", + }, + { + pub unsafe trait IVirtualDesktop: IUnknown { + pub unsafe fn is_view_visible( + &self, + p_view: ComIn, + out_bool: *mut u32, + ) -> HRESULT; + pub unsafe fn get_id(&self, out_guid: *mut GUID) -> HRESULT; + } + } +); + +reusable_com_interface!( + MacroOptions { + temp_macro_name: _IVirtualDesktopNotification, + iid: "C179334C-4295-40D3-BEA1-C654D965605A", + }, + { + pub unsafe trait IVirtualDesktopNotification: IUnknown { + pub unsafe fn virtual_desktop_created( + &self, + desktop: ComIn, + ) -> HRESULT; + + pub unsafe fn virtual_desktop_destroy_begin( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT; + + pub unsafe fn virtual_desktop_destroy_failed( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT; + + pub unsafe fn virtual_desktop_destroyed( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT; + + pub unsafe fn view_virtual_desktop_changed( + &self, + view: ComIn, + ) -> HRESULT; + + pub unsafe fn current_virtual_desktop_changed( + &self, + desktop_old: ComIn, + desktop_new: ComIn, + ) -> HRESULT; + } + + /// Implements an unstable interface that is only valid for a single Windows + /// version using a more stable trait that works for all Windows versions. + #[windows::core::implement(IVirtualDesktopNotification)] + pub struct VirtualDesktopNotificationAdaptor + where + T: build_dyn::IVirtualDesktopNotification_Impl, + { + pub inner: T, + } + impl IVirtualDesktopNotification_Impl for VirtualDesktopNotificationAdaptor + where + T: build_dyn::IVirtualDesktopNotification_Impl, + { + unsafe fn current_virtual_desktop_changed( + &self, + desktop_old: ComIn, + desktop_new: ComIn, + ) -> HRESULT { + self.inner + .current_virtual_desktop_changed(desktop_old.into(), desktop_new.into()) + } + + unsafe fn virtual_desktop_created(&self, desktop: ComIn) -> HRESULT { + self.inner.virtual_desktop_created(desktop.into()) + } + + unsafe fn virtual_desktop_destroy_begin( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT { + self.inner.virtual_desktop_destroy_begin( + desktop_destroyed.into(), + desktop_fallback.into(), + ) + } + + unsafe fn virtual_desktop_destroy_failed( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT { + self.inner.virtual_desktop_destroy_failed( + desktop_destroyed.into(), + desktop_fallback.into(), + ) + } + + unsafe fn virtual_desktop_destroyed( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT { + self.inner.virtual_desktop_destroyed( + desktop_destroyed.into(), + desktop_fallback.into(), + ) + } + + unsafe fn view_virtual_desktop_changed( + &self, + view: ComIn, + ) -> HRESULT { + self.inner.view_virtual_desktop_changed(view.into()) + } + } + } +); + +reusable_com_interface!( + MacroOptions { + temp_macro_name: _IVirtualDesktopNotificationService, + iid: "0CD45E71-D927-4F15-8B0A-8FEF525337BF", + }, + { + pub unsafe trait IVirtualDesktopNotificationService: IUnknown { + pub unsafe fn register( + &self, + notification: *mut std::ffi::c_void, // *const IVirtualDesktopNotification, + out_cookie: *mut DWORD, + ) -> HRESULT; + + pub unsafe fn unregister(&self, cookie: u32) -> HRESULT; + } + } +); + +reusable_com_interface!( + MacroOptions { + temp_macro_name: _IVirtualDesktopManagerInternal, + iid: "0F3A72B0-4566-487E-9A33-4ED302F6D6CE", + }, + { + pub unsafe trait IVirtualDesktopManagerInternal: IUnknown { + pub unsafe fn get_desktop_count(&self, out_count: *mut UINT) -> HRESULT; + + pub unsafe fn move_view_to_desktop( + &self, + view: ComIn, + desktop: ComIn, + ) -> HRESULT; + + pub unsafe fn can_move_view_between_desktops( + &self, + view: ComIn, + can_move: *mut i32, + ) -> HRESULT; + + pub unsafe fn get_current_desktop( + &self, + out_desktop: *mut Option, + ) -> HRESULT; + + pub unsafe fn get_desktops(&self, out_desktops: *mut Option) -> HRESULT; + + /// Get next or previous desktop + /// + /// Direction values: + /// 3 = Left direction + /// 4 = Right direction + pub unsafe fn get_adjacent_desktop( + &self, + in_desktop: ComIn, + direction: UINT, + out_pp_desktop: *mut Option, + ) -> HRESULT; + + pub unsafe fn switch_desktop(&self, desktop: ComIn) -> HRESULT; + + pub unsafe fn create_desktop( + &self, + out_desktop: *mut Option, + ) -> HRESULT; + + pub unsafe fn remove_desktop( + &self, + destroy_desktop: ComIn, + fallback_desktop: ComIn, + ) -> HRESULT; + + pub unsafe fn find_desktop( + &self, + guid: *const GUID, + out_desktop: *mut Option, + ) -> HRESULT; + } + } +); + +reusable_com_interface!( + MacroOptions { + temp_macro_name: _IVirtualDesktopPinnedApps, + iid: "4CE81583-1E4C-4632-A621-07A53543148F", + }, + { + pub unsafe trait IVirtualDesktopPinnedApps: IUnknown { + pub unsafe fn is_app_pinned(&self, app_id: PCWSTR, out_iss: *mut bool) -> HRESULT; + pub unsafe fn pin_app(&self, app_id: PCWSTR) -> HRESULT; + pub unsafe fn unpin_app(&self, app_id: PCWSTR) -> HRESULT; + + pub unsafe fn is_view_pinned( + &self, + view: ComIn, + out_iss: *mut bool, + ) -> HRESULT; + pub unsafe fn pin_view(&self, view: ComIn) -> HRESULT; + pub unsafe fn unpin_view(&self, view: ComIn) -> HRESULT; + } + } +); diff --git a/src/interfaces_multi/build_22000.rs b/src/interfaces_multi/build_22000.rs new file mode 100644 index 0000000..0967961 --- /dev/null +++ b/src/interfaces_multi/build_22000.rs @@ -0,0 +1,340 @@ +//! Support for Windows 11. +use super::*; + +// These interfaces haven't changed since previous version: +build_10240::IApplicationView!("372E1D3B-38D3-42E4-A15B-8AB2B178F513"); +build_10240::IApplicationViewCollection!("1841c6d7-4f9d-42c0-af41-8747538f10e5"); + +// But these interfaces have different methods: + +reusable_com_interface!( + MacroOptions { + temp_macro_name: _IVirtualDesktop, + iid: "3F07F4BE-B107-441A-AF0F-39D82529072C", + }, + { + pub unsafe trait IVirtualDesktop: IUnknown { + pub unsafe fn is_view_visible( + &self, + p_view: ComIn, + out_bool: *mut u32, + ) -> HRESULT; + pub unsafe fn get_id(&self, out_guid: *mut GUID) -> HRESULT; + pub unsafe fn get_name(&self, out_string: *mut HSTRING) -> HRESULT; + pub unsafe fn get_wallpaper(&self, out_string: *mut HSTRING) -> HRESULT; + } + } +); + +reusable_com_interface!( + MacroOptions { + temp_macro_name: _IVirtualDesktopNotification, + iid: "B9E5E94D-233E-49AB-AF5C-2B4541C3AADE", + }, + { + pub unsafe trait IVirtualDesktopNotification: IUnknown { + pub unsafe fn virtual_desktop_created( + &self, + desktop: ComIn, + ) -> HRESULT; + + pub unsafe fn virtual_desktop_destroy_begin( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT; + + pub unsafe fn virtual_desktop_destroy_failed( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT; + + pub unsafe fn virtual_desktop_destroyed( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT; + + pub unsafe fn proc7(&self) -> HRESULT; + + pub unsafe fn virtual_desktop_moved( + &self, + desktop: ComIn, + old_index: i64, + new_index: i64, + ) -> HRESULT; + + pub unsafe fn virtual_desktop_name_changed( + &self, + desktop: ComIn, + name: HSTRING, + ) -> HRESULT; + + pub unsafe fn view_virtual_desktop_changed( + &self, + view: ComIn, + ) -> HRESULT; + + pub unsafe fn current_virtual_desktop_changed( + &self, + desktop_old: ComIn, + desktop_new: ComIn, + ) -> HRESULT; + + pub unsafe fn virtual_desktop_wallpaper_changed( + &self, + desktop: ComIn, + name: HSTRING, + ) -> HRESULT; + + pub unsafe fn virtual_desktop_switched( + &self, + desktop: ComIn, + ) -> HRESULT; + + pub unsafe fn remote_virtual_desktop_connected( + &self, + desktop: ComIn, + ) -> HRESULT; + } + + /// Implements an unstable interface that is only valid for a single Windows + /// version using a more stable trait that works for all Windows versions. + #[windows::core::implement(IVirtualDesktopNotification)] + pub struct VirtualDesktopNotificationAdaptor + where + T: build_dyn::IVirtualDesktopNotification_Impl, + { + pub inner: T, + } + impl IVirtualDesktopNotification_Impl for VirtualDesktopNotificationAdaptor + where + T: build_dyn::IVirtualDesktopNotification_Impl, + { + unsafe fn current_virtual_desktop_changed( + &self, + desktop_old: ComIn, + desktop_new: ComIn, + ) -> HRESULT { + self.inner + .current_virtual_desktop_changed(desktop_old.into(), desktop_new.into()) + } + + unsafe fn virtual_desktop_wallpaper_changed( + &self, + desktop: ComIn, + name: HSTRING, + ) -> HRESULT { + self.inner + .virtual_desktop_wallpaper_changed(desktop.into(), name) + } + + unsafe fn virtual_desktop_created(&self, desktop: ComIn) -> HRESULT { + self.inner.virtual_desktop_created(desktop.into()) + } + + unsafe fn virtual_desktop_destroy_begin( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT { + self.inner.virtual_desktop_destroy_begin( + desktop_destroyed.into(), + desktop_fallback.into(), + ) + } + + unsafe fn virtual_desktop_destroy_failed( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT { + self.inner.virtual_desktop_destroy_failed( + desktop_destroyed.into(), + desktop_fallback.into(), + ) + } + + unsafe fn virtual_desktop_destroyed( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT { + self.inner.virtual_desktop_destroyed( + desktop_destroyed.into(), + desktop_fallback.into(), + ) + } + + unsafe fn proc7(&self) -> HRESULT { + HRESULT(0) + } + + unsafe fn virtual_desktop_moved( + &self, + desktop: ComIn, + old_index: i64, + new_index: i64, + ) -> HRESULT { + self.inner + .virtual_desktop_moved(desktop.into(), old_index, new_index) + } + + unsafe fn virtual_desktop_name_changed( + &self, + desktop: ComIn, + name: HSTRING, + ) -> HRESULT { + self.inner + .virtual_desktop_name_changed(desktop.into(), name) + } + + unsafe fn view_virtual_desktop_changed( + &self, + view: ComIn, + ) -> HRESULT { + self.inner.view_virtual_desktop_changed(view.into()) + } + + unsafe fn virtual_desktop_switched(&self, desktop: ComIn) -> HRESULT { + self.inner.virtual_desktop_switched(desktop.into()) + } + + unsafe fn remote_virtual_desktop_connected( + &self, + desktop: ComIn, + ) -> HRESULT { + self.inner + .remote_virtual_desktop_connected(desktop.into()) + } + } + } +); + +reusable_com_interface!( + MacroOptions { + temp_macro_name: _IVirtualDesktopNotificationService, + iid: "0CD45E71-D927-4F15-8B0A-8FEF525337BF", + }, + { + pub unsafe trait IVirtualDesktopNotificationService: IUnknown { + pub unsafe fn register( + &self, + notification: *mut std::ffi::c_void, // *const IVirtualDesktopNotification, + out_cookie: *mut DWORD, + ) -> HRESULT; + + pub unsafe fn unregister(&self, cookie: u32) -> HRESULT; + } + } +); + +reusable_com_interface!( + MacroOptions { + temp_macro_name: _IVirtualDesktopManagerInternal, + iid: "53F5CA0B-158F-4124-900C-057158060B27", + }, + { + pub unsafe trait IVirtualDesktopManagerInternal: IUnknown { + pub unsafe fn get_desktop_count(&self, out_count: *mut UINT) -> HRESULT; + + pub unsafe fn move_view_to_desktop( + &self, + view: ComIn, + desktop: ComIn, + ) -> HRESULT; + + pub unsafe fn can_move_view_between_desktops( + &self, + view: ComIn, + can_move: *mut i32, + ) -> HRESULT; + + pub unsafe fn get_current_desktop( + &self, + out_desktop: *mut Option, + ) -> HRESULT; + + pub unsafe fn get_desktops(&self, out_desktops: *mut Option) -> HRESULT; + + /// Get next or previous desktop + /// + /// Direction values: + /// 3 = Left direction + /// 4 = Right direction + pub unsafe fn get_adjacent_desktop( + &self, + in_desktop: ComIn, + direction: UINT, + out_pp_desktop: *mut Option, + ) -> HRESULT; + + pub unsafe fn switch_desktop(&self, desktop: ComIn) -> HRESULT; + + pub unsafe fn create_desktop( + &self, + out_desktop: *mut Option, + ) -> HRESULT; + + pub unsafe fn move_desktop( + &self, + in_desktop: ComIn, + index: UINT, + ) -> HRESULT; + + pub unsafe fn remove_desktop( + &self, + destroy_desktop: ComIn, + fallback_desktop: ComIn, + ) -> HRESULT; + + pub unsafe fn find_desktop( + &self, + guid: *const GUID, + out_desktop: *mut Option, + ) -> HRESULT; + + pub unsafe fn get_desktop_switch_include_exclude_views( + &self, + desktop: ComIn, + out_pp_desktops1: *mut IObjectArray, + out_pp_desktops2: *mut IObjectArray, + ) -> HRESULT; + + pub unsafe fn set_name( + &self, + desktop: ComIn, + name: HSTRING, + ) -> HRESULT; + pub unsafe fn set_wallpaper( + &self, + desktop: ComIn, + name: HSTRING, + ) -> HRESULT; + pub unsafe fn update_wallpaper_for_all(&self, name: HSTRING) -> HRESULT; + } + } +); + +reusable_com_interface!( + MacroOptions { + temp_macro_name: _IVirtualDesktopPinnedApps, + iid: "4CE81583-1E4C-4632-A621-07A53543148F", + }, + { + pub unsafe trait IVirtualDesktopPinnedApps: IUnknown { + pub unsafe fn is_app_pinned(&self, app_id: PCWSTR, out_iss: *mut bool) -> HRESULT; + pub unsafe fn pin_app(&self, app_id: PCWSTR) -> HRESULT; + pub unsafe fn unpin_app(&self, app_id: PCWSTR) -> HRESULT; + + pub unsafe fn is_view_pinned( + &self, + view: ComIn, + out_iss: *mut bool, + ) -> HRESULT; + pub unsafe fn pin_view(&self, view: ComIn) -> HRESULT; + pub unsafe fn unpin_view(&self, view: ComIn) -> HRESULT; + } + } +); diff --git a/src/interfaces_multi/build_dyn.rs b/src/interfaces_multi/build_dyn.rs new file mode 100644 index 0000000..aa70877 --- /dev/null +++ b/src/interfaces_multi/build_dyn.rs @@ -0,0 +1,1112 @@ +//! Interface abstraction that allow interacting with COM interfaces even when +//! we don't know their IID and what exact methods they have until runtime. +//! +//! The interface types in this module is similar to the ones in the version +//! specific modules except they don't implement `ComInterface` since their IID +//! isn't known at compile time. + +use super::*; + +use crate::comobjects::HRESULTHelpers; +use core::{ffi::c_void, marker::PhantomData}; +use windows::{ + core::{ComInterface, Interface, GUID, HRESULT, HSTRING}, + Win32::{ + Foundation::{E_NOTIMPL, HWND}, + UI::Shell::Common::IObjectArray, + }, +}; + +macro_rules! declare_WindowsVersion { + (versions = {$($version:ident,)*},) => { + /// Indicates different Windows versions that have different Virtual Desktop + /// interfaces. + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] + #[allow(non_camel_case_types)] + enum WindowsVersion { + $($version,)* + } + impl WindowsVersion { + const ALL: &'static [Self] = &[$(Self::$version,)*]; + const fn as_str(&self) -> &'static str { + match self { + $(Self::$version => stringify!($version),)* + } + } + } + impl Default for WindowsVersion { + fn default() -> Self { + *Self::ALL.last().expect("No Windows version is supported") + } + } + }; +} +with_versions!(declare_WindowsVersion); + +// Check that the versions are sorted when they were declared, this is a bit +// slow currently so it has been disabled: +// impl WindowsVersion { +// #[allow(dead_code)] +// const fn has_sorted_versions() -> bool { +// let mut prev = 0; +// let ix = 0; +// let arr = Self::ALL; +// while ix < arr.len() { +// let ver = arr[ix].windows_build(); +// if ver < prev { +// return false; +// } +// prev = ver; +// } +// true +// } +// /// Code from +// const _ASSERT_SORTED_VERSIONS: [(); 0 - !Self::has_sorted_versions() as usize] = []; +// const fn windows_build(&self) -> u32 { +// let name = self.as_str(); +// let bytes = name.as_bytes(); +// let mut ix = 0; +// while ix < bytes.len() && !u8::is_ascii_digit(&bytes[ix]) { +// ix += 1; +// } +// let mut parsed = 0; +// while ix < bytes.len() { +// parsed *= 10; +// parsed += (bytes[ix] - b'0') as u32; +// ix += 1; +// } +// parsed +// } +// } +impl WindowsVersion { + fn windows_build(&self) -> u32 { + let (_, ver) = self + .as_str() + .split_once('_') + .expect("Module name didn't contain an underscore"); + ver.parse() + .expect("Failed to parse module suffix as build version") + } + /// Get info about the current Windows version. Only differentiates between + /// Windows versions that have different virtual desktop interfaces. + /// + /// # Determining Windows Version + /// + /// We could use the [`GetVersionExW` function + /// (sysinfoapi.h)](https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getversionexw), + /// but it is deprecated after Windows 8.1. It also changes behavior depending + /// on what manifest is embedded in the executable. + /// + /// That pages links to [Version Helper functions - Win32 + /// apps](https://learn.microsoft.com/en-us/windows/win32/sysinfo/version-helper-apis) + /// where we are linked to the [`IsWindowsVersionOrGreater` function + /// (versionhelpers.h)](https://learn.microsoft.com/en-us/windows/win32/api/VersionHelpers/nf-versionhelpers-iswindowsversionorgreater) + /// and the [`VerifyVersionInfoA` function + /// (winbase.h)](https://learn.microsoft.com/en-us/windows/win32/api/Winbase/nf-winbase-verifyversioninfoa) + /// that it uses internally (though the later function is deprecated in Windows + /// 10). + /// + /// We can use `RtlGetVersion` [RtlGetVersion function (wdm.h) - Windows + /// drivers](https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-rtlgetversion?redirectedfrom=MSDN) + /// as mentioned at [c++ - Detecting Windows 10 version - Stack + /// Overflow](https://stackoverflow.com/questions/36543301/detecting-windows-10-version/36545162#36545162). + /// + /// # `windows` API References + /// + /// - [GetVersionExW in windows::Win32::System::SystemInformation - + /// Rust](https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/System/SystemInformation/fn.GetVersionExW.html) + /// - Affected by manifest. + /// - [RtlGetVersion in windows::Wdk::System::SystemServices - + /// Rust](https://microsoft.github.io/windows-docs-rs/doc/windows/Wdk/System/SystemServices/fn.RtlGetVersion.html) + /// - Always returns the correct version. + pub fn get() -> Self { + static INIT: std::sync::OnceLock = std::sync::OnceLock::new(); + *INIT.get_or_init(|| { + let mut version: windows::Win32::System::SystemInformation::OSVERSIONINFOW = + Default::default(); + version.dwOSVersionInfoSize = core::mem::size_of_val(&version) as u32; + let res = unsafe { windows::Wdk::System::SystemServices::RtlGetVersion(&mut version) }; + if res.is_err() { + return Default::default(); + } + Self::ALL + .iter() + .copied() + .map(|v| (v, v.windows_build())) + // Only consider COM interfaces from previous or current build: + .filter(|(_, build_ver)| *build_ver <= version.dwBuildNumber) + // Then find the latest one: + .max_by_key(|(_, build_ver)| *build_ver) + .map(|(v, _)| v) + .unwrap_or_default() + }) + } +} + +/// Do an action with the type of the actual COM Interface on this Windows +/// version. +/// +/// This is implemented for the more generic COM interfaces that don't know +/// their IID at compile time. Those implementations will put a bound on `F` so +/// that it must accept all concrete COM types that might be used. +pub trait WithVersionedType { + /// Invokes the callback with the COM interface type of this Windows + /// version. Return `None` if the interface doesn't exist on this platform. + fn with_versioned_type(callback: F) -> Option; +} +/// A callback that will be invoked with the actual COM interface type for a +/// specific Windows version. +/// +/// Implement this when you want to make use of a concrete COM interface type. +pub trait WithVersionedTypeCallback { + fn call(self) -> R; +} + +pub(crate) trait ForwardArg { + fn forward(self) -> T; +} +impl ForwardArg for T { + fn forward(self) -> Self { + self + } +} + +/// Generates support code for a COM interface. +/// +/// Syntax is: `as CreatedEnumName for InterfaceName in $(all)? [version_module_1, version_module_2 $(,)?]` +macro_rules! support_interface { + (@inner {$dollar:tt} as $state:ident for $name:ident in $(all $(@ $all:tt)?)? [$($version:ident),* $(,)?]) => { + $( + // assert_eq_size from static_assertions crate + const _: fn() = || { + // We need this since we transmute and pointer cast between the two types. + let _ = core::mem::transmute::<$name, self::$version::$name>; + }; + )* + + // Maybe enforce that all build versions are supported by this interface: + #[allow(unreachable_patterns)] + const _: fn(WindowsVersion) = |version: WindowsVersion| { + match version { + $(WindowsVersion::$version => (),)* + // If there is no "all" word in the macro input then: + // all() => true + // Otherwise: + // all(false) => false + // any() => false + // all(any()) => false + // And the default macro arm will be hidden. + #[cfg(all($(any() $($all)?)?))] + _ => (), + } + }; + + /// An enum with one variant per Windows version that is supported by + /// this interface. Use the `from_typed` function to construct this + /// type. + #[allow(non_camel_case_types)] + enum $state<'a> { + $( $version(ComIn<'a, self::$version::$name>) ),* + } + impl<'a> $state<'a> { + fn from_typed(data: &'a $name) -> Self { + unsafe { Self::from_raw(&data.0) } + } + /// # Safety + /// + /// The COM object must implement the expected interface. + #[allow(unreachable_patterns)] + unsafe fn from_raw(data: &'a IUnknown) -> Self { + let win_ver = WindowsVersion::get(); + match win_ver { + $(WindowsVersion::$version => $state::$version(core::mem::transmute_copy::>(data)),)* + _ => unreachable!("Tried to cast into a COM interface that wasn't available for the current Windows version"), + } + } + } + impl $name { + /// Convert from a raw pointer to the COM interface. + /// + /// # Safety + /// + /// The pointer must be an instance of the COM interface indicated + /// by the `IID` method. + pub unsafe fn from_raw(ptr: *mut c_void) -> Self { + Self(IUnknown::from_raw(ptr)) + } + pub fn as_raw(&self) -> *mut c_void { + self.0.as_raw() + } + + /// The IID for the COM interface that is supported by this + /// platform, return a zeroed GUID if the interface isn't supported. + #[allow(non_snake_case, unreachable_patterns)] + pub unsafe fn IID() -> GUID { + match WindowsVersion::get() { + $(WindowsVersion::$version => self::$version::$name::IID,)* + _ => GUID::zeroed(), + } + } + } + /// Allow putting the abstract type in the `ComIn` wrapper type. + unsafe impl PointerRepr for $name { + fn as_pointer_repr(&self) -> *mut c_void { + windows::core::Interface::as_raw(&self.0) + } + } + /// Allow direct access to the wrapped COM interface type if required. + impl WithVersionedType for $name + where + $( + F: WithVersionedTypeCallback, + )* + { + #[allow(unreachable_patterns)] + fn with_versioned_type(callback: F) -> Option { + match WindowsVersion::get() { + $(WindowsVersion::$version => Some(>::call(callback)),)* + _ => None, + } + } + } + // From implementations to make forwarding arguments to versioned + // interface methods easier: + $( + /// Versioned -> Abstract + impl From for $name { + fn from(v: self::$version::$name) -> Self { + debug_assert_eq!( + WindowsVersion::get(), + WindowsVersion::$version, + "if we have an COM interface for a specific Windows version then we must already have ensured that it is actually the Windows version the user has" + ); + Self(v.into()) + } + } + /// &Versioned -> &Abstract + impl<'a> From<&'a self::$version::$name> for &'a $name { + fn from(v: &'a self::$version::$name) -> Self { + debug_assert_eq!( + WindowsVersion::get(), + WindowsVersion::$version, + "if we have an COM interface for a specific Windows version then we must already have ensured that it is actually the Windows version the user has" + ); + // Safety: both types are just transparent wrappers over a + // raw pointer and we don't drop either of them. + unsafe { + &*(v as *const self::$version::$name as *const $name) + } + } + } + /// ComIn -> ComIn + impl<'a> From> for ComIn<'a, $name> { + fn from(v: ComIn<'a, self::$version::$name>) -> Self { + ComIn::new(<&$name as From<_>>::from(ComIn::into_ref(&v))) + } + } + /// Abstract -> Versioned (fallible) + impl From<$name> for self::$version::$name { + fn from(v: $name) -> Self { + assert_eq!(WindowsVersion::get(), WindowsVersion::$version); + // Safety: interpret the wrapped raw pointer as the specific COM interface. + unsafe { core::mem::transmute(v.0) } + } + } + /// ComIn -> ComIn (fallible) + impl<'a> From> for ComIn<'a, self::$version::$name> { + #[allow(irrefutable_let_patterns)] + fn from(v: ComIn<'a, $name>) -> Self { + if let $state::$version(v) = $state::from_typed(ComIn::into_ref(&v)) { + v + } else { + unreachable!("requested a COM interface for a different Windows version than the one that was installed"); + } + } + } + /// ComIn -> ComIn (fallible) + impl<'a> ForwardArg> for ComIn<'a, $name> { + fn forward(self) -> ComIn<'a, self::$version::$name> { + self.into() + } + } + /// *mut Option -> *mut Option + impl ForwardArg<*mut Option> for *mut Option<$name> { + fn forward(self) -> *mut Option { + self as *mut _ + } + } + )* + /// Preform the same action for each version of the wrapped COM interface. + /// + /// Syntax: GeneralType, |versioned: versioned_mod::VersionedType| block_of_code + /// + /// Note: named the same as the interface to allow for easier usage with macros. + #[allow(unused_macros)] + macro_rules! $name { + ( + $dollar this:expr, + |$dollar arg:ident + $dollar ( + : + $dollar module_name:ident + :: + $dollar arg_ty:ident + )? + | + $dollar ($dollar body:tt)* + ) => { + match $state::from_typed(&$dollar this) { + $( + $state::$version($dollar arg) => { + $dollar ( + #[allow(unused_imports)] + use self::$version as $dollar module_name; + #[allow(unused_imports)] + use self::$version::$name as $dollar arg_ty; + )? + $dollar ($dollar body)* + }, + )* + } + } + } + }; + // Pass an escaped dollar sign to the real macro so that we can construct a + // new macro later: + (as $state:ident for $name:ident in $($in:tt)*) => { + support_interface! { @inner {$} as $state for $name in $($in)* } + }; +} + +/// Implement a method by calling the same method on the Windows version +/// dependant COM interface. +macro_rules! forward_call { + ( + #[forward_for = $name:ident] + $( #[$attr:meta] )* + $pub:vis + $(unsafe $(@ $unsafe:tt)?)? + fn $fname:ident ( + &$self_:ident $(,)? $( $arg_name:ident : $ArgTy:ty ),* $(,)? + ) -> $RetTy:ty; + ) => ( + $( #[$attr] )* + #[allow(unused_parens)] + $pub + $(unsafe $($unsafe)?)? + fn $fname ( + &$self_, $( $arg_name : $ArgTy ),* + ) -> $RetTy + { + unsafe { + $name!( + $self_, + |v| (*v).$fname( $( + ForwardArg::forward($arg_name) + ),*) + ) + } + } + ); + ( + $( #[$attr:meta] )* + impl $name:ident { + $($item:item)* + } + ) => { + $(#[$attr])* + impl $name { + $( + #[apply(forward_call)] + #[forward_for = $name] + $item + )* + } + }; +} + +support_interface!(as IApplicationViewInner for IApplicationView in all [build_10240, build_22000]); + +#[derive(Debug, Clone, PartialEq, Eq)] +#[repr(transparent)] +pub struct IApplicationView(IUnknown); +impl IApplicationView { + /* IInspecateble */ + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn get_iids( + &self, + out_iid_count: *mut ULONG, + out_opt_iid_array_ptr: *mut *mut GUID, + ) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn get_runtime_class_name(&self, out_opt_class_name: *mut HSTRING) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn get_trust_level(&self, ptr_trust_level: LPVOID) -> HRESULT; + + /* IApplicationView methods */ + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn set_focus(&self) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn switch_to(&self) -> HRESULT; + + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn try_invoke_back(&self, ptr_async_callback: IAsyncCallback) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn get_thumbnail_window(&self, out_hwnd: *mut HWND) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn get_monitor(&self, out_monitors: *mut *mut IImmersiveMonitor) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn get_visibility(&self, out_int: LPVOID) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn set_cloak( + &self, + application_view_cloak_type: APPLICATION_VIEW_CLOAK_TYPE, + unknown: INT, + ) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn get_position( + &self, + unknowniid: *const GUID, + unknown_array_ptr: LPVOID, + ) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn set_position(&self, view_position: *mut IApplicationViewPosition) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn insert_after_window(&self, window: HWND) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn get_extended_frame_position(&self, rect: *mut RECT) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn get_app_user_model_id(&self, id: *mut PWSTR) -> HRESULT; // Proc17 + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn set_app_user_model_id(&self, id: PCWSTR) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn is_equal_by_app_user_model_id(&self, id: PCWSTR, out_result: *mut INT) + -> HRESULT; + + /*** IApplicationView methods ***/ + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn get_view_state(&self, out_state: *mut UINT) -> HRESULT; // Proc20 + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn set_view_state(&self, state: UINT) -> HRESULT; // Proc21 + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn get_neediness(&self, out_neediness: *mut INT) -> HRESULT; // Proc22 + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn get_last_activation_timestamp(&self, out_timestamp: *mut ULONGLONG) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn set_last_activation_timestamp(&self, timestamp: ULONGLONG) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn get_virtual_desktop_id(&self, out_desktop_guid: *mut GUID) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn set_virtual_desktop_id(&self, desktop_guid: *const GUID) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn get_show_in_switchers(&self, out_show: *mut INT) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn set_show_in_switchers(&self, show: INT) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn get_scale_factor(&self, out_scale_factor: *mut INT) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn can_receive_input(&self, out_can: *mut BOOL) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn get_compatibility_policy_type( + &self, + out_policy_type: *mut APPLICATION_VIEW_COMPATIBILITY_POLICY, + ) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn set_compatibility_policy_type( + &self, + policy_type: APPLICATION_VIEW_COMPATIBILITY_POLICY, + ) -> HRESULT; + + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn get_size_constraints( + &self, + monitor: *mut IImmersiveMonitor, + out_size1: *mut SIZE, + out_size2: *mut SIZE, + ) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn get_size_constraints_for_dpi( + &self, + dpi: UINT, + out_size1: *mut SIZE, + out_size2: *mut SIZE, + ) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn set_size_constraints_for_dpi( + &self, + dpi: *const UINT, + size1: *const SIZE, + size2: *const SIZE, + ) -> HRESULT; + + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn on_min_size_preferences_updated(&self, window: HWND) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn apply_operation(&self, operation: *mut IApplicationViewOperation) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn is_tray(&self, out_is: *mut BOOL) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn is_in_high_zorder_band(&self, out_is: *mut BOOL) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn is_splash_screen_presented(&self, out_is: *mut BOOL) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn flash(&self) -> HRESULT; + pub unsafe fn get_root_switchable_owner(&self, app_view: *mut IApplicationView) -> HRESULT { + // proc45 + IApplicationView!(self, |inner| inner + .get_root_switchable_owner(app_view as *mut _)) + } + + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn enumerate_ownership_tree(&self, objects: *mut IObjectArray) -> HRESULT; // proc46 + + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn get_enterprise_id(&self, out_id: *mut PWSTR) -> HRESULT; // proc47 + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn is_mirrored(&self, out_is: *mut BOOL) -> HRESULT; // + + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn unknown1(&self, arg: *mut INT) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn unknown2(&self, arg: *mut INT) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn unknown3(&self, arg: *mut INT) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn unknown4(&self, arg: INT) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn unknown5(&self, arg: *mut INT) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn unknown6(&self, arg: INT) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn unknown7(&self) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn unknown8(&self, arg: *mut INT) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn unknown9(&self, arg: INT) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn unknown10(&self, arg: INT, arg2: INT) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn unknown11(&self, arg: INT) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IApplicationView] + pub unsafe fn unknown12(&self, arg: *mut SIZE) -> HRESULT; +} + +support_interface!(as IVirtualDesktopInner for IVirtualDesktop in [build_10240, build_22000]); + +#[derive(Debug, Clone, PartialEq, Eq)] +#[repr(transparent)] +pub struct IVirtualDesktop(IUnknown); +impl IVirtualDesktop { + #[apply(forward_call)] + #[forward_for = IVirtualDesktop] + pub unsafe fn is_view_visible( + &self, + p_view: ComIn, + out_bool: *mut u32, + ) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IVirtualDesktop] + pub unsafe fn get_id(&self, out_guid: *mut GUID) -> HRESULT; + + pub unsafe fn get_name(&self, out_string: *mut HSTRING) -> HRESULT { + match IVirtualDesktopInner::from_typed(self) { + IVirtualDesktopInner::build_10240(_) => E_NOTIMPL, + IVirtualDesktopInner::build_22000(this) => unsafe { this.get_name(out_string) }, + } + } + pub unsafe fn get_wallpaper(&self, out_string: *mut HSTRING) -> HRESULT { + match IVirtualDesktopInner::from_typed(self) { + IVirtualDesktopInner::build_10240(_) => E_NOTIMPL, + IVirtualDesktopInner::build_22000(this) => unsafe { this.get_wallpaper(out_string) }, + } + } +} + +support_interface!(as IApplicationViewCollectionInner for IApplicationViewCollection in all [build_10240, build_22000]); + +#[derive(Debug, Clone, PartialEq, Eq)] +#[repr(transparent)] +pub struct IApplicationViewCollection(IUnknown); +impl IApplicationViewCollection { + #[apply(forward_call)] + #[forward_for = IApplicationViewCollection] + pub unsafe fn get_views(&self, out_views: *mut IObjectArray) -> HRESULT; + + #[apply(forward_call)] + #[forward_for = IApplicationViewCollection] + pub unsafe fn get_views_by_zorder(&self, out_views: *mut IObjectArray) -> HRESULT; + + #[apply(forward_call)] + #[forward_for = IApplicationViewCollection] + pub unsafe fn get_views_by_app_user_model_id( + &self, + id: PCWSTR, + out_views: *mut IObjectArray, + ) -> HRESULT; + + pub unsafe fn get_view_for_hwnd( + &self, + window: HWND, + out_view: *mut Option, + ) -> HRESULT { + IApplicationViewCollection!(self, |inner| inner + .get_view_for_hwnd(window, out_view as *mut _)) + } + + pub unsafe fn get_view_for_application( + &self, + app: IImmersiveApplication, + out_view: *mut IApplicationView, + ) -> HRESULT { + IApplicationViewCollection!(self, |inner| inner + .get_view_for_application(app, out_view as *mut _)) + } + + pub unsafe fn get_view_for_app_user_model_id( + &self, + id: PCWSTR, + out_view: *mut IApplicationView, + ) -> HRESULT { + IApplicationViewCollection!(self, |inner| inner + .get_view_for_app_user_model_id(id, out_view as *mut _)) + } + + pub unsafe fn get_view_in_focus(&self, out_view: &mut Option) -> HRESULT { + unsafe { + IApplicationViewCollection!(self, |inner| inner + .get_view_in_focus(out_view as *mut Option<_> as *mut _)) + } + } + + #[apply(forward_call)] + #[forward_for = IApplicationViewCollection] + pub unsafe fn refresh_collection(&self) -> HRESULT; + + pub unsafe fn register_for_application_view_changes( + &self, + listener: IApplicationViewChangeListener, + out_id: &mut DWORD, + ) -> HRESULT { + unsafe { + IApplicationViewCollection!(self, |inner| inner + .register_for_application_view_changes(listener, out_id)) + } + } + + #[apply(forward_call)] + #[forward_for = IApplicationViewCollection] + pub unsafe fn unregister_for_application_view_changes(&self, id: DWORD) -> HRESULT; +} +impl IApplicationViewCollection { + pub unsafe fn query_service(provider: &IServiceProvider) -> crate::Result { + let mut obj = std::ptr::null_mut::(); + unsafe { + provider + .query_service( + &IApplicationViewCollection::IID(), + &IApplicationViewCollection::IID(), + &mut obj, + ) + .as_result()?; + } + assert_eq!(obj.is_null(), false); + unsafe { Ok(IApplicationViewCollection::from_raw(obj)) } + } +} + +support_interface!(as IVirtualDesktopNotificationInner for IVirtualDesktopNotification in all [build_10240, build_22000]); + +#[derive(Debug, Clone, PartialEq, Eq)] +#[repr(transparent)] +pub struct IVirtualDesktopNotification(IUnknown); +impl From for IVirtualDesktopNotification +where + T: IVirtualDesktopNotification_Impl, +{ + fn from(value: T) -> Self { + match WindowsVersion::get() { + WindowsVersion::build_10240 => build_10240::IVirtualDesktopNotification::from( + build_10240::VirtualDesktopNotificationAdaptor { inner: value }, + ) + .into(), + WindowsVersion::build_22000 => build_22000::IVirtualDesktopNotification::from( + build_22000::VirtualDesktopNotificationAdaptor { inner: value }, + ) + .into(), + } + } +} +#[allow(non_camel_case_types)] +pub trait IVirtualDesktopNotification_Impl { + unsafe fn virtual_desktop_created(&self, desktop: ComIn) -> HRESULT; + + unsafe fn virtual_desktop_destroy_begin( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT; + + unsafe fn virtual_desktop_destroy_failed( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT; + + unsafe fn virtual_desktop_destroyed( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT; + + unsafe fn virtual_desktop_moved( + &self, + desktop: ComIn, + old_index: i64, + new_index: i64, + ) -> HRESULT; + + unsafe fn virtual_desktop_name_changed( + &self, + desktop: ComIn, + name: HSTRING, + ) -> HRESULT; + + unsafe fn view_virtual_desktop_changed(&self, view: ComIn) -> HRESULT; + + unsafe fn current_virtual_desktop_changed( + &self, + desktop_old: ComIn, + desktop_new: ComIn, + ) -> HRESULT; + + unsafe fn virtual_desktop_wallpaper_changed( + &self, + desktop: ComIn, + name: HSTRING, + ) -> HRESULT; + + unsafe fn virtual_desktop_switched(&self, desktop: ComIn) -> HRESULT; + + unsafe fn remote_virtual_desktop_connected(&self, desktop: ComIn) -> HRESULT; +} + +support_interface!(as IVirtualDesktopNotificationServiceInner for IVirtualDesktopNotificationService in all [build_10240, build_22000]); + +#[derive(Debug, Clone, PartialEq, Eq)] +#[repr(transparent)] +pub struct IVirtualDesktopNotificationService(IUnknown); + +impl IVirtualDesktopNotificationService { + #[apply(forward_call)] + #[forward_for = IVirtualDesktopNotificationService] + pub unsafe fn register( + &self, + notification: *mut std::ffi::c_void, + out_cookie: *mut DWORD, + ) -> HRESULT; + + #[apply(forward_call)] + #[forward_for = IVirtualDesktopNotificationService] + pub unsafe fn unregister(&self, cookie: u32) -> HRESULT; +} +impl IVirtualDesktopNotificationService { + pub unsafe fn query_service(provider: &IServiceProvider) -> crate::Result { + let mut obj = std::ptr::null_mut::(); + unsafe { + provider + .query_service( + &CLSID_IVirtualNotificationService, + &IVirtualDesktopNotificationService::IID(), + &mut obj, + ) + .as_result()?; + } + assert_eq!(obj.is_null(), false); + unsafe { Ok(IVirtualDesktopNotificationService::from_raw(obj)) } + } +} + +support_interface!(as IVirtualDesktopManagerInternalInner for IVirtualDesktopManagerInternal in all [build_10240, build_22000]); + +#[derive(Debug, Clone, PartialEq, Eq)] +#[repr(transparent)] +pub struct IVirtualDesktopManagerInternal(IUnknown); +impl IVirtualDesktopManagerInternal { + #[apply(forward_call)] + #[forward_for = IVirtualDesktopManagerInternal] + pub unsafe fn get_desktop_count(&self, out_count: *mut UINT) -> HRESULT; + + #[apply(forward_call)] + #[forward_for = IVirtualDesktopManagerInternal] + pub unsafe fn move_view_to_desktop( + &self, + view: ComIn, + desktop: ComIn, + ) -> HRESULT; + + pub unsafe fn can_move_view_between_desktops( + &self, + view: ComIn, + can_move: &mut i32, + ) -> HRESULT { + unsafe { + IVirtualDesktopManagerInternal!(self, |i| i + .can_move_view_between_desktops(view.into(), can_move)) + } + } + + #[apply(forward_call)] + #[forward_for = IVirtualDesktopManagerInternal] + pub unsafe fn get_current_desktop(&self, out_desktop: *mut Option) -> HRESULT; + + #[apply(forward_call)] + #[forward_for = IVirtualDesktopManagerInternal] + pub unsafe fn get_desktops(&self, out_desktops: *mut Option) -> HRESULT; + + #[apply(forward_call)] + #[forward_for = IVirtualDesktopManagerInternal] + /// Get next or previous desktop + /// + /// Direction values: + /// 3 = Left direction + /// 4 = Right direction + pub unsafe fn get_adjacent_desktop( + &self, + in_desktop: ComIn, + direction: UINT, + out_pp_desktop: *mut Option, + ) -> HRESULT; + + #[apply(forward_call)] + #[forward_for = IVirtualDesktopManagerInternal] + pub unsafe fn switch_desktop(&self, desktop: ComIn) -> HRESULT; + + #[apply(forward_call)] + #[forward_for = IVirtualDesktopManagerInternal] + pub unsafe fn create_desktop(&self, out_desktop: *mut Option) -> HRESULT; + + pub unsafe fn move_desktop(&self, in_desktop: ComIn, index: UINT) -> HRESULT { + match IVirtualDesktopManagerInternalInner::from_typed(self) { + IVirtualDesktopManagerInternalInner::build_10240(_) => E_NOTIMPL, + IVirtualDesktopManagerInternalInner::build_22000(v) => { + v.move_desktop(in_desktop.into(), index) + } + } + } + + #[apply(forward_call)] + #[forward_for = IVirtualDesktopManagerInternal] + pub unsafe fn remove_desktop( + &self, + destroy_desktop: ComIn, + fallback_desktop: ComIn, + ) -> HRESULT; + + pub unsafe fn find_desktop( + &self, + guid: *const GUID, + out_desktop: *mut Option, + ) -> HRESULT { + unsafe { + IVirtualDesktopManagerInternal!(self, |inner| { + inner.find_desktop(guid, out_desktop.forward()) + }) + } + } + + pub unsafe fn get_desktop_switch_include_exclude_views( + &self, + desktop: ComIn, + out_pp_desktops1: *mut IObjectArray, + out_pp_desktops2: *mut IObjectArray, + ) -> HRESULT { + match IVirtualDesktopManagerInternalInner::from_typed(self) { + IVirtualDesktopManagerInternalInner::build_10240(_) => E_NOTIMPL, + IVirtualDesktopManagerInternalInner::build_22000(inner) => inner + .get_desktop_switch_include_exclude_views( + desktop.forward(), + out_pp_desktops1, + out_pp_desktops2, + ), + } + } + + pub unsafe fn set_name(&self, desktop: ComIn, name: HSTRING) -> HRESULT { + match IVirtualDesktopManagerInternalInner::from_typed(self) { + IVirtualDesktopManagerInternalInner::build_10240(_) => E_NOTIMPL, + IVirtualDesktopManagerInternalInner::build_22000(inner) => { + inner.set_name(desktop.forward(), name) + } + } + } + pub unsafe fn set_wallpaper(&self, desktop: ComIn, name: HSTRING) -> HRESULT { + match IVirtualDesktopManagerInternalInner::from_typed(self) { + IVirtualDesktopManagerInternalInner::build_10240(_) => E_NOTIMPL, + IVirtualDesktopManagerInternalInner::build_22000(inner) => { + inner.set_wallpaper(desktop.forward(), name) + } + } + } + pub unsafe fn update_wallpaper_for_all(&self, name: HSTRING) -> HRESULT { + match IVirtualDesktopManagerInternalInner::from_typed(self) { + IVirtualDesktopManagerInternalInner::build_10240(_) => E_NOTIMPL, + IVirtualDesktopManagerInternalInner::build_22000(inner) => { + inner.update_wallpaper_for_all(name) + } + } + } +} +impl IVirtualDesktopManagerInternal { + pub unsafe fn query_service(provider: &IServiceProvider) -> crate::Result { + let mut obj = std::ptr::null_mut::(); + unsafe { + provider + .query_service( + &CLSID_VirtualDesktopManagerInternal, + &IVirtualDesktopManagerInternal::IID(), + &mut obj, + ) + .as_result()?; + } + assert_eq!(obj.is_null(), false); + unsafe { Ok(IVirtualDesktopManagerInternal::from_raw(obj)) } + } +} + +support_interface!(as IVirtualDesktopPinnedAppsInner for IVirtualDesktopPinnedApps in all [build_10240, build_22000]); + +#[derive(Debug, Clone, PartialEq, Eq)] +#[repr(transparent)] +pub struct IVirtualDesktopPinnedApps(IUnknown); + +impl IVirtualDesktopPinnedApps { + #[apply(forward_call)] + #[forward_for = IVirtualDesktopPinnedApps] + pub unsafe fn is_app_pinned(&self, app_id: PCWSTR, out_iss: *mut bool) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IVirtualDesktopPinnedApps] + pub unsafe fn pin_app(&self, app_id: PCWSTR) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IVirtualDesktopPinnedApps] + pub unsafe fn unpin_app(&self, app_id: PCWSTR) -> HRESULT; + + pub unsafe fn is_view_pinned( + &self, + view: ComIn, + out_iss: *mut bool, + ) -> HRESULT { + unsafe { + IVirtualDesktopPinnedApps!(self, |inner| inner.is_view_pinned(view.into(), out_iss)) + } + } + #[apply(forward_call)] + #[forward_for = IVirtualDesktopPinnedApps] + pub unsafe fn pin_view(&self, view: ComIn) -> HRESULT; + #[apply(forward_call)] + #[forward_for = IVirtualDesktopPinnedApps] + pub unsafe fn unpin_view(&self, view: ComIn) -> HRESULT; +} +impl IVirtualDesktopPinnedApps { + pub unsafe fn query_service(provider: &IServiceProvider) -> crate::Result { + let mut obj = std::ptr::null_mut::(); + unsafe { + provider + .query_service( + &CLSID_VirtualDesktopPinnedApps, + &IVirtualDesktopPinnedApps::IID(), + &mut obj, + ) + .as_result()?; + } + assert_eq!(obj.is_null(), false); + unsafe { Ok(IVirtualDesktopPinnedApps::from_raw(obj)) } + } +} + +// Bellow are helper methods that accesses the real COM interfaces. We could +// avoid the need for these helper methods by working with the IUnknown +// interface or implementing ComInterface for our abstraction types with the +// `IUnknown` IDD, even if that might get confusing. + +struct IObjectArrayGetAtCallback<'a, T>(&'a IObjectArray, UINT, PhantomData); +impl WithVersionedTypeCallback> + for IObjectArrayGetAtCallback<'_, T> +where + // The COM interface for this specific Windows version: + COM: ComInterface, + // Should be possible to convert it into the more generic type: + T: From, +{ + fn call(self) -> Result { + let com: COM = unsafe { self.0.GetAt::(self.1)? }; + Ok(From::from(com)) + } +} + +/// Same as `GetAt` for `IObjectArray` but works even when we don't know the IID +/// of a COM interface at compile time. +#[allow(non_snake_case, private_bounds)] +pub unsafe fn IObjectArrayGetAt<'a, T>( + object_array: &'a IObjectArray, + index: UINT, +) -> Result +where + T: WithVersionedType, Result>, +{ + T::with_versioned_type(IObjectArrayGetAtCallback(object_array, index, PhantomData)) + .ok_or_else(|| windows::core::Error::from(E_NOTIMPL))? +} diff --git a/src/lib.rs b/src/lib.rs index 4974321..1c8c9e2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,10 +8,15 @@ //! * Get desktop name by GUID `get_desktop(GUID(123...)).get_name()` //! * Switch to fifth desktop by index `switch_desktop(4)` //! * Get third desktop name `get_desktop(2).get_name()` +#![allow(clippy::bool_assert_comparison)] + mod comobjects; mod desktop; mod events; +#[cfg_attr(feature = "multiple-windows-versions", allow(dead_code))] mod interfaces; +#[cfg(feature = "multiple-windows-versions")] +mod interfaces_multi; mod listener; mod log; @@ -19,6 +24,10 @@ mod log; #[cfg(test)] mod tests; +// Allow importing the single version COM interfaces. +#[cfg(not(feature = "multiple-windows-versions"))] +use interfaces as interfaces_multi; + pub use comobjects::Error; pub use desktop::*; pub use events::*; diff --git a/src/listener.rs b/src/listener.rs index b427447..286876d 100644 --- a/src/listener.rs +++ b/src/listener.rs @@ -3,7 +3,7 @@ use std::pin::Pin; use std::time::Duration; use crate::comobjects::ComObjects; -use crate::interfaces::{ +use crate::interfaces_multi::{ ComIn, IApplicationView, IVirtualDesktop, IVirtualDesktopNotification, IVirtualDesktopNotification_Impl, }; @@ -11,6 +11,7 @@ use crate::log::log_output; use crate::DesktopEventSender; use crate::{DesktopEvent, Result}; +#[allow(unused_imports)] use windows::core::{Interface, HRESULT, HSTRING}; use windows::Win32::Foundation::HWND; use windows::Win32::System::Threading::{ @@ -173,7 +174,7 @@ impl<'a> Drop for VirtualDesktopNotificationWrapper<'a> { } } -#[windows::core::implement(IVirtualDesktopNotification)] +#[cfg_attr(not(feature = "multiple-windows-versions"), windows::core::implement(IVirtualDesktopNotification))] struct VirtualDesktopNotification { sender: Box, } diff --git a/testbin/Cargo.toml b/testbin/Cargo.toml index 59dd0b3..383a2cb 100644 --- a/testbin/Cargo.toml +++ b/testbin/Cargo.toml @@ -7,6 +7,9 @@ publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +multiple-windows-versions = ["winvd/multiple-windows-versions"] + [dependencies] winit = "0.29" winvd = { path = "../", features = ["winit"] } From e87809359763081ad015055a8dd6de0be71f76b5 Mon Sep 17 00:00:00 2001 From: Lej77 <31554212+Lej77@users.noreply.github.com> Date: Tue, 2 Apr 2024 02:49:46 +0200 Subject: [PATCH 06/11] refactor: smarter macro to minimize repeated code --- src/interfaces_multi/build_dyn.rs | 288 ++++++++++++------------------ 1 file changed, 116 insertions(+), 172 deletions(-) diff --git a/src/interfaces_multi/build_dyn.rs b/src/interfaces_multi/build_dyn.rs index aa70877..733c77d 100644 --- a/src/interfaces_multi/build_dyn.rs +++ b/src/interfaces_multi/build_dyn.rs @@ -335,6 +335,12 @@ macro_rules! support_interface { self as *mut _ } } + /// *mut Abstract -> *mut Versioned + impl ForwardArg<*mut self::$version::$name> for *mut $name { + fn forward(self) -> *mut self::$version::$name { + self as *mut _ + } + } )* /// Preform the same action for each version of the wrapped COM interface. /// @@ -408,18 +414,81 @@ macro_rules! forward_call { } } ); - ( + // No function body => forward the call automatically: + (@item + #[forward_for = $name:ident] + $( #[$attr:meta] )* + $pub:vis + $(unsafe $(@ $unsafe:tt)?)? + fn $fname:ident ( + &$self_:ident $(,)? $( $arg_name:ident : $ArgTy:ty ),* $(,)? + ) -> $RetTy:ty; + ) => { + $( #[$attr] )* + #[allow(unused_parens)] + $pub + $(unsafe $($unsafe)?)? + fn $fname ( + &$self_, $( $arg_name : $ArgTy ),* + ) -> $RetTy + { + unsafe { + $name!( + $self_, + |v| (*v).$fname( $( + ForwardArg::forward($arg_name) + ),*) + ) + } + } + }; + // Manual body implementation: + (@item + #[forward_for = $name:ident] $( #[$attr:meta] )* + $pub:vis + $(unsafe $(@ $unsafe:tt)?)? + fn $fname:ident ( + &$self_:ident $(,)? $( $arg_name:ident : $ArgTy:ty ),* $(,)? + ) -> $RetTy:ty { + $($body:tt)* + } + ) => { + $( #[$attr] )* + #[allow(unused_parens)] + $pub + $(unsafe $($unsafe)?)? + fn $fname ( + &$self_, $( $arg_name : $ArgTy ),* + ) -> $RetTy + { $($body)* } + }; + ( + $( #[$attr_impl:meta] )* impl $name:ident { - $($item:item)* + $( + $( #[$($attr_item:tt)*] )* + $pub:vis + $(unsafe $(@ $unsafe:tt)?)? + fn $fname:ident $params:tt -> $RetTy:ty $({ + $($body:tt)* + })? + $(; $(<= $semi:tt)?)? + )* } ) => { - $(#[$attr])* + $(#[$attr_impl])* impl $name { $( - #[apply(forward_call)] - #[forward_for = $name] - $item + forward_call! {@item + #[forward_for = $name] + $(#[$($attr_item)*])* + $pub + $(unsafe $($unsafe)?)? + fn $fname $params -> $RetTy + $({ $($body)* })? + $(; $($semi)?)? + } )* } }; @@ -430,141 +499,96 @@ support_interface!(as IApplicationViewInner for IApplicationView in all [build_1 #[derive(Debug, Clone, PartialEq, Eq)] #[repr(transparent)] pub struct IApplicationView(IUnknown); +#[apply(forward_call)] impl IApplicationView { /* IInspecateble */ - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn get_iids( &self, out_iid_count: *mut ULONG, out_opt_iid_array_ptr: *mut *mut GUID, ) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn get_runtime_class_name(&self, out_opt_class_name: *mut HSTRING) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] + pub unsafe fn get_runtime_class_name( + &self, + out_opt_class_name: *mut HSTRING, + ) -> HRESULT; pub unsafe fn get_trust_level(&self, ptr_trust_level: LPVOID) -> HRESULT; /* IApplicationView methods */ - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn set_focus(&self) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn switch_to(&self) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn try_invoke_back(&self, ptr_async_callback: IAsyncCallback) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn get_thumbnail_window(&self, out_hwnd: *mut HWND) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn get_monitor(&self, out_monitors: *mut *mut IImmersiveMonitor) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn get_visibility(&self, out_int: LPVOID) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn set_cloak( &self, application_view_cloak_type: APPLICATION_VIEW_CLOAK_TYPE, unknown: INT, ) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn get_position( &self, unknowniid: *const GUID, unknown_array_ptr: LPVOID, ) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn set_position(&self, view_position: *mut IApplicationViewPosition) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] + pub unsafe fn set_position( + &self, + view_position: *mut IApplicationViewPosition, + ) -> HRESULT; pub unsafe fn insert_after_window(&self, window: HWND) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn get_extended_frame_position(&self, rect: *mut RECT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn get_app_user_model_id(&self, id: *mut PWSTR) -> HRESULT; // Proc17 - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn set_app_user_model_id(&self, id: PCWSTR) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn is_equal_by_app_user_model_id(&self, id: PCWSTR, out_result: *mut INT) - -> HRESULT; + pub unsafe fn is_equal_by_app_user_model_id( + &self, + id: PCWSTR, + out_result: *mut INT, + ) -> HRESULT; /*** IApplicationView methods ***/ - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn get_view_state(&self, out_state: *mut UINT) -> HRESULT; // Proc20 - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn set_view_state(&self, state: UINT) -> HRESULT; // Proc21 - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn get_neediness(&self, out_neediness: *mut INT) -> HRESULT; // Proc22 - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn get_last_activation_timestamp(&self, out_timestamp: *mut ULONGLONG) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] + pub unsafe fn get_last_activation_timestamp( + &self, + out_timestamp: *mut ULONGLONG, + ) -> HRESULT; pub unsafe fn set_last_activation_timestamp(&self, timestamp: ULONGLONG) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn get_virtual_desktop_id(&self, out_desktop_guid: *mut GUID) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn set_virtual_desktop_id(&self, desktop_guid: *const GUID) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn get_show_in_switchers(&self, out_show: *mut INT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn set_show_in_switchers(&self, show: INT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn get_scale_factor(&self, out_scale_factor: *mut INT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn can_receive_input(&self, out_can: *mut BOOL) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn get_compatibility_policy_type( &self, out_policy_type: *mut APPLICATION_VIEW_COMPATIBILITY_POLICY, ) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn set_compatibility_policy_type( &self, policy_type: APPLICATION_VIEW_COMPATIBILITY_POLICY, ) -> HRESULT; + pub unsafe fn get_position_priority( + &self, + out_priority: *mut IShellPositionerPriority, + ) -> HRESULT; + pub unsafe fn set_position_priority( + &self, + priority: IShellPositionerPriority, + ) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn get_size_constraints( &self, monitor: *mut IImmersiveMonitor, out_size1: *mut SIZE, out_size2: *mut SIZE, ) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn get_size_constraints_for_dpi( &self, dpi: UINT, out_size1: *mut SIZE, out_size2: *mut SIZE, ) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn set_size_constraints_for_dpi( &self, dpi: *const UINT, @@ -572,76 +596,36 @@ impl IApplicationView { size2: *const SIZE, ) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] + pub unsafe fn query_size_constraints_from_app(&self) -> HRESULT; pub unsafe fn on_min_size_preferences_updated(&self, window: HWND) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] - pub unsafe fn apply_operation(&self, operation: *mut IApplicationViewOperation) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] + pub unsafe fn apply_operation( + &self, + operation: *mut IApplicationViewOperation, + ) -> HRESULT; pub unsafe fn is_tray(&self, out_is: *mut BOOL) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn is_in_high_zorder_band(&self, out_is: *mut BOOL) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn is_splash_screen_presented(&self, out_is: *mut BOOL) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn flash(&self) -> HRESULT; - pub unsafe fn get_root_switchable_owner(&self, app_view: *mut IApplicationView) -> HRESULT { - // proc45 - IApplicationView!(self, |inner| inner - .get_root_switchable_owner(app_view as *mut _)) - } - - #[apply(forward_call)] - #[forward_for = IApplicationView] + pub unsafe fn get_root_switchable_owner( + &self, + app_view: *mut IApplicationView, + ) -> HRESULT; // proc45 pub unsafe fn enumerate_ownership_tree(&self, objects: *mut IObjectArray) -> HRESULT; // proc46 - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn get_enterprise_id(&self, out_id: *mut PWSTR) -> HRESULT; // proc47 - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn is_mirrored(&self, out_is: *mut BOOL) -> HRESULT; // - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn unknown1(&self, arg: *mut INT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn unknown2(&self, arg: *mut INT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn unknown3(&self, arg: *mut INT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn unknown4(&self, arg: INT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn unknown5(&self, arg: *mut INT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn unknown6(&self, arg: INT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn unknown7(&self) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn unknown8(&self, arg: *mut INT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn unknown9(&self, arg: INT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn unknown10(&self, arg: INT, arg2: INT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn unknown11(&self, arg: INT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationView] pub unsafe fn unknown12(&self, arg: *mut SIZE) -> HRESULT; } @@ -650,16 +634,13 @@ support_interface!(as IVirtualDesktopInner for IVirtualDesktop in [build_10240, #[derive(Debug, Clone, PartialEq, Eq)] #[repr(transparent)] pub struct IVirtualDesktop(IUnknown); +#[apply(forward_call)] impl IVirtualDesktop { - #[apply(forward_call)] - #[forward_for = IVirtualDesktop] pub unsafe fn is_view_visible( &self, p_view: ComIn, out_bool: *mut u32, ) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IVirtualDesktop] pub unsafe fn get_id(&self, out_guid: *mut GUID) -> HRESULT; pub unsafe fn get_name(&self, out_string: *mut HSTRING) -> HRESULT { @@ -681,17 +662,12 @@ support_interface!(as IApplicationViewCollectionInner for IApplicationViewCollec #[derive(Debug, Clone, PartialEq, Eq)] #[repr(transparent)] pub struct IApplicationViewCollection(IUnknown); +#[apply(forward_call)] impl IApplicationViewCollection { - #[apply(forward_call)] - #[forward_for = IApplicationViewCollection] pub unsafe fn get_views(&self, out_views: *mut IObjectArray) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationViewCollection] pub unsafe fn get_views_by_zorder(&self, out_views: *mut IObjectArray) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IApplicationViewCollection] pub unsafe fn get_views_by_app_user_model_id( &self, id: PCWSTR, @@ -732,8 +708,6 @@ impl IApplicationViewCollection { } } - #[apply(forward_call)] - #[forward_for = IApplicationViewCollection] pub unsafe fn refresh_collection(&self) -> HRESULT; pub unsafe fn register_for_application_view_changes( @@ -747,8 +721,6 @@ impl IApplicationViewCollection { } } - #[apply(forward_call)] - #[forward_for = IApplicationViewCollection] pub unsafe fn unregister_for_application_view_changes(&self, id: DWORD) -> HRESULT; } impl IApplicationViewCollection { @@ -850,17 +822,13 @@ support_interface!(as IVirtualDesktopNotificationServiceInner for IVirtualDeskto #[repr(transparent)] pub struct IVirtualDesktopNotificationService(IUnknown); +#[apply(forward_call)] impl IVirtualDesktopNotificationService { - #[apply(forward_call)] - #[forward_for = IVirtualDesktopNotificationService] pub unsafe fn register( &self, notification: *mut std::ffi::c_void, out_cookie: *mut DWORD, ) -> HRESULT; - - #[apply(forward_call)] - #[forward_for = IVirtualDesktopNotificationService] pub unsafe fn unregister(&self, cookie: u32) -> HRESULT; } impl IVirtualDesktopNotificationService { @@ -885,13 +853,10 @@ support_interface!(as IVirtualDesktopManagerInternalInner for IVirtualDesktopMan #[derive(Debug, Clone, PartialEq, Eq)] #[repr(transparent)] pub struct IVirtualDesktopManagerInternal(IUnknown); +#[apply(forward_call)] impl IVirtualDesktopManagerInternal { - #[apply(forward_call)] - #[forward_for = IVirtualDesktopManagerInternal] pub unsafe fn get_desktop_count(&self, out_count: *mut UINT) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IVirtualDesktopManagerInternal] pub unsafe fn move_view_to_desktop( &self, view: ComIn, @@ -901,7 +866,7 @@ impl IVirtualDesktopManagerInternal { pub unsafe fn can_move_view_between_desktops( &self, view: ComIn, - can_move: &mut i32, + can_move: *mut i32, ) -> HRESULT { unsafe { IVirtualDesktopManagerInternal!(self, |i| i @@ -909,16 +874,10 @@ impl IVirtualDesktopManagerInternal { } } - #[apply(forward_call)] - #[forward_for = IVirtualDesktopManagerInternal] pub unsafe fn get_current_desktop(&self, out_desktop: *mut Option) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IVirtualDesktopManagerInternal] pub unsafe fn get_desktops(&self, out_desktops: *mut Option) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IVirtualDesktopManagerInternal] /// Get next or previous desktop /// /// Direction values: @@ -931,12 +890,8 @@ impl IVirtualDesktopManagerInternal { out_pp_desktop: *mut Option, ) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IVirtualDesktopManagerInternal] pub unsafe fn switch_desktop(&self, desktop: ComIn) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IVirtualDesktopManagerInternal] pub unsafe fn create_desktop(&self, out_desktop: *mut Option) -> HRESULT; pub unsafe fn move_desktop(&self, in_desktop: ComIn, index: UINT) -> HRESULT { @@ -948,8 +903,6 @@ impl IVirtualDesktopManagerInternal { } } - #[apply(forward_call)] - #[forward_for = IVirtualDesktopManagerInternal] pub unsafe fn remove_desktop( &self, destroy_desktop: ComIn, @@ -1033,15 +986,10 @@ support_interface!(as IVirtualDesktopPinnedAppsInner for IVirtualDesktopPinnedAp #[repr(transparent)] pub struct IVirtualDesktopPinnedApps(IUnknown); +#[apply(forward_call)] impl IVirtualDesktopPinnedApps { - #[apply(forward_call)] - #[forward_for = IVirtualDesktopPinnedApps] pub unsafe fn is_app_pinned(&self, app_id: PCWSTR, out_iss: *mut bool) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IVirtualDesktopPinnedApps] pub unsafe fn pin_app(&self, app_id: PCWSTR) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IVirtualDesktopPinnedApps] pub unsafe fn unpin_app(&self, app_id: PCWSTR) -> HRESULT; pub unsafe fn is_view_pinned( @@ -1053,11 +1001,7 @@ impl IVirtualDesktopPinnedApps { IVirtualDesktopPinnedApps!(self, |inner| inner.is_view_pinned(view.into(), out_iss)) } } - #[apply(forward_call)] - #[forward_for = IVirtualDesktopPinnedApps] pub unsafe fn pin_view(&self, view: ComIn) -> HRESULT; - #[apply(forward_call)] - #[forward_for = IVirtualDesktopPinnedApps] pub unsafe fn unpin_view(&self, view: ComIn) -> HRESULT; } impl IVirtualDesktopPinnedApps { From f19fd5084221d23ebe3a366fe968eb03b10d0412 Mon Sep 17 00:00:00 2001 From: Lej77 <31554212+Lej77@users.noreply.github.com> Date: Tue, 2 Apr 2024 17:23:48 +0200 Subject: [PATCH 07/11] feat: support same Windows versions as github.com/mzomparelli/VirtualDesktop --- dll/Cargo.toml | 3 + dll/src/lib.rs | 2 +- src/interfaces_multi.rs | 17 +- src/interfaces_multi/build_10240.rs | 137 +++--- src/interfaces_multi/build_16299.rs | 10 + src/interfaces_multi/build_17134.rs | 10 + src/interfaces_multi/build_19045.rs | 10 + src/interfaces_multi/build_20348.rs | 269 +++++++++++ src/interfaces_multi/build_22000.rs | 327 +++++++------ src/interfaces_multi/build_22621_2215.rs | 331 +++++++++++++ src/interfaces_multi/build_22621_3155.rs | 10 + src/interfaces_multi/build_22631_2428.rs | 10 + src/interfaces_multi/build_22631_3155.rs | 10 + src/interfaces_multi/build_dyn.rs | 584 ++++++++++++++++------- src/lib.rs | 8 + src/listener.rs | 8 - 16 files changed, 1333 insertions(+), 413 deletions(-) create mode 100644 src/interfaces_multi/build_16299.rs create mode 100644 src/interfaces_multi/build_17134.rs create mode 100644 src/interfaces_multi/build_19045.rs create mode 100644 src/interfaces_multi/build_20348.rs create mode 100644 src/interfaces_multi/build_22621_2215.rs create mode 100644 src/interfaces_multi/build_22621_3155.rs create mode 100644 src/interfaces_multi/build_22631_2428.rs create mode 100644 src/interfaces_multi/build_22631_3155.rs diff --git a/dll/Cargo.toml b/dll/Cargo.toml index ab8d7ac..96a717d 100644 --- a/dll/Cargo.toml +++ b/dll/Cargo.toml @@ -26,3 +26,6 @@ windows = { version = "0.52", features = [ "Win32_UI_Shell_Common", # for IObjectArray "Win32_Foundation", ] } + +[features] +multiple-windows-versions = ["winvd/multiple-windows-versions"] diff --git a/dll/src/lib.rs b/dll/src/lib.rs index 07f5483..b353bfc 100644 --- a/dll/src/lib.rs +++ b/dll/src/lib.rs @@ -1,4 +1,4 @@ -#![allow(non_snake_case)] +#![allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)] use once_cell::sync::Lazy; use std::{ diff --git a/src/interfaces_multi.rs b/src/interfaces_multi.rs index 4f41730..fea70b6 100644 --- a/src/interfaces_multi.rs +++ b/src/interfaces_multi.rs @@ -15,7 +15,6 @@ //! - These are actually compiled when the app is executed by the `ComInterfaceAssemblyBuilder.CreateAssembly` method at: [VirtualDesktop/src/VirtualDesktop/Interop/ComInterfaceAssemblyBuilder.cs at 7e37b9848aef681713224dae558d2e51960cf41e · mzomparelli/VirtualDesktop](https://github.com/mzomparelli/VirtualDesktop/blob/7e37b9848aef681713224dae558d2e51960cf41e/src/VirtualDesktop/Interop/ComInterfaceAssemblyBuilder.cs#L84-L153) //! - Bindings at [MScholtes/VirtualDesktop at 6de804dced760778450ae3cd1481f8969f75fb39](https://github.com/MScholtes/VirtualDesktop/tree/6de804dced760778450ae3cd1481f8969f75fb39) - #![allow(non_upper_case_globals, clippy::upper_case_acronyms)] use std::ffi::c_void; @@ -29,7 +28,7 @@ use windows::{ macro_rules! declare_versions { (@inner { dollar = {$dollar:tt}, - versions = {$($version:ident),* $(,)?}, + versions = {$($version:tt),* $(,)?}, }) => { macro_rules! _with_versions { ($dollar macro_callback:path $dollar (, $dollar ( $dollar state:tt )* )?) => { @@ -44,7 +43,7 @@ macro_rules! declare_versions { }; ($( $(#[ $($attr:tt)* ])* - mod $version:ident $({ $($code:tt)* })? $(; $(<= $semi:tt)?)? + mod $version:tt $({ $($code:tt)* })? $(; $(<= $semi:tt)?)? )*) => { $( $(#[ $($attr)* ])* @@ -58,7 +57,15 @@ macro_rules! declare_versions { } declare_versions!( mod build_10240; - mod build_22000; + mod build_16299; // IDD change + mod build_17134; // IDD change + mod build_19045; // IDD change + mod build_20348; // Interface change + mod build_22000; // Interface change + mod build_22621_2215; // Interface change + mod build_22621_3155; // IID change + mod build_22631_2428; // IID change + mod build_22631_3155; ); mod build_dyn; @@ -126,7 +133,6 @@ macro_rules! _reusable_com_interface { // Allow normal imports to work for macro: use _reusable_com_interface as reusable_com_interface; - /// Type that can be cast into [`ComIn`] /// /// # Safety @@ -236,6 +242,7 @@ type PCWSTR = *const WCHAR; type PWSTR = *mut WCHAR; type ULONGLONG = u64; type LONG = i32; +type HMONITOR = isize; type IAsyncCallback = UINT; type IImmersiveMonitor = UINT; diff --git a/src/interfaces_multi/build_10240.rs b/src/interfaces_multi/build_10240.rs index e108eb4..f012935 100644 --- a/src/interfaces_multi/build_10240.rs +++ b/src/interfaces_multi/build_10240.rs @@ -1,12 +1,13 @@ //! Support for Windows 10. //! -//! These definitions should be valid from Windows version `10240` (inclusive) to `22000` (exclusive). +//! The [`IVirtualDesktopNotification`] and [`IVirtualDesktopManagerInternal`] +//! interfaces do not take "monitor" arguments. use super::*; reusable_com_interface!( MacroOptions { temp_macro_name: _IApplicationView, - iid: "871F602A-2B58-42B4-8C4B-6C43D642C06F", + iid: "9AC0B5C8-1484-4C5B-9533-4134A0F97CEA", }, { pub unsafe trait IApplicationView: IUnknown { @@ -143,7 +144,7 @@ reusable_com_interface!( reusable_com_interface!( MacroOptions { temp_macro_name: _IApplicationViewCollection, - iid: "1841C6D7-4F9D-42C0-AF41-8747538F10E5", + iid: "2C08ADF0-A386-4B35-9250-0FE183476FCC", }, { pub unsafe trait IApplicationViewCollection: IUnknown { @@ -213,6 +214,68 @@ reusable_com_interface!( } ); +reusable_com_interface!( + MacroOptions { + temp_macro_name: _IVirtualDesktopManagerInternal, + iid: "F31574D6-B682-4CDC-BD56-1827860ABEC6", + }, + { + pub unsafe trait IVirtualDesktopManagerInternal: IUnknown { + pub unsafe fn get_desktop_count(&self, out_count: *mut UINT) -> HRESULT; + + pub unsafe fn move_view_to_desktop( + &self, + view: ComIn, + desktop: ComIn, + ) -> HRESULT; + + pub unsafe fn can_move_view_between_desktops( + &self, + view: ComIn, + can_move: *mut i32, + ) -> HRESULT; + + pub unsafe fn get_current_desktop( + &self, + out_desktop: *mut Option, + ) -> HRESULT; + + pub unsafe fn get_desktops(&self, out_desktops: *mut Option) -> HRESULT; + + /// Get next or previous desktop + /// + /// Direction values: + /// 3 = Left direction + /// 4 = Right direction + pub unsafe fn get_adjacent_desktop( + &self, + in_desktop: ComIn, + direction: UINT, + out_pp_desktop: *mut Option, + ) -> HRESULT; + + pub unsafe fn switch_desktop(&self, desktop: ComIn) -> HRESULT; + + pub unsafe fn create_desktop( + &self, + out_desktop: *mut Option, + ) -> HRESULT; + + pub unsafe fn remove_desktop( + &self, + destroy_desktop: ComIn, + fallback_desktop: ComIn, + ) -> HRESULT; + + pub unsafe fn find_desktop( + &self, + guid: *const GUID, + out_desktop: *mut Option, + ) -> HRESULT; + } + } +); + reusable_com_interface!( MacroOptions { temp_macro_name: _IVirtualDesktopNotification, @@ -308,10 +371,8 @@ reusable_com_interface!( desktop_destroyed: ComIn, desktop_fallback: ComIn, ) -> HRESULT { - self.inner.virtual_desktop_destroyed( - desktop_destroyed.into(), - desktop_fallback.into(), - ) + self.inner + .virtual_desktop_destroyed(desktop_destroyed.into(), desktop_fallback.into()) } unsafe fn view_virtual_desktop_changed( @@ -342,68 +403,6 @@ reusable_com_interface!( } ); -reusable_com_interface!( - MacroOptions { - temp_macro_name: _IVirtualDesktopManagerInternal, - iid: "0F3A72B0-4566-487E-9A33-4ED302F6D6CE", - }, - { - pub unsafe trait IVirtualDesktopManagerInternal: IUnknown { - pub unsafe fn get_desktop_count(&self, out_count: *mut UINT) -> HRESULT; - - pub unsafe fn move_view_to_desktop( - &self, - view: ComIn, - desktop: ComIn, - ) -> HRESULT; - - pub unsafe fn can_move_view_between_desktops( - &self, - view: ComIn, - can_move: *mut i32, - ) -> HRESULT; - - pub unsafe fn get_current_desktop( - &self, - out_desktop: *mut Option, - ) -> HRESULT; - - pub unsafe fn get_desktops(&self, out_desktops: *mut Option) -> HRESULT; - - /// Get next or previous desktop - /// - /// Direction values: - /// 3 = Left direction - /// 4 = Right direction - pub unsafe fn get_adjacent_desktop( - &self, - in_desktop: ComIn, - direction: UINT, - out_pp_desktop: *mut Option, - ) -> HRESULT; - - pub unsafe fn switch_desktop(&self, desktop: ComIn) -> HRESULT; - - pub unsafe fn create_desktop( - &self, - out_desktop: *mut Option, - ) -> HRESULT; - - pub unsafe fn remove_desktop( - &self, - destroy_desktop: ComIn, - fallback_desktop: ComIn, - ) -> HRESULT; - - pub unsafe fn find_desktop( - &self, - guid: *const GUID, - out_desktop: *mut Option, - ) -> HRESULT; - } - } -); - reusable_com_interface!( MacroOptions { temp_macro_name: _IVirtualDesktopPinnedApps, diff --git a/src/interfaces_multi/build_16299.rs b/src/interfaces_multi/build_16299.rs new file mode 100644 index 0000000..3a4c645 --- /dev/null +++ b/src/interfaces_multi/build_16299.rs @@ -0,0 +1,10 @@ +use super::*; +use build_10240 as prev_build; + +prev_build::IApplicationView!("9AC0B5C8-1484-4C5B-9533-4134A0F97CEA"); +prev_build::IApplicationViewCollection!("2C08ADF0-A386-4B35-9250-0FE183476FCC"); +prev_build::IVirtualDesktop!("FF72FFDD-BE7E-43FC-9C03-AD81681E88E4"); +prev_build::IVirtualDesktopManagerInternal!("F31574D6-B682-4CDC-BD56-1827860ABEC6"); +prev_build::IVirtualDesktopNotification!("C179334C-4295-40D3-BEA1-C654D965605A"); +prev_build::IVirtualDesktopNotificationService!("0CD45E71-D927-4F15-8B0A-8FEF525337BF"); +prev_build::IVirtualDesktopPinnedApps!("4CE81583-1E4C-4632-A621-07A53543148F"); diff --git a/src/interfaces_multi/build_17134.rs b/src/interfaces_multi/build_17134.rs new file mode 100644 index 0000000..3943cab --- /dev/null +++ b/src/interfaces_multi/build_17134.rs @@ -0,0 +1,10 @@ +use super::*; +use build_10240 as prev_build; + +prev_build::IApplicationView!("871F602A-2B58-42B4-8C4B-6C43D642C06F"); +prev_build::IApplicationViewCollection!("2C08ADF0-A386-4B35-9250-0FE183476FCC"); +prev_build::IVirtualDesktop!("FF72FFDD-BE7E-43FC-9C03-AD81681E88E4"); +prev_build::IVirtualDesktopManagerInternal!("F31574D6-B682-4CDC-BD56-1827860ABEC6"); +prev_build::IVirtualDesktopNotification!("C179334C-4295-40D3-BEA1-C654D965605A"); +prev_build::IVirtualDesktopNotificationService!("0CD45E71-D927-4F15-8B0A-8FEF525337BF"); +prev_build::IVirtualDesktopPinnedApps!("4CE81583-1E4C-4632-A621-07A53543148F"); diff --git a/src/interfaces_multi/build_19045.rs b/src/interfaces_multi/build_19045.rs new file mode 100644 index 0000000..36f6bd3 --- /dev/null +++ b/src/interfaces_multi/build_19045.rs @@ -0,0 +1,10 @@ +use super::*; +use build_10240 as prev_build; + +prev_build::IApplicationView!("372E1D3B-38D3-42E4-A15B-8AB2B178F513"); +prev_build::IApplicationViewCollection!("1841C6D7-4F9D-42C0-AF41-8747538F10E5"); +prev_build::IVirtualDesktop!("FF72FFDD-BE7E-43FC-9C03-AD81681E88E4"); +prev_build::IVirtualDesktopManagerInternal!("F31574D6-B682-4CDC-BD56-1827860ABEC6"); +prev_build::IVirtualDesktopNotification!("C179334C-4295-40D3-BEA1-C654D965605A"); +prev_build::IVirtualDesktopNotificationService!("0CD45E71-D927-4F15-8B0A-8FEF525337BF"); +prev_build::IVirtualDesktopPinnedApps!("4CE81583-1E4C-4632-A621-07A53543148F"); diff --git a/src/interfaces_multi/build_20348.rs b/src/interfaces_multi/build_20348.rs new file mode 100644 index 0000000..2fc8871 --- /dev/null +++ b/src/interfaces_multi/build_20348.rs @@ -0,0 +1,269 @@ +//! New for this version is that the [`IVirtualDesktopManagerInternal`] +//! interfaces take "monitor" arguments, note that the The +//! [`IVirtualDesktopNotification`] interface still doesn't use monitors. +use super::*; +use build_10240 as prev_build; + +// These interfaces haven't changed since previous version: +prev_build::IApplicationView!("372E1D3B-38D3-42E4-A15B-8AB2B178F513"); +prev_build::IApplicationViewCollection!("1841C6D7-4F9D-42C0-AF41-8747538F10E5"); +prev_build::IVirtualDesktopNotificationService!("0cd45e71-d927-4f15-8b0a-8fef525337bf"); +prev_build::IVirtualDesktopPinnedApps!("4CE81583-1E4C-4632-A621-07A53543148F"); + +// But these interfaces have different methods: + +reusable_com_interface!( + MacroOptions { + temp_macro_name: _IVirtualDesktop, + iid: "62FDF88B-11CA-4AFB-8BD8-2296DFAE49E2", + }, + { + pub unsafe trait IVirtualDesktop: IUnknown { + pub unsafe fn is_view_visible( + &self, + p_view: ComIn, + out_bool: *mut u32, + ) -> HRESULT; + pub unsafe fn get_id(&self, out_guid: *mut GUID) -> HRESULT; + + // These methods are new: + + pub unsafe fn get_monitor( + &self, + monitor: HMONITOR, + out_monitor: *mut HMONITOR, + ) -> HRESULT; + pub unsafe fn get_name(&self, out_string: *mut HSTRING) -> HRESULT; + } + } +); + +reusable_com_interface!( + MacroOptions { + temp_macro_name: _IVirtualDesktopManagerInternal, + iid: "094AFE11-44F2-4BA0-976F-29A97E263EE0", + }, + { + pub unsafe trait IVirtualDesktopManagerInternal: IUnknown { + pub unsafe fn get_desktop_count( + &self, + monitor: HMONITOR, + out_count: *mut UINT, + ) -> HRESULT; + + pub unsafe fn move_view_to_desktop( + &self, + view: ComIn, + desktop: ComIn, + ) -> HRESULT; + + pub unsafe fn can_move_view_between_desktops( + &self, + view: ComIn, + can_move: *mut i32, + ) -> HRESULT; + + pub unsafe fn get_current_desktop( + &self, + monitor: HMONITOR, + out_desktop: *mut Option, + ) -> HRESULT; + + pub unsafe fn get_desktops( + &self, + monitor: HMONITOR, + out_desktops: *mut Option, + ) -> HRESULT; + + /// Get next or previous desktop + /// + /// Direction values: + /// 3 = Left direction + /// 4 = Right direction + pub unsafe fn get_adjacent_desktop( + &self, + in_desktop: ComIn, + direction: UINT, + out_pp_desktop: *mut Option, + ) -> HRESULT; + + pub unsafe fn switch_desktop( + &self, + monitor: HMONITOR, + desktop: ComIn, + ) -> HRESULT; + + pub unsafe fn create_desktop( + &self, + monitor: HMONITOR, + out_desktop: *mut Option, + ) -> HRESULT; + + pub unsafe fn remove_desktop( + &self, + destroy_desktop: ComIn, + fallback_desktop: ComIn, + ) -> HRESULT; + + pub unsafe fn find_desktop( + &self, + guid: *const GUID, + out_desktop: *mut Option, + ) -> HRESULT; + + // These methods are new: + + pub unsafe fn get_desktop_switch_include_exclude_views( + &self, + desktop: ComIn, + out_pp_desktops1: *mut IObjectArray, + out_pp_desktops2: *mut IObjectArray, + ) -> HRESULT; + + pub unsafe fn set_name( + &self, + desktop: ComIn, + name: HSTRING, + ) -> HRESULT; + + pub unsafe fn copy_desktop_state( + &self, + view0: ComIn, + view1: ComIn, + ) -> HRESULT; + + pub unsafe fn get_desktop_is_per_monitor(&self, out_per_monitor: *mut i32) -> HRESULT; + } + } +); + +reusable_com_interface!( + MacroOptions { + temp_macro_name: _IVirtualDesktopNotification, + iid: "f3163e11-6b04-433c-a64b-6f82c9094257", + }, + { + pub unsafe trait IVirtualDesktopNotification: IUnknown { + pub unsafe fn virtual_desktop_created( + &self, + desktop: ComIn, + ) -> HRESULT; + + pub unsafe fn virtual_desktop_destroy_begin( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT; + + pub unsafe fn virtual_desktop_destroy_failed( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT; + + pub unsafe fn virtual_desktop_destroyed( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT; + + // This method is new: + pub unsafe fn virtual_desktop_is_per_monitor_changed(&self, i: i64) -> HRESULT; + + pub unsafe fn virtual_desktop_name_changed( + &self, + desktop: ComIn, + name: HSTRING, + ) -> HRESULT; + + pub unsafe fn view_virtual_desktop_changed( + &self, + view: ComIn, + ) -> HRESULT; + + pub unsafe fn current_virtual_desktop_changed( + &self, + desktop_old: ComIn, + desktop_new: ComIn, + ) -> HRESULT; + } + + /// Implements an unstable interface that is only valid for a single Windows + /// version using a more stable trait that works for all Windows versions. + #[windows::core::implement(IVirtualDesktopNotification)] + pub struct VirtualDesktopNotificationAdaptor + where + T: build_dyn::IVirtualDesktopNotification_Impl, + { + pub inner: T, + } + impl IVirtualDesktopNotification_Impl for VirtualDesktopNotificationAdaptor + where + T: build_dyn::IVirtualDesktopNotification_Impl, + { + unsafe fn virtual_desktop_created(&self, desktop: ComIn) -> HRESULT { + self.inner.virtual_desktop_created(desktop.into()) + } + + unsafe fn virtual_desktop_destroy_begin( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT { + self.inner.virtual_desktop_destroy_begin( + desktop_destroyed.into(), + desktop_fallback.into(), + ) + } + + unsafe fn virtual_desktop_destroy_failed( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT { + self.inner.virtual_desktop_destroy_failed( + desktop_destroyed.into(), + desktop_fallback.into(), + ) + } + + unsafe fn virtual_desktop_destroyed( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT { + self.inner + .virtual_desktop_destroyed(desktop_destroyed.into(), desktop_fallback.into()) + } + + unsafe fn virtual_desktop_is_per_monitor_changed(&self, _i: i64) -> HRESULT { + HRESULT(0) + } + + unsafe fn virtual_desktop_name_changed( + &self, + desktop: ComIn, + name: HSTRING, + ) -> HRESULT { + self.inner + .virtual_desktop_name_changed(desktop.into(), name) + } + + unsafe fn view_virtual_desktop_changed( + &self, + view: ComIn, + ) -> HRESULT { + self.inner.view_virtual_desktop_changed(view.into()) + } + + unsafe fn current_virtual_desktop_changed( + &self, + desktop_old: ComIn, + desktop_new: ComIn, + ) -> HRESULT { + self.inner + .current_virtual_desktop_changed(desktop_old.into(), desktop_new.into()) + } + } + } +); diff --git a/src/interfaces_multi/build_22000.rs b/src/interfaces_multi/build_22000.rs index 0967961..8495d1e 100644 --- a/src/interfaces_multi/build_22000.rs +++ b/src/interfaces_multi/build_22000.rs @@ -1,16 +1,22 @@ -//! Support for Windows 11. +//! New for this version is that the [`IVirtualDesktopNotification`] interface +//! takes "monitors" as arguments, previously only the +//! [`IVirtualDesktopManagerInternal`] interface used them. + use super::*; +use build_10240 as prev_build; // These interfaces haven't changed since previous version: -build_10240::IApplicationView!("372E1D3B-38D3-42E4-A15B-8AB2B178F513"); -build_10240::IApplicationViewCollection!("1841c6d7-4f9d-42c0-af41-8747538f10e5"); +prev_build::IApplicationView!("372E1D3B-38D3-42E4-A15B-8AB2B178F513"); +prev_build::IApplicationViewCollection!("1841C6D7-4F9D-42C0-AF41-8747538F10E5"); +prev_build::IVirtualDesktopNotificationService!("0cd45e71-d927-4f15-8b0a-8fef525337bf"); +prev_build::IVirtualDesktopPinnedApps!("4CE81583-1E4C-4632-A621-07A53543148F"); // But these interfaces have different methods: reusable_com_interface!( MacroOptions { temp_macro_name: _IVirtualDesktop, - iid: "3F07F4BE-B107-441A-AF0F-39D82529072C", + iid: "536D3495-B208-4CC9-AE26-DE8111275BF8", }, { pub unsafe trait IVirtualDesktop: IUnknown { @@ -20,46 +26,174 @@ reusable_com_interface!( out_bool: *mut u32, ) -> HRESULT; pub unsafe fn get_id(&self, out_guid: *mut GUID) -> HRESULT; + pub unsafe fn get_monitor(&self, out_monitor: *mut HMONITOR) -> HRESULT; pub unsafe fn get_name(&self, out_string: *mut HSTRING) -> HRESULT; + // This method is new: pub unsafe fn get_wallpaper(&self, out_string: *mut HSTRING) -> HRESULT; } } ); +reusable_com_interface!( + MacroOptions { + temp_macro_name: _IVirtualDesktopManagerInternal, + iid: "B2F925B9-5A0F-4D2E-9F4D-2B1507593C10", + }, + { + pub unsafe trait IVirtualDesktopManagerInternal: IUnknown { + pub unsafe fn get_desktop_count( + &self, + monitor: HMONITOR, + out_count: *mut UINT, + ) -> HRESULT; + + pub unsafe fn move_view_to_desktop( + &self, + view: ComIn, + desktop: ComIn, + ) -> HRESULT; + + pub unsafe fn can_move_view_between_desktops( + &self, + view: ComIn, + can_move: *mut i32, + ) -> HRESULT; + + pub unsafe fn get_current_desktop( + &self, + monitor: HMONITOR, + out_desktop: *mut Option, + ) -> HRESULT; + + pub unsafe fn get_all_current_desktops( + &self, + out_desktops: *mut Option, + ) -> HRESULT; + + pub unsafe fn get_desktops( + &self, + monitor: HMONITOR, + out_desktops: *mut Option, + ) -> HRESULT; + + /// Get next or previous desktop + /// + /// Direction values: + /// 3 = Left direction + /// 4 = Right direction + pub unsafe fn get_adjacent_desktop( + &self, + in_desktop: ComIn, + direction: UINT, + out_pp_desktop: *mut Option, + ) -> HRESULT; + + pub unsafe fn switch_desktop( + &self, + monitor: HMONITOR, + desktop: ComIn, + ) -> HRESULT; + + pub unsafe fn create_desktop( + &self, + monitor: HMONITOR, + out_desktop: *mut Option, + ) -> HRESULT; + + pub unsafe fn move_desktop( + &self, + in_desktop: ComIn, + monitor: HMONITOR, + index: UINT, + ) -> HRESULT; + + pub unsafe fn remove_desktop( + &self, + destroy_desktop: ComIn, + fallback_desktop: ComIn, + ) -> HRESULT; + + pub unsafe fn find_desktop( + &self, + guid: *const GUID, + out_desktop: *mut Option, + ) -> HRESULT; + + pub unsafe fn get_desktop_switch_include_exclude_views( + &self, + desktop: ComIn, + out_pp_desktops1: *mut IObjectArray, + out_pp_desktops2: *mut IObjectArray, + ) -> HRESULT; + + pub unsafe fn set_name( + &self, + desktop: ComIn, + name: HSTRING, + ) -> HRESULT; + pub unsafe fn set_wallpaper( + &self, + desktop: ComIn, + name: HSTRING, + ) -> HRESULT; + pub unsafe fn update_wallpaper_for_all(&self, name: HSTRING) -> HRESULT; + + pub unsafe fn copy_desktop_state( + &self, + view0: ComIn, + view1: ComIn, + ) -> HRESULT; + + pub unsafe fn get_desktop_is_per_monitor(&self, out_per_monitor: *mut i32) -> HRESULT; + + pub unsafe fn set_desktop_is_per_monitor(&self, per_monitor: i32) -> HRESULT; + } + } +); + reusable_com_interface!( MacroOptions { temp_macro_name: _IVirtualDesktopNotification, - iid: "B9E5E94D-233E-49AB-AF5C-2B4541C3AADE", + iid: "cd403e52-deed-4c13-b437-b98380f2b1e8", }, { pub unsafe trait IVirtualDesktopNotification: IUnknown { pub unsafe fn virtual_desktop_created( &self, + monitors: ComIn, desktop: ComIn, ) -> HRESULT; pub unsafe fn virtual_desktop_destroy_begin( &self, + monitors: ComIn, desktop_destroyed: ComIn, desktop_fallback: ComIn, ) -> HRESULT; pub unsafe fn virtual_desktop_destroy_failed( &self, + monitors: ComIn, desktop_destroyed: ComIn, desktop_fallback: ComIn, ) -> HRESULT; pub unsafe fn virtual_desktop_destroyed( &self, + monitors: ComIn, desktop_destroyed: ComIn, desktop_fallback: ComIn, ) -> HRESULT; - pub unsafe fn proc7(&self) -> HRESULT; + pub unsafe fn virtual_desktop_is_per_monitor_changed( + &self, + is_per_monitor: i32, + ) -> HRESULT; + // This method is new: pub unsafe fn virtual_desktop_moved( &self, + monitors: ComIn, desktop: ComIn, old_index: i64, new_index: i64, @@ -78,10 +212,13 @@ reusable_com_interface!( pub unsafe fn current_virtual_desktop_changed( &self, + monitors: ComIn, desktop_old: ComIn, desktop_new: ComIn, ) -> HRESULT; + // These methods are new: + pub unsafe fn virtual_desktop_wallpaper_changed( &self, desktop: ComIn, @@ -112,30 +249,17 @@ reusable_com_interface!( where T: build_dyn::IVirtualDesktopNotification_Impl, { - unsafe fn current_virtual_desktop_changed( - &self, - desktop_old: ComIn, - desktop_new: ComIn, - ) -> HRESULT { - self.inner - .current_virtual_desktop_changed(desktop_old.into(), desktop_new.into()) - } - - unsafe fn virtual_desktop_wallpaper_changed( + unsafe fn virtual_desktop_created( &self, + _monitors: ComIn, desktop: ComIn, - name: HSTRING, ) -> HRESULT { - self.inner - .virtual_desktop_wallpaper_changed(desktop.into(), name) - } - - unsafe fn virtual_desktop_created(&self, desktop: ComIn) -> HRESULT { self.inner.virtual_desktop_created(desktop.into()) } unsafe fn virtual_desktop_destroy_begin( &self, + _monitors: ComIn, desktop_destroyed: ComIn, desktop_fallback: ComIn, ) -> HRESULT { @@ -147,6 +271,7 @@ reusable_com_interface!( unsafe fn virtual_desktop_destroy_failed( &self, + _monitors: ComIn, desktop_destroyed: ComIn, desktop_fallback: ComIn, ) -> HRESULT { @@ -158,21 +283,24 @@ reusable_com_interface!( unsafe fn virtual_desktop_destroyed( &self, + _monitors: ComIn, desktop_destroyed: ComIn, desktop_fallback: ComIn, ) -> HRESULT { - self.inner.virtual_desktop_destroyed( - desktop_destroyed.into(), - desktop_fallback.into(), - ) + self.inner + .virtual_desktop_destroyed(desktop_destroyed.into(), desktop_fallback.into()) } - unsafe fn proc7(&self) -> HRESULT { + unsafe fn virtual_desktop_is_per_monitor_changed( + &self, + _is_per_monitor: i32, + ) -> HRESULT { HRESULT(0) } unsafe fn virtual_desktop_moved( &self, + _monitors: ComIn, desktop: ComIn, old_index: i64, new_index: i64, @@ -197,144 +325,35 @@ reusable_com_interface!( self.inner.view_virtual_desktop_changed(view.into()) } - unsafe fn virtual_desktop_switched(&self, desktop: ComIn) -> HRESULT { - self.inner.virtual_desktop_switched(desktop.into()) - } - - unsafe fn remote_virtual_desktop_connected( + unsafe fn current_virtual_desktop_changed( &self, - desktop: ComIn, + _monitors: ComIn, + desktop_old: ComIn, + desktop_new: ComIn, ) -> HRESULT { self.inner - .remote_virtual_desktop_connected(desktop.into()) + .current_virtual_desktop_changed(desktop_old.into(), desktop_new.into()) } - } - } -); - -reusable_com_interface!( - MacroOptions { - temp_macro_name: _IVirtualDesktopNotificationService, - iid: "0CD45E71-D927-4F15-8B0A-8FEF525337BF", - }, - { - pub unsafe trait IVirtualDesktopNotificationService: IUnknown { - pub unsafe fn register( - &self, - notification: *mut std::ffi::c_void, // *const IVirtualDesktopNotification, - out_cookie: *mut DWORD, - ) -> HRESULT; - - pub unsafe fn unregister(&self, cookie: u32) -> HRESULT; - } - } -); - -reusable_com_interface!( - MacroOptions { - temp_macro_name: _IVirtualDesktopManagerInternal, - iid: "53F5CA0B-158F-4124-900C-057158060B27", - }, - { - pub unsafe trait IVirtualDesktopManagerInternal: IUnknown { - pub unsafe fn get_desktop_count(&self, out_count: *mut UINT) -> HRESULT; - - pub unsafe fn move_view_to_desktop( - &self, - view: ComIn, - desktop: ComIn, - ) -> HRESULT; - - pub unsafe fn can_move_view_between_desktops( - &self, - view: ComIn, - can_move: *mut i32, - ) -> HRESULT; - - pub unsafe fn get_current_desktop( - &self, - out_desktop: *mut Option, - ) -> HRESULT; - - pub unsafe fn get_desktops(&self, out_desktops: *mut Option) -> HRESULT; - - /// Get next or previous desktop - /// - /// Direction values: - /// 3 = Left direction - /// 4 = Right direction - pub unsafe fn get_adjacent_desktop( - &self, - in_desktop: ComIn, - direction: UINT, - out_pp_desktop: *mut Option, - ) -> HRESULT; - - pub unsafe fn switch_desktop(&self, desktop: ComIn) -> HRESULT; - - pub unsafe fn create_desktop( - &self, - out_desktop: *mut Option, - ) -> HRESULT; - - pub unsafe fn move_desktop( - &self, - in_desktop: ComIn, - index: UINT, - ) -> HRESULT; - pub unsafe fn remove_desktop( - &self, - destroy_desktop: ComIn, - fallback_desktop: ComIn, - ) -> HRESULT; - - pub unsafe fn find_desktop( - &self, - guid: *const GUID, - out_desktop: *mut Option, - ) -> HRESULT; - - pub unsafe fn get_desktop_switch_include_exclude_views( - &self, - desktop: ComIn, - out_pp_desktops1: *mut IObjectArray, - out_pp_desktops2: *mut IObjectArray, - ) -> HRESULT; - - pub unsafe fn set_name( - &self, - desktop: ComIn, - name: HSTRING, - ) -> HRESULT; - pub unsafe fn set_wallpaper( + unsafe fn virtual_desktop_wallpaper_changed( &self, desktop: ComIn, name: HSTRING, - ) -> HRESULT; - pub unsafe fn update_wallpaper_for_all(&self, name: HSTRING) -> HRESULT; - } - } -); + ) -> HRESULT { + self.inner + .virtual_desktop_wallpaper_changed(desktop.into(), name) + } -reusable_com_interface!( - MacroOptions { - temp_macro_name: _IVirtualDesktopPinnedApps, - iid: "4CE81583-1E4C-4632-A621-07A53543148F", - }, - { - pub unsafe trait IVirtualDesktopPinnedApps: IUnknown { - pub unsafe fn is_app_pinned(&self, app_id: PCWSTR, out_iss: *mut bool) -> HRESULT; - pub unsafe fn pin_app(&self, app_id: PCWSTR) -> HRESULT; - pub unsafe fn unpin_app(&self, app_id: PCWSTR) -> HRESULT; + unsafe fn virtual_desktop_switched(&self, desktop: ComIn) -> HRESULT { + self.inner.virtual_desktop_switched(desktop.into()) + } - pub unsafe fn is_view_pinned( + unsafe fn remote_virtual_desktop_connected( &self, - view: ComIn, - out_iss: *mut bool, - ) -> HRESULT; - pub unsafe fn pin_view(&self, view: ComIn) -> HRESULT; - pub unsafe fn unpin_view(&self, view: ComIn) -> HRESULT; + desktop: ComIn, + ) -> HRESULT { + self.inner.remote_virtual_desktop_connected(desktop.into()) + } } } ); diff --git a/src/interfaces_multi/build_22621_2215.rs b/src/interfaces_multi/build_22621_2215.rs new file mode 100644 index 0000000..a7b3565 --- /dev/null +++ b/src/interfaces_multi/build_22621_2215.rs @@ -0,0 +1,331 @@ +//! New for this version is that "monitor" arguments are no longer passed to the +//! [`IVirtualDesktopNotification`] and [`IVirtualDesktopManagerInternal`] +//! interfaces. +//! +//! # References +//! +//! - [New changes for 22621 · Ciantic/VirtualDesktopAccessor@c918946](https://github.com/Ciantic/VirtualDesktopAccessor/commit/c918946421c42a7f022abdf8b4672a4b3ddf2f35#diff-e073b55bb9e1746ee6b3a029ba955df76b3d61e774585c23535bd0b4967d9e18) +//! - +use super::*; + +// These interfaces haven't changed since previous version: +build_10240::IApplicationView!("372E1D3B-38D3-42E4-A15B-8AB2B178F513"); +build_10240::IApplicationViewCollection!("1841C6D7-4F9D-42C0-AF41-8747538F10E5"); +build_10240::IVirtualDesktopNotificationService!("0cd45e71-d927-4f15-8b0a-8fef525337bf"); +build_10240::IVirtualDesktopPinnedApps!("4CE81583-1E4C-4632-A621-07A53543148F"); + +// But these interfaces have different methods: + +reusable_com_interface!( + MacroOptions { + temp_macro_name: _IVirtualDesktop, + iid: "3F07F4BE-B107-441A-AF0F-39D82529072C", + }, + { + pub unsafe trait IVirtualDesktop: IUnknown { + pub unsafe fn is_view_visible( + &self, + p_view: ComIn, + out_bool: *mut u32, + ) -> HRESULT; + pub unsafe fn get_id(&self, out_guid: *mut GUID) -> HRESULT; + // get_monitor removed + pub unsafe fn get_name(&self, out_string: *mut HSTRING) -> HRESULT; + pub unsafe fn get_wallpaper(&self, out_string: *mut HSTRING) -> HRESULT; + // This method is new: + pub unsafe fn is_remote(&self, out_is_remote: *mut i32) -> HRESULT; + } + } +); + +reusable_com_interface!( + MacroOptions { + temp_macro_name: _IVirtualDesktopManagerInternal, + iid: "A3175F2D-239C-4BD2-8AA0-EEBA8B0B138E", + }, + { + pub unsafe trait IVirtualDesktopManagerInternal: IUnknown { + pub unsafe fn get_desktop_count(&self, out_count: *mut UINT) -> HRESULT; + + pub unsafe fn move_view_to_desktop( + &self, + view: ComIn, + desktop: ComIn, + ) -> HRESULT; + + pub unsafe fn can_move_view_between_desktops( + &self, + view: ComIn, + can_move: *mut i32, + ) -> HRESULT; + + pub unsafe fn get_current_desktop( + &self, + out_desktop: *mut Option, + ) -> HRESULT; + + pub unsafe fn get_desktops(&self, out_desktops: *mut Option) -> HRESULT; + + /// Get next or previous desktop + /// + /// Direction values: + /// 3 = Left direction + /// 4 = Right direction + pub unsafe fn get_adjacent_desktop( + &self, + in_desktop: ComIn, + direction: UINT, + out_pp_desktop: *mut Option, + ) -> HRESULT; + + pub unsafe fn switch_desktop(&self, desktop: ComIn) -> HRESULT; + + pub unsafe fn create_desktop( + &self, + out_desktop: *mut Option, + ) -> HRESULT; + + pub unsafe fn move_desktop( + &self, + in_desktop: ComIn, + index: UINT, + ) -> HRESULT; + + pub unsafe fn remove_desktop( + &self, + destroy_desktop: ComIn, + fallback_desktop: ComIn, + ) -> HRESULT; + + pub unsafe fn find_desktop( + &self, + guid: *const GUID, + out_desktop: *mut Option, + ) -> HRESULT; + + pub unsafe fn get_desktop_switch_include_exclude_views( + &self, + desktop: ComIn, + out_pp_desktops1: *mut IObjectArray, + out_pp_desktops2: *mut IObjectArray, + ) -> HRESULT; + + pub unsafe fn set_name( + &self, + desktop: ComIn, + name: HSTRING, + ) -> HRESULT; + pub unsafe fn set_wallpaper( + &self, + desktop: ComIn, + name: HSTRING, + ) -> HRESULT; + pub unsafe fn update_wallpaper_for_all(&self, name: HSTRING) -> HRESULT; + + pub unsafe fn copy_desktop_state( + &self, + view0: ComIn, + view1: ComIn, + ) -> HRESULT; + + // These methods are new: + + pub unsafe fn create_remote_desktop( + &self, + name: HSTRING, + out_desktop: *mut Option, + ) -> HRESULT; + + pub unsafe fn switch_remote_desktop(&self, desktop: ComIn) -> HRESULT; + + pub unsafe fn switch_desktop_with_animation( + &self, + desktop: ComIn, + ) -> HRESULT; + + pub unsafe fn get_last_active_desktop( + &self, + out_desktop: *mut Option, + ) -> HRESULT; + + pub unsafe fn wait_for_animation_to_complete(&self) -> HRESULT; + } + } +); + +reusable_com_interface!( + MacroOptions { + temp_macro_name: _IVirtualDesktopNotification, + iid: "B287FA1C-7771-471A-A2DF-9B6B21F0D675", + }, + { + pub unsafe trait IVirtualDesktopNotification: IUnknown { + pub unsafe fn virtual_desktop_created( + &self, + desktop: ComIn, + ) -> HRESULT; + + pub unsafe fn virtual_desktop_destroy_begin( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT; + + pub unsafe fn virtual_desktop_destroy_failed( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT; + + pub unsafe fn virtual_desktop_destroyed( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT; + + pub unsafe fn virtual_desktop_moved( + &self, + desktop: ComIn, + old_index: i64, + new_index: i64, + ) -> HRESULT; + + pub unsafe fn virtual_desktop_name_changed( + &self, + desktop: ComIn, + name: HSTRING, + ) -> HRESULT; + + pub unsafe fn view_virtual_desktop_changed( + &self, + view: ComIn, + ) -> HRESULT; + + pub unsafe fn current_virtual_desktop_changed( + &self, + desktop_old: ComIn, + desktop_new: ComIn, + ) -> HRESULT; + + pub unsafe fn virtual_desktop_wallpaper_changed( + &self, + desktop: ComIn, + name: HSTRING, + ) -> HRESULT; + + pub unsafe fn virtual_desktop_switched( + &self, + desktop: ComIn, + ) -> HRESULT; + + pub unsafe fn remote_virtual_desktop_connected( + &self, + desktop: ComIn, + ) -> HRESULT; + } + + /// Implements an unstable interface that is only valid for a single Windows + /// version using a more stable trait that works for all Windows versions. + #[windows::core::implement(IVirtualDesktopNotification)] + pub struct VirtualDesktopNotificationAdaptor + where + T: build_dyn::IVirtualDesktopNotification_Impl, + { + pub inner: T, + } + impl IVirtualDesktopNotification_Impl for VirtualDesktopNotificationAdaptor + where + T: build_dyn::IVirtualDesktopNotification_Impl, + { + unsafe fn virtual_desktop_created(&self, desktop: ComIn) -> HRESULT { + self.inner.virtual_desktop_created(desktop.into()) + } + + unsafe fn virtual_desktop_destroy_begin( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT { + self.inner.virtual_desktop_destroy_begin( + desktop_destroyed.into(), + desktop_fallback.into(), + ) + } + + unsafe fn virtual_desktop_destroy_failed( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT { + self.inner.virtual_desktop_destroy_failed( + desktop_destroyed.into(), + desktop_fallback.into(), + ) + } + + unsafe fn virtual_desktop_destroyed( + &self, + desktop_destroyed: ComIn, + desktop_fallback: ComIn, + ) -> HRESULT { + self.inner + .virtual_desktop_destroyed(desktop_destroyed.into(), desktop_fallback.into()) + } + + unsafe fn virtual_desktop_moved( + &self, + desktop: ComIn, + old_index: i64, + new_index: i64, + ) -> HRESULT { + self.inner + .virtual_desktop_moved(desktop.into(), old_index, new_index) + } + + unsafe fn virtual_desktop_name_changed( + &self, + desktop: ComIn, + name: HSTRING, + ) -> HRESULT { + self.inner + .virtual_desktop_name_changed(desktop.into(), name) + } + + unsafe fn view_virtual_desktop_changed( + &self, + view: ComIn, + ) -> HRESULT { + self.inner.view_virtual_desktop_changed(view.into()) + } + + unsafe fn current_virtual_desktop_changed( + &self, + desktop_old: ComIn, + desktop_new: ComIn, + ) -> HRESULT { + self.inner + .current_virtual_desktop_changed(desktop_old.into(), desktop_new.into()) + } + + unsafe fn virtual_desktop_wallpaper_changed( + &self, + desktop: ComIn, + name: HSTRING, + ) -> HRESULT { + self.inner + .virtual_desktop_wallpaper_changed(desktop.into(), name) + } + + unsafe fn virtual_desktop_switched(&self, desktop: ComIn) -> HRESULT { + self.inner.virtual_desktop_switched(desktop.into()) + } + + unsafe fn remote_virtual_desktop_connected( + &self, + desktop: ComIn, + ) -> HRESULT { + self.inner.remote_virtual_desktop_connected(desktop.into()) + } + } + } +); diff --git a/src/interfaces_multi/build_22621_3155.rs b/src/interfaces_multi/build_22621_3155.rs new file mode 100644 index 0000000..e74ba55 --- /dev/null +++ b/src/interfaces_multi/build_22621_3155.rs @@ -0,0 +1,10 @@ +use super::*; +use build_22621_2215 as prev_build; + +prev_build::IApplicationView!("372E1D3B-38D3-42E4-A15B-8AB2B178F513"); // Same +prev_build::IApplicationViewCollection!("1841C6D7-4F9D-42C0-AF41-8747538F10E5"); // Same +prev_build::IVirtualDesktop!("3F07F4BE-B107-441A-AF0F-39D82529072C"); // Same +prev_build::IVirtualDesktopManagerInternal!("53F5CA0B-158F-4124-900C-057158060B27"); // Changed +prev_build::IVirtualDesktopNotification!("B9E5E94D-233E-49AB-AF5C-2B4541C3AADE"); // Changed +prev_build::IVirtualDesktopNotificationService!("0cd45e71-d927-4f15-8b0a-8fef525337bf"); // Same +prev_build::IVirtualDesktopPinnedApps!("4CE81583-1E4C-4632-A621-07A53543148F"); // Same diff --git a/src/interfaces_multi/build_22631_2428.rs b/src/interfaces_multi/build_22631_2428.rs new file mode 100644 index 0000000..d946e5d --- /dev/null +++ b/src/interfaces_multi/build_22631_2428.rs @@ -0,0 +1,10 @@ +use super::*; +use build_22621_2215 as prev_build; + +prev_build::IApplicationView!("372E1D3B-38D3-42E4-A15B-8AB2B178F513"); +prev_build::IApplicationViewCollection!("1841C6D7-4F9D-42C0-AF41-8747538F10E5"); +prev_build::IVirtualDesktop!("3F07F4BE-B107-441A-AF0F-39D82529072C"); +prev_build::IVirtualDesktopManagerInternal!("A3175F2D-239C-4BD2-8AA0-EEBA8B0B138E"); // Changed +prev_build::IVirtualDesktopNotification!("B287FA1C-7771-471A-A2DF-9B6B21F0D675"); // Changed +prev_build::IVirtualDesktopNotificationService!("0cd45e71-d927-4f15-8b0a-8fef525337bf"); +prev_build::IVirtualDesktopPinnedApps!("4CE81583-1E4C-4632-A621-07A53543148F"); diff --git a/src/interfaces_multi/build_22631_3155.rs b/src/interfaces_multi/build_22631_3155.rs new file mode 100644 index 0000000..f697de6 --- /dev/null +++ b/src/interfaces_multi/build_22631_3155.rs @@ -0,0 +1,10 @@ +use super::*; +use build_22621_2215 as prev_build; + +prev_build::IApplicationView!("372E1D3B-38D3-42E4-A15B-8AB2B178F513"); +prev_build::IApplicationViewCollection!("1841C6D7-4F9D-42C0-AF41-8747538F10E5"); +prev_build::IVirtualDesktop!("3F07F4BE-B107-441A-AF0F-39D82529072C"); +prev_build::IVirtualDesktopManagerInternal!("53F5CA0B-158F-4124-900C-057158060B27"); // Changed +prev_build::IVirtualDesktopNotification!("B9E5E94D-233E-49AB-AF5C-2B4541C3AADE"); // Changed +prev_build::IVirtualDesktopNotificationService!("0cd45e71-d927-4f15-8b0a-8fef525337bf"); +prev_build::IVirtualDesktopPinnedApps!("4CE81583-1E4C-4632-A621-07A53543148F"); diff --git a/src/interfaces_multi/build_dyn.rs b/src/interfaces_multi/build_dyn.rs index 733c77d..d45decf 100644 --- a/src/interfaces_multi/build_dyn.rs +++ b/src/interfaces_multi/build_dyn.rs @@ -79,13 +79,22 @@ with_versions!(declare_WindowsVersion); // } // } impl WindowsVersion { - fn windows_build(&self) -> u32 { - let (_, ver) = self + fn windows_build(&self) -> (u32, u32) { + let (_, version) = self .as_str() .split_once('_') .expect("Module name didn't contain an underscore"); - ver.parse() - .expect("Failed to parse module suffix as build version") + // We allow omitting the patch version in the module name: + let (build, patch) = version.split_once('_').unwrap_or((version, "0")); + + ( + build + .parse() + .expect("Failed to parse module suffix as build version"), + patch + .parse() + .expect("Failed to parse module suffix as patch version"), + ) } /// Get info about the current Windows version. Only differentiates between /// Windows versions that have different virtual desktop interfaces. @@ -127,18 +136,26 @@ impl WindowsVersion { version.dwOSVersionInfoSize = core::mem::size_of_val(&version) as u32; let res = unsafe { windows::Wdk::System::SystemServices::RtlGetVersion(&mut version) }; if res.is_err() { + log_format!( + "Failed to get Windows version with error {res:?} using \ + COM interfaces for version latest supported version: {:?}", + Self::default() + ); return Default::default(); } - Self::ALL + // FIXME: we don't get the patch version of Windows and just assume the user is on the latest one. + let latest_supported = Self::ALL .iter() .copied() .map(|v| (v, v.windows_build())) // Only consider COM interfaces from previous or current build: - .filter(|(_, build_ver)| *build_ver <= version.dwBuildNumber) + .filter(|(_, (build, _patch))| *build <= version.dwBuildNumber) // Then find the latest one: - .max_by_key(|(_, build_ver)| *build_ver) + .max_by_key(|(_, version)| *version) .map(|(v, _)| v) - .unwrap_or_default() + .unwrap_or_default(); + log_format!("Using COM interfaces for Windows version: {latest_supported:?}"); + latest_supported }) } } @@ -162,6 +179,8 @@ pub trait WithVersionedTypeCallback { fn call(self) -> R; } +/// Convert a method argument when forwarding a call to a version specific COM +/// interface. pub(crate) trait ForwardArg { fn forward(self) -> T; } @@ -171,11 +190,15 @@ impl ForwardArg for T { } } -/// Generates support code for a COM interface. -/// -/// Syntax is: `as CreatedEnumName for InterfaceName in $(all)? [version_module_1, version_module_2 $(,)?]` +/// Generates code to support a COM interface. macro_rules! support_interface { - (@inner {$dollar:tt} as $state:ident for $name:ident in $(all $(@ $all:tt)?)? [$($version:ident),* $(,)?]) => { + (MacroOptions { + interface_name: $name:ident, + enum_name: $state:ident, + all_versions: $(true $(@ $all_versions:tt)?)? $(false)?, + versions: [$($version:ident),* $(,)?], + dollar: {$dollar:tt} $(,)? + }) => { $( // assert_eq_size from static_assertions crate const _: fn() = || { @@ -196,7 +219,7 @@ macro_rules! support_interface { // any() => false // all(any()) => false // And the default macro arm will be hidden. - #[cfg(all($(any() $($all)?)?))] + #[cfg(all($(any() $($all_versions)?)?))] _ => (), } }; @@ -344,11 +367,61 @@ macro_rules! support_interface { )* /// Preform the same action for each version of the wrapped COM interface. /// - /// Syntax: GeneralType, |versioned: versioned_mod::VersionedType| block_of_code + /// Syntax: abstract_value, |versioned: versioned_mod::VersionedType| block_of_code + /// + /// Alternative syntax (not implemented): + /// ```text + /// specialized abstract_value, + /// $( + /// $([variant, variant...],)? + /// |versioned: versioned_mod::VersionedType| {code_for_variants}, + /// )* + /// else + /// |versioned: versioned_mod::VersionedType| code_for_remaining_variants + /// ```text /// /// Note: named the same as the interface to allow for easier usage with macros. #[allow(unused_macros)] macro_rules! $name { + //(specialized + // $dollar this:expr, + // $dollar ( + // [$dollar ($dollar special:ident),* $dollar (,)?], + // |$dollar arg:ident + // $dollar ( + // : + // $dollar module_name:ident + // :: + // $dollar arg_ty:ident + // )? + // | + // { $dollar ($dollar body:tt)* } + // ),* + // else + // |$dollar arg_else:ident + // $dollar ( + // : + // $dollar module_name_else:ident + // :: + // $dollar arg_ty_else:ident + // )? + // | + // $dollar ($dollar body_else:tt)* + //) => {{ + // match $state::from_typed(&$dollar this) { + // $( + // $state::$version($dollar arg) => { + // $dollar ( + // #[allow(unused_imports)] + // use self::$version as $dollar module_name; + // #[allow(unused_imports)] + // use self::$version::$name as $dollar arg_ty; + // )? + // $dollar ($dollar body)* + // }, + // )* + // } + //}}; ( $dollar this:expr, |$dollar arg:ident @@ -374,13 +447,50 @@ macro_rules! support_interface { }, )* } - } + }; } }; - // Pass an escaped dollar sign to the real macro so that we can construct a - // new macro later: - (as $state:ident for $name:ident in $($in:tt)*) => { - support_interface! { @inner {$} as $state for $name in $($in)* } + (MacroOptions { + interface_name: $name:ident, + enum_name: $state:ident, + all_versions: true, + }) => { + super::with_versions!{ + support_interface, + @callback + state = { + interface_name: $name, + enum_name: $state, + }, + } + }; + // Invoked by `with_versions` macro, allows us to use all module names + (@callback + state = { $($other_args:tt)* }, + versions = { $($versions:tt)* }, + ) => { + support_interface! {MacroOptions { + $($other_args)* + all_versions: true, + versions: [$($versions)*], + dollar: {$}, + }} + }; + (MacroOptions { + interface_name: $name:ident, + enum_name: $state:ident, + all_versions: $(true $(@$all_versions:tt)?)? $(false)?, + versions: [$($versions:ident),* $(,)?] $(,)? + }) => { + // Pass an escaped dollar sign to the real macro so that we can construct a + // new macro later: + support_interface! {MacroOptions { + interface_name: $name, + enum_name: $state, + all_versions: $(true $all_versions)?, + versions: [$($versions,)*], + dollar: {$}, + }} }; } @@ -414,6 +524,52 @@ macro_rules! forward_call { } } ); + // No function body => forward the call automatically (sometimes not + // implemented for the versioned interface): + (@item + #[forward_for = $name:ident] + #[optional_method] + $( #[$attr:meta] )* + $pub:vis + $(unsafe $(@ $unsafe:tt)?)? + fn $fname:ident ( + &$self_:ident $(,)? $( $arg_name:ident : $ArgTy:ty ),* $(,)? + ) -> $RetTy:ty; + ) => { + $( #[$attr] )* + #[allow(unused_parens, unused_unsafe)] + $pub + $(unsafe $($unsafe)?)? + fn $fname ( + &$self_, $( $arg_name : $ArgTy ),* + ) -> $RetTy + { + /// Trait implementation has lower priority than inherent + /// implementation, see: + /// + trait __FallbackNotImpl { + fn $fname( + &$self_, $( _: $ArgTy ),* + ) -> $RetTy; + } + impl __FallbackNotImpl for T { + fn $fname( + &$self_, $( _: $ArgTy ),* + ) -> $RetTy { + E_NOTIMPL + } + } + + unsafe { + $name!( + $self_, + |v| (*v).$fname( $( + ForwardArg::forward($arg_name) + ),*) + ) + } + } + }; // No function body => forward the call automatically: (@item #[forward_for = $name:ident] @@ -494,11 +650,15 @@ macro_rules! forward_call { }; } -support_interface!(as IApplicationViewInner for IApplicationView in all [build_10240, build_22000]); - #[derive(Debug, Clone, PartialEq, Eq)] #[repr(transparent)] pub struct IApplicationView(IUnknown); +support_interface!(MacroOptions { + interface_name: IApplicationView, + enum_name: IApplicationViewEnum, + all_versions: true, +}); + #[apply(forward_call)] impl IApplicationView { /* IInspecateble */ @@ -507,10 +667,7 @@ impl IApplicationView { out_iid_count: *mut ULONG, out_opt_iid_array_ptr: *mut *mut GUID, ) -> HRESULT; - pub unsafe fn get_runtime_class_name( - &self, - out_opt_class_name: *mut HSTRING, - ) -> HRESULT; + pub unsafe fn get_runtime_class_name(&self, out_opt_class_name: *mut HSTRING) -> HRESULT; pub unsafe fn get_trust_level(&self, ptr_trust_level: LPVOID) -> HRESULT; /* IApplicationView methods */ @@ -531,28 +688,19 @@ impl IApplicationView { unknowniid: *const GUID, unknown_array_ptr: LPVOID, ) -> HRESULT; - pub unsafe fn set_position( - &self, - view_position: *mut IApplicationViewPosition, - ) -> HRESULT; + pub unsafe fn set_position(&self, view_position: *mut IApplicationViewPosition) -> HRESULT; pub unsafe fn insert_after_window(&self, window: HWND) -> HRESULT; pub unsafe fn get_extended_frame_position(&self, rect: *mut RECT) -> HRESULT; pub unsafe fn get_app_user_model_id(&self, id: *mut PWSTR) -> HRESULT; // Proc17 pub unsafe fn set_app_user_model_id(&self, id: PCWSTR) -> HRESULT; - pub unsafe fn is_equal_by_app_user_model_id( - &self, - id: PCWSTR, - out_result: *mut INT, - ) -> HRESULT; + pub unsafe fn is_equal_by_app_user_model_id(&self, id: PCWSTR, out_result: *mut INT) + -> HRESULT; /*** IApplicationView methods ***/ pub unsafe fn get_view_state(&self, out_state: *mut UINT) -> HRESULT; // Proc20 pub unsafe fn set_view_state(&self, state: UINT) -> HRESULT; // Proc21 pub unsafe fn get_neediness(&self, out_neediness: *mut INT) -> HRESULT; // Proc22 - pub unsafe fn get_last_activation_timestamp( - &self, - out_timestamp: *mut ULONGLONG, - ) -> HRESULT; + pub unsafe fn get_last_activation_timestamp(&self, out_timestamp: *mut ULONGLONG) -> HRESULT; pub unsafe fn set_last_activation_timestamp(&self, timestamp: ULONGLONG) -> HRESULT; pub unsafe fn get_virtual_desktop_id(&self, out_desktop_guid: *mut GUID) -> HRESULT; pub unsafe fn set_virtual_desktop_id(&self, desktop_guid: *const GUID) -> HRESULT; @@ -568,14 +716,6 @@ impl IApplicationView { &self, policy_type: APPLICATION_VIEW_COMPATIBILITY_POLICY, ) -> HRESULT; - pub unsafe fn get_position_priority( - &self, - out_priority: *mut IShellPositionerPriority, - ) -> HRESULT; - pub unsafe fn set_position_priority( - &self, - priority: IShellPositionerPriority, - ) -> HRESULT; pub unsafe fn get_size_constraints( &self, @@ -596,20 +736,13 @@ impl IApplicationView { size2: *const SIZE, ) -> HRESULT; - pub unsafe fn query_size_constraints_from_app(&self) -> HRESULT; pub unsafe fn on_min_size_preferences_updated(&self, window: HWND) -> HRESULT; - pub unsafe fn apply_operation( - &self, - operation: *mut IApplicationViewOperation, - ) -> HRESULT; + pub unsafe fn apply_operation(&self, operation: *mut IApplicationViewOperation) -> HRESULT; pub unsafe fn is_tray(&self, out_is: *mut BOOL) -> HRESULT; pub unsafe fn is_in_high_zorder_band(&self, out_is: *mut BOOL) -> HRESULT; pub unsafe fn is_splash_screen_presented(&self, out_is: *mut BOOL) -> HRESULT; pub unsafe fn flash(&self) -> HRESULT; - pub unsafe fn get_root_switchable_owner( - &self, - app_view: *mut IApplicationView, - ) -> HRESULT; // proc45 + pub unsafe fn get_root_switchable_owner(&self, app_view: *mut IApplicationView) -> HRESULT; // proc45 pub unsafe fn enumerate_ownership_tree(&self, objects: *mut IObjectArray) -> HRESULT; // proc46 pub unsafe fn get_enterprise_id(&self, out_id: *mut PWSTR) -> HRESULT; // proc47 @@ -629,11 +762,15 @@ impl IApplicationView { pub unsafe fn unknown12(&self, arg: *mut SIZE) -> HRESULT; } -support_interface!(as IVirtualDesktopInner for IVirtualDesktop in [build_10240, build_22000]); - #[derive(Debug, Clone, PartialEq, Eq)] #[repr(transparent)] pub struct IVirtualDesktop(IUnknown); +support_interface!(MacroOptions { + interface_name: IVirtualDesktop, + enum_name: IVirtualDesktopInner, + all_versions: true, +}); + #[apply(forward_call)] impl IVirtualDesktop { pub unsafe fn is_view_visible( @@ -642,26 +779,21 @@ impl IVirtualDesktop { out_bool: *mut u32, ) -> HRESULT; pub unsafe fn get_id(&self, out_guid: *mut GUID) -> HRESULT; - - pub unsafe fn get_name(&self, out_string: *mut HSTRING) -> HRESULT { - match IVirtualDesktopInner::from_typed(self) { - IVirtualDesktopInner::build_10240(_) => E_NOTIMPL, - IVirtualDesktopInner::build_22000(this) => unsafe { this.get_name(out_string) }, - } - } - pub unsafe fn get_wallpaper(&self, out_string: *mut HSTRING) -> HRESULT { - match IVirtualDesktopInner::from_typed(self) { - IVirtualDesktopInner::build_10240(_) => E_NOTIMPL, - IVirtualDesktopInner::build_22000(this) => unsafe { this.get_wallpaper(out_string) }, - } - } + #[optional_method] + pub unsafe fn get_name(&self, out_string: *mut HSTRING) -> HRESULT; + #[optional_method] + pub unsafe fn get_wallpaper(&self, out_string: *mut HSTRING) -> HRESULT; } -support_interface!(as IApplicationViewCollectionInner for IApplicationViewCollection in all [build_10240, build_22000]); - #[derive(Debug, Clone, PartialEq, Eq)] #[repr(transparent)] pub struct IApplicationViewCollection(IUnknown); +support_interface!(MacroOptions { + interface_name: IApplicationViewCollection, + enum_name: IApplicationViewCollectionInner, + all_versions: true, +}); + #[apply(forward_call)] impl IApplicationViewCollection { pub unsafe fn get_views(&self, out_views: *mut IObjectArray) -> HRESULT; @@ -678,48 +810,35 @@ impl IApplicationViewCollection { &self, window: HWND, out_view: *mut Option, - ) -> HRESULT { - IApplicationViewCollection!(self, |inner| inner - .get_view_for_hwnd(window, out_view as *mut _)) - } + ) -> HRESULT; pub unsafe fn get_view_for_application( &self, app: IImmersiveApplication, out_view: *mut IApplicationView, - ) -> HRESULT { - IApplicationViewCollection!(self, |inner| inner - .get_view_for_application(app, out_view as *mut _)) - } + ) -> HRESULT; pub unsafe fn get_view_for_app_user_model_id( &self, id: PCWSTR, out_view: *mut IApplicationView, - ) -> HRESULT { - IApplicationViewCollection!(self, |inner| inner - .get_view_for_app_user_model_id(id, out_view as *mut _)) - } + ) -> HRESULT; - pub unsafe fn get_view_in_focus(&self, out_view: &mut Option) -> HRESULT { - unsafe { - IApplicationViewCollection!(self, |inner| inner - .get_view_in_focus(out_view as *mut Option<_> as *mut _)) - } - } + pub unsafe fn get_view_in_focus(&self, out_view: *mut IApplicationView) -> HRESULT; + + #[optional_method] + pub unsafe fn try_get_last_active_visible_view( + &self, + out_view: *mut IApplicationView, + ) -> HRESULT; pub unsafe fn refresh_collection(&self) -> HRESULT; pub unsafe fn register_for_application_view_changes( &self, listener: IApplicationViewChangeListener, - out_id: &mut DWORD, - ) -> HRESULT { - unsafe { - IApplicationViewCollection!(self, |inner| inner - .register_for_application_view_changes(listener, out_id)) - } - } + out_id: *mut DWORD, + ) -> HRESULT; pub unsafe fn unregister_for_application_view_changes(&self, id: DWORD) -> HRESULT; } @@ -740,26 +859,32 @@ impl IApplicationViewCollection { } } -support_interface!(as IVirtualDesktopNotificationInner for IVirtualDesktopNotification in all [build_10240, build_22000]); - #[derive(Debug, Clone, PartialEq, Eq)] #[repr(transparent)] pub struct IVirtualDesktopNotification(IUnknown); +support_interface!(MacroOptions { + interface_name: IVirtualDesktopNotification, + enum_name: IVirtualDesktopNotificationInner, + all_versions: true, +}); + impl From for IVirtualDesktopNotification where T: IVirtualDesktopNotification_Impl, { fn from(value: T) -> Self { - match WindowsVersion::get() { - WindowsVersion::build_10240 => build_10240::IVirtualDesktopNotification::from( - build_10240::VirtualDesktopNotificationAdaptor { inner: value }, - ) - .into(), - WindowsVersion::build_22000 => build_22000::IVirtualDesktopNotification::from( - build_22000::VirtualDesktopNotificationAdaptor { inner: value }, - ) - .into(), + macro_rules! get_adaptor { + (versions = {$($version:ident,)*},) => { + match WindowsVersion::get() { + $( + WindowsVersion::$version => $version::IVirtualDesktopNotification::from( + $version::VirtualDesktopNotificationAdaptor { inner: value }, + ).into(), + )* + } + }; } + super::with_versions!{get_adaptor} } } #[allow(non_camel_case_types)] @@ -816,19 +941,23 @@ pub trait IVirtualDesktopNotification_Impl { unsafe fn remote_virtual_desktop_connected(&self, desktop: ComIn) -> HRESULT; } -support_interface!(as IVirtualDesktopNotificationServiceInner for IVirtualDesktopNotificationService in all [build_10240, build_22000]); - #[derive(Debug, Clone, PartialEq, Eq)] #[repr(transparent)] pub struct IVirtualDesktopNotificationService(IUnknown); +support_interface!(MacroOptions { + interface_name: IVirtualDesktopNotificationService, + enum_name: IVirtualDesktopNotificationServiceInner, + all_versions: true, +}); #[apply(forward_call)] impl IVirtualDesktopNotificationService { pub unsafe fn register( &self, - notification: *mut std::ffi::c_void, + notification: *mut std::ffi::c_void, // *const IVirtualDesktopNotification, out_cookie: *mut DWORD, ) -> HRESULT; + pub unsafe fn unregister(&self, cookie: u32) -> HRESULT; } impl IVirtualDesktopNotificationService { @@ -848,14 +977,41 @@ impl IVirtualDesktopNotificationService { } } -support_interface!(as IVirtualDesktopManagerInternalInner for IVirtualDesktopManagerInternal in all [build_10240, build_22000]); - #[derive(Debug, Clone, PartialEq, Eq)] #[repr(transparent)] pub struct IVirtualDesktopManagerInternal(IUnknown); +support_interface!(MacroOptions { + interface_name: IVirtualDesktopManagerInternal, + enum_name: IVirtualDesktopManagerInternalInner, + all_versions: true, +}); + #[apply(forward_call)] impl IVirtualDesktopManagerInternal { - pub unsafe fn get_desktop_count(&self, out_count: *mut UINT) -> HRESULT; + pub unsafe fn get_desktop_count(&self, out_count: *mut UINT) -> HRESULT { + struct Specialize(T); + impl Specialize<&build_20348::IVirtualDesktopManagerInternal> { + unsafe fn get_desktop_count(&self, out_count: *mut UINT) -> HRESULT { + self.0.get_desktop_count(0, out_count) + } + } + impl Specialize<&build_22000::IVirtualDesktopManagerInternal> { + unsafe fn get_desktop_count(&self, out_count: *mut UINT) -> HRESULT { + self.0.get_desktop_count(0, out_count) + } + } + // The compiler prefers inherit methods and only derefs if no such + // method can be found. + impl core::ops::Deref for Specialize { + type Target = T; + fn deref(&self) -> &T { + &self.0 + } + } + IVirtualDesktopManagerInternal!(self, |this: version::Versioned| { + Specialize(&*this).get_desktop_count(out_count) + }) + } pub unsafe fn move_view_to_desktop( &self, @@ -867,16 +1023,57 @@ impl IVirtualDesktopManagerInternal { &self, view: ComIn, can_move: *mut i32, - ) -> HRESULT { - unsafe { - IVirtualDesktopManagerInternal!(self, |i| i - .can_move_view_between_desktops(view.into(), can_move)) + ) -> HRESULT; + + pub unsafe fn get_current_desktop(&self, out_desktop: *mut Option) -> HRESULT { + struct Specialize(T); + impl Specialize<&build_20348::IVirtualDesktopManagerInternal> { + unsafe fn get_current_desktop(&self, out_desktop: *mut Option) -> HRESULT { + self.0.get_current_desktop(0, out_desktop.forward()) + } + } + impl Specialize<&build_22000::IVirtualDesktopManagerInternal> { + unsafe fn get_current_desktop(&self, out_desktop: *mut Option) -> HRESULT { + self.0.get_current_desktop(0, out_desktop.forward()) + } + } + // The compiler prefers inherit methods and only derefs if no such + // method can be found. + impl core::ops::Deref for Specialize { + type Target = T; + fn deref(&self) -> &T { + &self.0 + } } + IVirtualDesktopManagerInternal!(self, |this: version::Versioned| { + Specialize(&*this).get_current_desktop(out_desktop.forward()) + }) } - pub unsafe fn get_current_desktop(&self, out_desktop: *mut Option) -> HRESULT; - - pub unsafe fn get_desktops(&self, out_desktops: *mut Option) -> HRESULT; + pub unsafe fn get_desktops(&self, out_desktops: *mut Option) -> HRESULT { + struct Specialize(T); + impl Specialize<&build_20348::IVirtualDesktopManagerInternal> { + unsafe fn get_desktops(&self, out_desktops: *mut Option) -> HRESULT { + self.0.get_desktops(0, out_desktops) + } + } + impl Specialize<&build_22000::IVirtualDesktopManagerInternal> { + unsafe fn get_desktops(&self, out_desktops: *mut Option) -> HRESULT { + self.0.get_desktops(0, out_desktops) + } + } + // The compiler prefers inherit methods and only derefs if no such + // method can be found. + impl core::ops::Deref for Specialize { + type Target = T; + fn deref(&self) -> &T { + &self.0 + } + } + IVirtualDesktopManagerInternal!(self, |this: version::Versioned| { + Specialize(&*this).get_desktops(out_desktops) + }) + } /// Get next or previous desktop /// @@ -890,17 +1087,86 @@ impl IVirtualDesktopManagerInternal { out_pp_desktop: *mut Option, ) -> HRESULT; - pub unsafe fn switch_desktop(&self, desktop: ComIn) -> HRESULT; + pub unsafe fn switch_desktop(&self, desktop: ComIn) -> HRESULT { + struct Specialize(T); + impl Specialize<&build_20348::IVirtualDesktopManagerInternal> { + unsafe fn switch_desktop(&self, desktop: ComIn) -> HRESULT { + self.0.switch_desktop(0, desktop.forward()) + } + } + impl Specialize<&build_22000::IVirtualDesktopManagerInternal> { + unsafe fn switch_desktop(&self, desktop: ComIn) -> HRESULT { + self.0.switch_desktop(0, desktop.forward()) + } + } + // The compiler prefers inherit methods and only derefs if no such + // method can be found. + impl core::ops::Deref for Specialize { + type Target = T; + fn deref(&self) -> &T { + &self.0 + } + } + IVirtualDesktopManagerInternal!(self, |this: version::Versioned| { + Specialize(&*this).switch_desktop(desktop.forward()) + }) + } - pub unsafe fn create_desktop(&self, out_desktop: *mut Option) -> HRESULT; + pub unsafe fn create_desktop(&self, out_desktop: *mut Option) -> HRESULT { + struct Specialize(T); + impl Specialize<&build_20348::IVirtualDesktopManagerInternal> { + unsafe fn create_desktop(&self, out_desktop: *mut Option) -> HRESULT { + self.0.create_desktop(0, out_desktop.forward()) + } + } + impl Specialize<&build_22000::IVirtualDesktopManagerInternal> { + unsafe fn create_desktop(&self, out_desktop: *mut Option) -> HRESULT { + self.0.create_desktop(0, out_desktop.forward()) + } + } + // The compiler prefers inherit methods and only derefs if no such + // method can be found. + impl core::ops::Deref for Specialize { + type Target = T; + fn deref(&self) -> &T { + &self.0 + } + } + IVirtualDesktopManagerInternal!(self, |this: version::Versioned| { + Specialize(&*this).create_desktop(out_desktop.forward()) + }) + } pub unsafe fn move_desktop(&self, in_desktop: ComIn, index: UINT) -> HRESULT { - match IVirtualDesktopManagerInternalInner::from_typed(self) { - IVirtualDesktopManagerInternalInner::build_10240(_) => E_NOTIMPL, - IVirtualDesktopManagerInternalInner::build_22000(v) => { - v.move_desktop(in_desktop.into(), index) + struct Specialize(T); + impl Specialize<&build_22000::IVirtualDesktopManagerInternal> { + unsafe fn move_desktop(&self, in_desktop: ComIn, index: UINT) -> HRESULT { + self.0.move_desktop(in_desktop.forward(), 0, index) } } + // The compiler prefers inherit methods and only derefs if no such + // method can be found. + impl core::ops::Deref for Specialize { + type Target = T; + fn deref(&self) -> &T { + &self.0 + } + } + + trait __FallbackNotImpl { + unsafe fn move_desktop(&self, in_desktop: ComIn, index: UINT) -> HRESULT; + } + + IVirtualDesktopManagerInternal!(self, |this: version::Versioned| { + // Only uses trait methods if there aren't any inherent methods + impl __FallbackNotImpl for Versioned { + unsafe fn move_desktop(&self, _: ComIn, _: UINT) -> HRESULT { + E_NOTIMPL + } + } + + Specialize(&*this).move_desktop(in_desktop.forward(), index) + }) } pub unsafe fn remove_desktop( @@ -913,55 +1179,22 @@ impl IVirtualDesktopManagerInternal { &self, guid: *const GUID, out_desktop: *mut Option, - ) -> HRESULT { - unsafe { - IVirtualDesktopManagerInternal!(self, |inner| { - inner.find_desktop(guid, out_desktop.forward()) - }) - } - } + ) -> HRESULT; + #[optional_method] pub unsafe fn get_desktop_switch_include_exclude_views( &self, desktop: ComIn, out_pp_desktops1: *mut IObjectArray, out_pp_desktops2: *mut IObjectArray, - ) -> HRESULT { - match IVirtualDesktopManagerInternalInner::from_typed(self) { - IVirtualDesktopManagerInternalInner::build_10240(_) => E_NOTIMPL, - IVirtualDesktopManagerInternalInner::build_22000(inner) => inner - .get_desktop_switch_include_exclude_views( - desktop.forward(), - out_pp_desktops1, - out_pp_desktops2, - ), - } - } + ) -> HRESULT; - pub unsafe fn set_name(&self, desktop: ComIn, name: HSTRING) -> HRESULT { - match IVirtualDesktopManagerInternalInner::from_typed(self) { - IVirtualDesktopManagerInternalInner::build_10240(_) => E_NOTIMPL, - IVirtualDesktopManagerInternalInner::build_22000(inner) => { - inner.set_name(desktop.forward(), name) - } - } - } - pub unsafe fn set_wallpaper(&self, desktop: ComIn, name: HSTRING) -> HRESULT { - match IVirtualDesktopManagerInternalInner::from_typed(self) { - IVirtualDesktopManagerInternalInner::build_10240(_) => E_NOTIMPL, - IVirtualDesktopManagerInternalInner::build_22000(inner) => { - inner.set_wallpaper(desktop.forward(), name) - } - } - } - pub unsafe fn update_wallpaper_for_all(&self, name: HSTRING) -> HRESULT { - match IVirtualDesktopManagerInternalInner::from_typed(self) { - IVirtualDesktopManagerInternalInner::build_10240(_) => E_NOTIMPL, - IVirtualDesktopManagerInternalInner::build_22000(inner) => { - inner.update_wallpaper_for_all(name) - } - } - } + #[optional_method] + pub unsafe fn set_name(&self, desktop: ComIn, name: HSTRING) -> HRESULT; + #[optional_method] + pub unsafe fn set_wallpaper(&self, desktop: ComIn, name: HSTRING) -> HRESULT; + #[optional_method] + pub unsafe fn update_wallpaper_for_all(&self, name: HSTRING) -> HRESULT; } impl IVirtualDesktopManagerInternal { pub unsafe fn query_service(provider: &IServiceProvider) -> crate::Result { @@ -980,11 +1213,14 @@ impl IVirtualDesktopManagerInternal { } } -support_interface!(as IVirtualDesktopPinnedAppsInner for IVirtualDesktopPinnedApps in all [build_10240, build_22000]); - #[derive(Debug, Clone, PartialEq, Eq)] #[repr(transparent)] pub struct IVirtualDesktopPinnedApps(IUnknown); +support_interface!(MacroOptions { + interface_name: IVirtualDesktopPinnedApps, + enum_name: IVirtualDesktopPinnedAppsInner, + all_versions: true, +}); #[apply(forward_call)] impl IVirtualDesktopPinnedApps { @@ -996,11 +1232,7 @@ impl IVirtualDesktopPinnedApps { &self, view: ComIn, out_iss: *mut bool, - ) -> HRESULT { - unsafe { - IVirtualDesktopPinnedApps!(self, |inner| inner.is_view_pinned(view.into(), out_iss)) - } - } + ) -> HRESULT; pub unsafe fn pin_view(&self, view: ComIn) -> HRESULT; pub unsafe fn unpin_view(&self, view: ComIn) -> HRESULT; } diff --git a/src/lib.rs b/src/lib.rs index 1c8c9e2..bb96a1d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,14 @@ //! * Get third desktop name `get_desktop(2).get_name()` #![allow(clippy::bool_assert_comparison)] +// Log format macro +macro_rules! log_format { + ($($arg:tt)*) => { + #[cfg(debug_assertions)] + $crate::log::log_output(&format!($($arg)*)); + }; +} + mod comobjects; mod desktop; mod events; diff --git a/src/listener.rs b/src/listener.rs index 286876d..1bccdaa 100644 --- a/src/listener.rs +++ b/src/listener.rs @@ -18,14 +18,6 @@ use windows::Win32::System::Threading::{ GetCurrentThread, SetThreadPriority, THREAD_PRIORITY_TIME_CRITICAL, }; -// Log format macro -macro_rules! log_format { - ($($arg:tt)*) => { - #[cfg(debug_assertions)] - $crate::log::log_output(&format!($($arg)*)); - }; -} - enum DekstopEventThreadMsg { Quit, } From dfb1409f991c8a4e4a674cb7c5ea57deb78cd3de Mon Sep 17 00:00:00 2001 From: Lej77 <31554212+Lej77@users.noreply.github.com> Date: Tue, 2 Apr 2024 17:30:28 +0200 Subject: [PATCH 08/11] test: fix doc tests and ignore those that don't compile --- src/comobjects.rs | 11 +++++------ src/events.rs | 6 +++--- src/interfaces.rs | 4 ++-- src/interfaces_multi.rs | 4 ++-- src/tests.rs | 25 ++++++++++++++++--------- 5 files changed, 28 insertions(+), 22 deletions(-) diff --git a/src/comobjects.rs b/src/comobjects.rs index 1094238..d26b1a8 100644 --- a/src/comobjects.rs +++ b/src/comobjects.rs @@ -189,7 +189,7 @@ pub struct ComObjects { view_collection: RefCell>>, } -fn retry_function(com_objects: &ComObjects, f: F, fn_name: &str) -> Result +fn retry_function(com_objects: &ComObjects, f: F, _fn_name: &str) -> Result where F: Fn() -> Result, { @@ -203,8 +203,7 @@ where || er == &Error::ComAllocatedNullPtr || er == &Error::ComNotInitialized => { - #[cfg(debug_assertions)] - log_output(&format!("Retry the function \"{fn_name}\" after {:?}", er)); + log_format!("Retry the function \"{_fn_name}\" after {:?}", er); if er == &Error::ComNotInitialized { let _ = unsafe { CoIncrementMTAUsage() }; @@ -226,10 +225,10 @@ where #[cfg(debug_assertions)] if let Err(er) = &value { - log_output(&format!( - "Com_objects function \"{fn_name}\" failed with {:?}", + log_format!( + "Com_objects function \"{_fn_name}\" failed with {:?}", er - )); + ); } value diff --git a/src/events.rs b/src/events.rs index 6e5fd9d..4b3ea6d 100644 --- a/src/events.rs +++ b/src/events.rs @@ -100,9 +100,9 @@ pub enum DesktopEvent { /// /// # Example /// -/// ```rust -/// let (tx, rx) = std::sync::mpsc::channel::(); -/// let _notifications_thread = listen_desktop_events(tx); +/// ```rust,no_run +/// let (tx, rx) = std::sync::mpsc::channel::(); +/// let _notifications_thread = winvd::listen_desktop_events(tx); /// // Do with receiver something /// for item in rx { /// println!("{:?}", item); diff --git a/src/interfaces.rs b/src/interfaces.rs index 8eac1b8..d2aac43 100644 --- a/src/interfaces.rs +++ b/src/interfaces.rs @@ -57,7 +57,7 @@ use windows::{ /// /// E.g. /// -/// ```rust +/// ```rust,ignore /// fn get_current_desktop(&mut self, desktop: &mut Option) -> HRESULT; /// fn switch_desktop(&self, desktop: ManuallyDrop) -> HRESULT; /// @@ -72,7 +72,7 @@ use windows::{ /// /// To make things safer and easier to use, ComIn is used instead. /// -/// ```rust +/// ```rust,ignore /// fn get_current_desktop(&mut self, desktop: &mut Option) -> HRESULT; /// fn switch_desktop(&self, desktop: ComIn) -> HRESULT; /// diff --git a/src/interfaces_multi.rs b/src/interfaces_multi.rs index fea70b6..ba8e1d6 100644 --- a/src/interfaces_multi.rs +++ b/src/interfaces_multi.rs @@ -163,7 +163,7 @@ unsafe impl PointerRepr for T { /// /// E.g. /// -/// ```rust +/// ```rust,ignore /// fn get_current_desktop(&mut self, desktop: &mut Option) -> HRESULT; /// fn switch_desktop(&self, desktop: ManuallyDrop) -> HRESULT; /// @@ -178,7 +178,7 @@ unsafe impl PointerRepr for T { /// /// To make things safer and easier to use, ComIn is used instead. /// -/// ```rust +/// ```rust,ignore /// fn get_current_desktop(&mut self, desktop: &mut Option) -> HRESULT; /// fn switch_desktop(&self, desktop: ComIn) -> HRESULT; /// diff --git a/src/tests.rs b/src/tests.rs index f4330d4..d1318d1 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,6 +1,6 @@ use super::*; use once_cell::sync::Lazy; -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Mutex, PoisonError}; use std::thread; use std::time::Duration; use windows::core::PCWSTR; @@ -12,9 +12,9 @@ static SEMAPHORE: Lazy>> = Lazy::new(|| Arc::new(Mutex::new(0))); // Run the tests synchronously pub fn sync_test(test: T) where - T: FnOnce() -> (), + T: FnOnce(), { - let mut tests_ran = SEMAPHORE.lock().unwrap(); + let mut tests_ran = SEMAPHORE.lock().unwrap_or_else(PoisonError::into_inner); test(); *tests_ran += 1; drop(tests_ran); @@ -24,7 +24,7 @@ where fn test_desktop_get() { sync_test(|| { let desktop = get_desktop(0).get_id().unwrap(); - get_desktop(&desktop).get_index().unwrap(); + get_desktop(desktop).get_index().unwrap(); }) } @@ -292,17 +292,24 @@ fn test_threads() { // }; let mut threads = vec![]; for _ in 0..555 { - threads.push(std::thread::spawn(|| { - get_desktops().unwrap().iter().for_each(|d| { - let _n = d.get_name().unwrap(); + threads.push(std::thread::spawn(|| -> bool { + for d in get_desktops().unwrap() { + let _n = match d.get_name() { + Ok(n) => n, + Err(Error::ComNotImplemented) => return true, + Err(e) => panic!("Failed to get name of desktop: {e:?}"), + }; let _i = d.get_index().unwrap(); // println!("Thread {n} {i} {:?}", std::thread::current().id()); - }) + } + false })); } thread::sleep(Duration::from_millis(150)); for t in threads { - t.join().unwrap(); + if t.join().unwrap() { + panic!("Failed to get name of desktop because that feature wasn't implemented on current Windows version"); + } } }) } From 8936e7a42327c1e3de28e8a52ede54d62d0eefd5 Mon Sep 17 00:00:00 2001 From: Lej77 <31554212+Lej77@users.noreply.github.com> Date: Tue, 2 Apr 2024 17:32:03 +0200 Subject: [PATCH 09/11] refactor: simplify specialization for certain WIndows versions --- src/interfaces_multi.rs | 2 +- src/interfaces_multi/build_19045.rs | 2 + src/interfaces_multi/build_20348.rs | 42 +++++- src/interfaces_multi/build_22000.rs | 52 ++++++- src/interfaces_multi/build_dyn.rs | 222 ++++------------------------ 5 files changed, 117 insertions(+), 203 deletions(-) diff --git a/src/interfaces_multi.rs b/src/interfaces_multi.rs index ba8e1d6..2762099 100644 --- a/src/interfaces_multi.rs +++ b/src/interfaces_multi.rs @@ -65,7 +65,7 @@ declare_versions!( mod build_22621_2215; // Interface change mod build_22621_3155; // IID change mod build_22631_2428; // IID change - mod build_22631_3155; + mod build_22631_3155; // IID change ); mod build_dyn; diff --git a/src/interfaces_multi/build_19045.rs b/src/interfaces_multi/build_19045.rs index 36f6bd3..57ee182 100644 --- a/src/interfaces_multi/build_19045.rs +++ b/src/interfaces_multi/build_19045.rs @@ -1,3 +1,5 @@ +//! Windows 10 + use super::*; use build_10240 as prev_build; diff --git a/src/interfaces_multi/build_20348.rs b/src/interfaces_multi/build_20348.rs index 2fc8871..a8bd97d 100644 --- a/src/interfaces_multi/build_20348.rs +++ b/src/interfaces_multi/build_20348.rs @@ -45,7 +45,7 @@ reusable_com_interface!( }, { pub unsafe trait IVirtualDesktopManagerInternal: IUnknown { - pub unsafe fn get_desktop_count( + pub unsafe fn get_desktop_count_m( &self, monitor: HMONITOR, out_count: *mut UINT, @@ -63,13 +63,13 @@ reusable_com_interface!( can_move: *mut i32, ) -> HRESULT; - pub unsafe fn get_current_desktop( + pub unsafe fn get_current_desktop_m( &self, monitor: HMONITOR, out_desktop: *mut Option, ) -> HRESULT; - pub unsafe fn get_desktops( + pub unsafe fn get_desktops_m( &self, monitor: HMONITOR, out_desktops: *mut Option, @@ -87,13 +87,13 @@ reusable_com_interface!( out_pp_desktop: *mut Option, ) -> HRESULT; - pub unsafe fn switch_desktop( + pub unsafe fn switch_desktop_m( &self, monitor: HMONITOR, desktop: ComIn, ) -> HRESULT; - pub unsafe fn create_desktop( + pub unsafe fn create_desktop_m( &self, monitor: HMONITOR, out_desktop: *mut Option, @@ -134,6 +134,38 @@ reusable_com_interface!( pub unsafe fn get_desktop_is_per_monitor(&self, out_per_monitor: *mut i32) -> HRESULT; } + impl IVirtualDesktopManagerInternal { + pub unsafe fn get_desktop_count(&self, out_count: *mut UINT) -> HRESULT { + self.get_desktop_count_m(0, out_count) + } + pub unsafe fn get_current_desktop( + &self, + out_desktop: *mut Option, + ) -> HRESULT { + self.get_current_desktop_m(0, out_desktop) + } + + pub unsafe fn get_desktops( + &self, + out_desktops: *mut Option, + ) -> HRESULT { + self.get_desktops_m(0, out_desktops) + } + + pub unsafe fn switch_desktop( + &self, + desktop: ComIn, + ) -> HRESULT { + self.switch_desktop_m(0, desktop) + } + + pub unsafe fn create_desktop( + &self, + out_desktop: *mut Option, + ) -> HRESULT { + self.create_desktop_m(0, out_desktop) + } + } } ); diff --git a/src/interfaces_multi/build_22000.rs b/src/interfaces_multi/build_22000.rs index 8495d1e..ae39a29 100644 --- a/src/interfaces_multi/build_22000.rs +++ b/src/interfaces_multi/build_22000.rs @@ -41,7 +41,7 @@ reusable_com_interface!( }, { pub unsafe trait IVirtualDesktopManagerInternal: IUnknown { - pub unsafe fn get_desktop_count( + pub unsafe fn get_desktop_count_m( &self, monitor: HMONITOR, out_count: *mut UINT, @@ -59,7 +59,7 @@ reusable_com_interface!( can_move: *mut i32, ) -> HRESULT; - pub unsafe fn get_current_desktop( + pub unsafe fn get_current_desktop_m( &self, monitor: HMONITOR, out_desktop: *mut Option, @@ -70,7 +70,7 @@ reusable_com_interface!( out_desktops: *mut Option, ) -> HRESULT; - pub unsafe fn get_desktops( + pub unsafe fn get_desktops_m( &self, monitor: HMONITOR, out_desktops: *mut Option, @@ -88,19 +88,19 @@ reusable_com_interface!( out_pp_desktop: *mut Option, ) -> HRESULT; - pub unsafe fn switch_desktop( + pub unsafe fn switch_desktop_m( &self, monitor: HMONITOR, desktop: ComIn, ) -> HRESULT; - pub unsafe fn create_desktop( + pub unsafe fn create_desktop_m( &self, monitor: HMONITOR, out_desktop: *mut Option, ) -> HRESULT; - pub unsafe fn move_desktop( + pub unsafe fn move_desktop_m( &self, in_desktop: ComIn, monitor: HMONITOR, @@ -148,6 +148,46 @@ reusable_com_interface!( pub unsafe fn set_desktop_is_per_monitor(&self, per_monitor: i32) -> HRESULT; } + impl IVirtualDesktopManagerInternal { + pub unsafe fn get_desktop_count(&self, out_count: *mut UINT) -> HRESULT { + self.get_desktop_count_m(0, out_count) + } + pub unsafe fn get_current_desktop( + &self, + out_desktop: *mut Option, + ) -> HRESULT { + self.get_current_desktop_m(0, out_desktop) + } + + pub unsafe fn get_desktops( + &self, + out_desktops: *mut Option, + ) -> HRESULT { + self.get_desktops_m(0, out_desktops) + } + + pub unsafe fn switch_desktop( + &self, + desktop: ComIn, + ) -> HRESULT { + self.switch_desktop_m(0, desktop) + } + + pub unsafe fn create_desktop( + &self, + out_desktop: *mut Option, + ) -> HRESULT { + self.create_desktop_m(0, out_desktop) + } + + pub unsafe fn move_desktop( + &self, + in_desktop: ComIn, + index: UINT, + ) -> HRESULT { + self.move_desktop_m(in_desktop, 0, index) + } + } } ); diff --git a/src/interfaces_multi/build_dyn.rs b/src/interfaces_multi/build_dyn.rs index d45decf..5b0aa93 100644 --- a/src/interfaces_multi/build_dyn.rs +++ b/src/interfaces_multi/build_dyn.rs @@ -34,15 +34,15 @@ macro_rules! declare_WindowsVersion { } } } - impl Default for WindowsVersion { - fn default() -> Self { - *Self::ALL.last().expect("No Windows version is supported") - } - } }; } with_versions!(declare_WindowsVersion); +impl Default for WindowsVersion { + fn default() -> Self { + *Self::ALL.last().expect("No Windows version is supported") + } +} // Check that the versions are sorted when they were declared, this is a bit // slow currently so it has been disabled: // impl WindowsVersion { @@ -154,7 +154,11 @@ impl WindowsVersion { .max_by_key(|(_, version)| *version) .map(|(v, _)| v) .unwrap_or_default(); - log_format!("Using COM interfaces for Windows version: {latest_supported:?}"); + log_format!( + "Using COM interfaces for Windows version: {latest_supported:?} \ + (Detected Windows version was: {:?}.{:?}.{:?})", + version.dwMajorVersion, version.dwMinorVersion, version.dwBuildNumber + ); latest_supported }) } @@ -264,7 +268,7 @@ macro_rules! support_interface { /// The IID for the COM interface that is supported by this /// platform, return a zeroed GUID if the interface isn't supported. #[allow(non_snake_case, unreachable_patterns)] - pub unsafe fn IID() -> GUID { + pub fn IID() -> GUID { match WindowsVersion::get() { $(WindowsVersion::$version => self::$version::$name::IID,)* _ => GUID::zeroed(), @@ -497,36 +501,9 @@ macro_rules! support_interface { /// Implement a method by calling the same method on the Windows version /// dependant COM interface. macro_rules! forward_call { - ( - #[forward_for = $name:ident] - $( #[$attr:meta] )* - $pub:vis - $(unsafe $(@ $unsafe:tt)?)? - fn $fname:ident ( - &$self_:ident $(,)? $( $arg_name:ident : $ArgTy:ty ),* $(,)? - ) -> $RetTy:ty; - ) => ( - $( #[$attr] )* - #[allow(unused_parens)] - $pub - $(unsafe $($unsafe)?)? - fn $fname ( - &$self_, $( $arg_name : $ArgTy ),* - ) -> $RetTy - { - unsafe { - $name!( - $self_, - |v| (*v).$fname( $( - ForwardArg::forward($arg_name) - ),*) - ) - } - } - ); // No function body => forward the call automatically (sometimes not // implemented for the versioned interface): - (@item + ( #[forward_for = $name:ident] #[optional_method] $( #[$attr:meta] )* @@ -563,6 +540,8 @@ macro_rules! forward_call { unsafe { $name!( $self_, + // Note: important to deref here otherwise we would call the + // fallback method on the `InCom` wrapper |v| (*v).$fname( $( ForwardArg::forward($arg_name) ),*) @@ -571,7 +550,7 @@ macro_rules! forward_call { } }; // No function body => forward the call automatically: - (@item + ( #[forward_for = $name:ident] $( #[$attr:meta] )* $pub:vis @@ -598,8 +577,8 @@ macro_rules! forward_call { } } }; - // Manual body implementation: - (@item + // Manual body implementation (leave it unchanged): + ( #[forward_for = $name:ident] $( #[$attr:meta] )* $pub:vis @@ -619,6 +598,7 @@ macro_rules! forward_call { ) -> $RetTy { $($body)* } }; + // Apply forward_call to all items in a trait: ( $( #[$attr_impl:meta] )* impl $name:ident { @@ -636,7 +616,7 @@ macro_rules! forward_call { $(#[$attr_impl])* impl $name { $( - forward_call! {@item + forward_call! { #[forward_for = $name] $(#[$($attr_item)*])* $pub @@ -867,12 +847,16 @@ support_interface!(MacroOptions { enum_name: IVirtualDesktopNotificationInner, all_versions: true, }); - +/// Create a [`IVirtualDesktopNotification`] from any type that implements its +/// interface using [`IVirtualDesktopNotification_Impl`]. impl From for IVirtualDesktopNotification where T: IVirtualDesktopNotification_Impl, { fn from(value: T) -> Self { + // Each Windows version has a unique "adaptor" type that implements its + // COM interface by delegating to any type that implements the shared + // IVirtualDesktopNotification_Impl trait. macro_rules! get_adaptor { (versions = {$($version:ident,)*},) => { match WindowsVersion::get() { @@ -988,30 +972,7 @@ support_interface!(MacroOptions { #[apply(forward_call)] impl IVirtualDesktopManagerInternal { - pub unsafe fn get_desktop_count(&self, out_count: *mut UINT) -> HRESULT { - struct Specialize(T); - impl Specialize<&build_20348::IVirtualDesktopManagerInternal> { - unsafe fn get_desktop_count(&self, out_count: *mut UINT) -> HRESULT { - self.0.get_desktop_count(0, out_count) - } - } - impl Specialize<&build_22000::IVirtualDesktopManagerInternal> { - unsafe fn get_desktop_count(&self, out_count: *mut UINT) -> HRESULT { - self.0.get_desktop_count(0, out_count) - } - } - // The compiler prefers inherit methods and only derefs if no such - // method can be found. - impl core::ops::Deref for Specialize { - type Target = T; - fn deref(&self) -> &T { - &self.0 - } - } - IVirtualDesktopManagerInternal!(self, |this: version::Versioned| { - Specialize(&*this).get_desktop_count(out_count) - }) - } + pub unsafe fn get_desktop_count(&self, out_count: *mut UINT) -> HRESULT; pub unsafe fn move_view_to_desktop( &self, @@ -1025,55 +986,9 @@ impl IVirtualDesktopManagerInternal { can_move: *mut i32, ) -> HRESULT; - pub unsafe fn get_current_desktop(&self, out_desktop: *mut Option) -> HRESULT { - struct Specialize(T); - impl Specialize<&build_20348::IVirtualDesktopManagerInternal> { - unsafe fn get_current_desktop(&self, out_desktop: *mut Option) -> HRESULT { - self.0.get_current_desktop(0, out_desktop.forward()) - } - } - impl Specialize<&build_22000::IVirtualDesktopManagerInternal> { - unsafe fn get_current_desktop(&self, out_desktop: *mut Option) -> HRESULT { - self.0.get_current_desktop(0, out_desktop.forward()) - } - } - // The compiler prefers inherit methods and only derefs if no such - // method can be found. - impl core::ops::Deref for Specialize { - type Target = T; - fn deref(&self) -> &T { - &self.0 - } - } - IVirtualDesktopManagerInternal!(self, |this: version::Versioned| { - Specialize(&*this).get_current_desktop(out_desktop.forward()) - }) - } + pub unsafe fn get_current_desktop(&self, out_desktop: *mut Option) -> HRESULT; - pub unsafe fn get_desktops(&self, out_desktops: *mut Option) -> HRESULT { - struct Specialize(T); - impl Specialize<&build_20348::IVirtualDesktopManagerInternal> { - unsafe fn get_desktops(&self, out_desktops: *mut Option) -> HRESULT { - self.0.get_desktops(0, out_desktops) - } - } - impl Specialize<&build_22000::IVirtualDesktopManagerInternal> { - unsafe fn get_desktops(&self, out_desktops: *mut Option) -> HRESULT { - self.0.get_desktops(0, out_desktops) - } - } - // The compiler prefers inherit methods and only derefs if no such - // method can be found. - impl core::ops::Deref for Specialize { - type Target = T; - fn deref(&self) -> &T { - &self.0 - } - } - IVirtualDesktopManagerInternal!(self, |this: version::Versioned| { - Specialize(&*this).get_desktops(out_desktops) - }) - } + pub unsafe fn get_desktops(&self, out_desktops: *mut Option) -> HRESULT; /// Get next or previous desktop /// @@ -1087,87 +1002,12 @@ impl IVirtualDesktopManagerInternal { out_pp_desktop: *mut Option, ) -> HRESULT; - pub unsafe fn switch_desktop(&self, desktop: ComIn) -> HRESULT { - struct Specialize(T); - impl Specialize<&build_20348::IVirtualDesktopManagerInternal> { - unsafe fn switch_desktop(&self, desktop: ComIn) -> HRESULT { - self.0.switch_desktop(0, desktop.forward()) - } - } - impl Specialize<&build_22000::IVirtualDesktopManagerInternal> { - unsafe fn switch_desktop(&self, desktop: ComIn) -> HRESULT { - self.0.switch_desktop(0, desktop.forward()) - } - } - // The compiler prefers inherit methods and only derefs if no such - // method can be found. - impl core::ops::Deref for Specialize { - type Target = T; - fn deref(&self) -> &T { - &self.0 - } - } - IVirtualDesktopManagerInternal!(self, |this: version::Versioned| { - Specialize(&*this).switch_desktop(desktop.forward()) - }) - } + pub unsafe fn switch_desktop(&self, desktop: ComIn) -> HRESULT; - pub unsafe fn create_desktop(&self, out_desktop: *mut Option) -> HRESULT { - struct Specialize(T); - impl Specialize<&build_20348::IVirtualDesktopManagerInternal> { - unsafe fn create_desktop(&self, out_desktop: *mut Option) -> HRESULT { - self.0.create_desktop(0, out_desktop.forward()) - } - } - impl Specialize<&build_22000::IVirtualDesktopManagerInternal> { - unsafe fn create_desktop(&self, out_desktop: *mut Option) -> HRESULT { - self.0.create_desktop(0, out_desktop.forward()) - } - } - // The compiler prefers inherit methods and only derefs if no such - // method can be found. - impl core::ops::Deref for Specialize { - type Target = T; - fn deref(&self) -> &T { - &self.0 - } - } - IVirtualDesktopManagerInternal!(self, |this: version::Versioned| { - Specialize(&*this).create_desktop(out_desktop.forward()) - }) - } + pub unsafe fn create_desktop(&self, out_desktop: *mut Option) -> HRESULT; - pub unsafe fn move_desktop(&self, in_desktop: ComIn, index: UINT) -> HRESULT { - struct Specialize(T); - impl Specialize<&build_22000::IVirtualDesktopManagerInternal> { - unsafe fn move_desktop(&self, in_desktop: ComIn, index: UINT) -> HRESULT { - self.0.move_desktop(in_desktop.forward(), 0, index) - } - } - // The compiler prefers inherit methods and only derefs if no such - // method can be found. - impl core::ops::Deref for Specialize { - type Target = T; - fn deref(&self) -> &T { - &self.0 - } - } - - trait __FallbackNotImpl { - unsafe fn move_desktop(&self, in_desktop: ComIn, index: UINT) -> HRESULT; - } - - IVirtualDesktopManagerInternal!(self, |this: version::Versioned| { - // Only uses trait methods if there aren't any inherent methods - impl __FallbackNotImpl for Versioned { - unsafe fn move_desktop(&self, _: ComIn, _: UINT) -> HRESULT { - E_NOTIMPL - } - } - - Specialize(&*this).move_desktop(in_desktop.forward(), index) - }) - } + #[optional_method] + pub unsafe fn move_desktop(&self, in_desktop: ComIn, index: UINT) -> HRESULT; pub unsafe fn remove_desktop( &self, From c6b3b0c0dbf66ebefe551d93b1aad04a7e26a82f Mon Sep 17 00:00:00 2001 From: Lej77 <31554212+Lej77@users.noreply.github.com> Date: Tue, 2 Apr 2024 20:22:27 +0200 Subject: [PATCH 10/11] feat: detect Windows patch version using the registry --- Cargo.toml | 1 + src/interfaces_multi/build_dyn.rs | 69 +++++++++++++++++++++++++++---- 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 44d210c..1814c3b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,7 @@ integration-tests = [] multiple-windows-versions = [ "windows/Win32_System_SystemInformation", # For RtlGetVersion return type "windows/Wdk_System_SystemServices", # For RtlGetVersion + "windows/Win32_System_Registry", # For RegGetValueW ] [package.metadata.docs.rs] diff --git a/src/interfaces_multi/build_dyn.rs b/src/interfaces_multi/build_dyn.rs index 5b0aa93..9904ef4 100644 --- a/src/interfaces_multi/build_dyn.rs +++ b/src/interfaces_multi/build_dyn.rs @@ -79,7 +79,9 @@ impl Default for WindowsVersion { // } // } impl WindowsVersion { - fn windows_build(&self) -> (u32, u32) { + /// Returns the Windows build and Windows patch that a Rust module with COM + /// interfaces supports. (It might support some later versions as well.) + fn windows_version(&self) -> (u32, u32) { let (_, version) = self .as_str() .split_once('_') @@ -96,6 +98,49 @@ impl WindowsVersion { .expect("Failed to parse module suffix as patch version"), ) } + /// Get the Windows patch version (the last number in the full version). + /// + /// # References + /// + /// - This is how the C# VirtualDesktop library does it: [VirtualDesktop/src/VirtualDesktop/Utils/OS.cs at 7e37b9848aef681713224dae558d2e51960cf41e · mzomparelli/VirtualDesktop](https://github.com/mzomparelli/VirtualDesktop/blob/7e37b9848aef681713224dae558d2e51960cf41e/src/VirtualDesktop/Utils/OS.cs#L21) + /// - We use this function: [RegGetValueW in windows::Win32::System::Registry - Rust](https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/System/Registry/fn.RegGetValueW.html) + /// - Function docs: [RegGetValueW function (winreg.h) - Win32 apps | Microsoft Learn](https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-reggetvaluew) + /// - StackOverflow usage example: [windows - RegGetValueW(), how to do it right - Stack Overflow](https://stackoverflow.com/questions/78224404/reggetvaluew-how-to-do-it-right) + /// - Info about the registry key: [.net - C# - How to show the full Windows 10 build number? - Stack Overflow](https://stackoverflow.com/questions/52041735/c-sharp-how-to-show-the-full-windows-10-build-number) + fn read_patch_version_from_registry() -> Option { + use windows::{ + core::w, + Win32::System::Registry::{RegGetValueW, HKEY_LOCAL_MACHINE, RRF_RT_REG_DWORD}, + }; + + let mut buffer: [u8; 4] = [0; 4]; + let mut cb_data = buffer.len() as u32; + let res = unsafe { + RegGetValueW( + HKEY_LOCAL_MACHINE, + w!(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#), + w!("UBR"), + RRF_RT_REG_DWORD, + Some(std::ptr::null_mut()), + Some(buffer.as_mut_ptr() as _), + Some(&mut cb_data as *mut u32), + ) + }; + if let Err(e) = res { + log_format!("Failed to read Windows patch version from the registry: {e:?}"); + return None; + } + + // REG_DWORD is signed 32-bit, using little endian + let patch_version = i32::from_le_bytes(buffer); + if patch_version < 0 { + log_format!( + "Windows patch version read from the registry was negative \ + ({patch_version}), ignoring read value" + ); + } + u32::try_from(patch_version).ok() + } /// Get info about the current Windows version. Only differentiates between /// Windows versions that have different virtual desktop interfaces. /// @@ -143,21 +188,29 @@ impl WindowsVersion { ); return Default::default(); } - // FIXME: we don't get the patch version of Windows and just assume the user is on the latest one. + let patch_version = Self::read_patch_version_from_registry(); let latest_supported = Self::ALL .iter() .copied() - .map(|v| (v, v.windows_build())) - // Only consider COM interfaces from previous or current build: - .filter(|(_, (build, _patch))| *build <= version.dwBuildNumber) + .map(|v| (v, v.windows_version())) + // Only consider COM interfaces from previous or current Windows version: + .filter(|(_, full_ver)| { + *full_ver <= (version.dwBuildNumber, patch_version.unwrap_or(u32::MAX)) + }) // Then find the latest one: .max_by_key(|(_, version)| *version) .map(|(v, _)| v) .unwrap_or_default(); log_format!( "Using COM interfaces for Windows version: {latest_supported:?} \ - (Detected Windows version was: {:?}.{:?}.{:?})", - version.dwMajorVersion, version.dwMinorVersion, version.dwBuildNumber + (Detected Windows version was: {}.{}.{}.{})", + version.dwMajorVersion, + version.dwMinorVersion, + version.dwBuildNumber, + match patch_version { + Some(v) => v.to_string(), + None => "N/A".to_owned(), + } ); latest_supported }) @@ -868,7 +921,7 @@ where } }; } - super::with_versions!{get_adaptor} + super::with_versions! {get_adaptor} } } #[allow(non_camel_case_types)] From 126b9e04f4f01d434af06c20d8200d0659547774 Mon Sep 17 00:00:00 2001 From: Jari Pennanen Date: Thu, 9 May 2024 15:43:45 +0300 Subject: [PATCH 11/11] Update windows-rs --- Cargo.lock | 438 +++++++++++++++++++++++++++++++++++++++------- Cargo.toml | 11 +- src/comobjects.rs | 1 - src/interfaces.rs | 8 +- 4 files changed, 384 insertions(+), 74 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c1f2cbe..8b10a22 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,9 +20,9 @@ checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" [[package]] name = "ahash" -version = "0.8.6" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "getrandom", @@ -45,9 +45,30 @@ dependencies = [ "jni-sys", "libc", "log", - "ndk", + "ndk 0.8.0", "ndk-context", - "ndk-sys", + "ndk-sys 0.5.0+25.2.9519653", + "num_enum", + "thiserror", +] + +[[package]] +name = "android-activity" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" +dependencies = [ + "android-properties", + "bitflags 2.4.1", + "cc", + "cesu8", + "jni", + "jni-sys", + "libc", + "log", + "ndk 0.9.0", + "ndk-context", + "ndk-sys 0.6.0+11769913", "num_enum", "thiserror", ] @@ -116,7 +137,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15b55663a85f33501257357e6421bb33e769d5c9ffb5ba0921c975a123e35e68" dependencies = [ "block-sys", - "objc2", + "objc2 0.4.1", +] + +[[package]] +name = "block2" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43ff7d91d3c1d568065b06c899777d1e48dcf76103a672a0adbc238a7f247f1e" +dependencies = [ + "objc2 0.5.1", ] [[package]] @@ -191,6 +221,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +[[package]] +name = "cfg_aliases" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e53693616d3075149f4ead59bdeecd204ac6b8192d8969757601b74bddf00f" + [[package]] name = "combine" version = "4.6.6" @@ -296,7 +332,7 @@ version = "0.1.0" dependencies = [ "crossbeam-channel", "once_cell", - "windows", + "windows 0.52.0", "winvd", ] @@ -306,6 +342,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" +[[package]] +name = "dpi" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" + [[package]] name = "equivalent" version = "1.0.1" @@ -359,6 +401,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "gethostname" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" +dependencies = [ + "libc", + "windows-targets 0.48.5", +] + [[package]] name = "getrandom" version = "0.2.11" @@ -382,9 +434,9 @@ version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d3aaff8a54577104bafdf686ff18565c3b6903ca5782a2026ef06e2c7aa319" dependencies = [ - "block2", + "block2 0.3.0", "dispatch", - "objc2", + "objc2 0.4.1", ] [[package]] @@ -541,7 +593,22 @@ dependencies = [ "bitflags 2.4.1", "jni-sys", "log", - "ndk-sys", + "ndk-sys 0.5.0+25.2.9519653", + "num_enum", + "raw-window-handle", + "thiserror", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.4.1", + "jni-sys", + "log", + "ndk-sys 0.6.0+11769913", "num_enum", "raw-window-handle", "thiserror", @@ -562,6 +629,15 @@ dependencies = [ "jni-sys", ] +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys", +] + [[package]] name = "nix" version = "0.26.4" @@ -607,9 +683,9 @@ dependencies = [ [[package]] name = "objc-sys" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e1d07c6eab1ce8b6382b8e3c7246fe117ff3f8b34be065f5ebace6749fe845" +checksum = "da284c198fb9b7b0603f8635185e85fbd5b64ee154b1ed406d489077de2d6d60" [[package]] name = "objc2" @@ -618,7 +694,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "559c5a40fdd30eb5e344fbceacf7595a81e242529fb4e21cf5f43fb4f11ff98d" dependencies = [ "objc-sys", - "objc2-encode", + "objc2-encode 3.0.0", +] + +[[package]] +name = "objc2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b25e1034d0e636cd84707ccdaa9f81243d399196b8a773946dcffec0401659" +dependencies = [ + "objc-sys", + "objc2-encode 4.0.1", +] + +[[package]] +name = "objc2-app-kit" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb79768a710a9a1798848179edb186d1af7e8a8679f369e4b8d201dd2a034047" +dependencies = [ + "block2 0.5.0", + "objc2 0.5.1", + "objc2-core-data", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-data" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e092bc42eaf30a08844e6a076938c60751225ec81431ab89f5d1ccd9f958d6c" +dependencies = [ + "block2 0.5.0", + "objc2 0.5.1", + "objc2-foundation", ] [[package]] @@ -627,11 +736,28 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666" +[[package]] +name = "objc2-encode" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88658da63e4cc2c8adb1262902cd6af51094df0488b760d6fd27194269c0950a" + +[[package]] +name = "objc2-foundation" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfaefe14254871ea16c7d88968c0ff14ba554712a20d76421eec52f0a7fb8904" +dependencies = [ + "block2 0.5.0", + "dispatch", + "objc2 0.5.1", +] + [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "orbclient" @@ -663,6 +789,26 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -790,6 +936,19 @@ dependencies = [ "tiny-skia", ] +[[package]] +name = "sctk-adwaita" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7de61fa7334ee8ee1f5c3c58dcc414fb9361e7e8f5bff9d45f4d69eeb89a7169" +dependencies = [ + "ab_glyph", + "log", + "memmap2", + "smithay-client-toolkit", + "tiny-skia", +] + [[package]] name = "serde" version = "1.0.192" @@ -881,7 +1040,7 @@ name = "testbin" version = "0.0.1" dependencies = [ "once_cell", - "winit", + "winit 0.29.3", "winvd", ] @@ -1198,6 +1357,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" @@ -1244,10 +1413,20 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ - "windows-core", - "windows-implement", - "windows-interface", - "windows-targets 0.52.0", + "windows-core 0.52.0", + "windows-implement 0.52.0", + "windows-interface 0.52.0", + "windows-targets 0.52.5", +] + +[[package]] +name = "windows" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1de69df01bdf1ead2f4ac895dc77c9351aefff65b2f3db429a343f9cbf05e132" +dependencies = [ + "windows-core 0.56.0", + "windows-targets 0.52.5", ] [[package]] @@ -1256,7 +1435,19 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.5", +] + +[[package]] +name = "windows-core" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4698e52ed2d08f8658ab0c39512a7c00ee5fe2688c65f8c0a4f06750d729f2a6" +dependencies = [ + "windows-implement 0.56.0", + "windows-interface 0.56.0", + "windows-result", + "windows-targets 0.52.5", ] [[package]] @@ -1270,6 +1461,17 @@ dependencies = [ "syn", ] +[[package]] +name = "windows-implement" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "windows-interface" version = "0.52.0" @@ -1281,6 +1483,26 @@ dependencies = [ "syn", ] +[[package]] +name = "windows-interface" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-result" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "749f0da9cc72d82e600d8d2e44cadd0b9eedb9038f71a1c58556ac1c5791813b" +dependencies = [ + "windows-targets 0.52.5", +] + [[package]] name = "windows-sys" version = "0.45.0" @@ -1299,6 +1521,15 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.5", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -1331,17 +1562,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -1358,9 +1590,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -1376,9 +1608,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -1394,9 +1626,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -1412,9 +1650,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -1430,9 +1668,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" @@ -1448,9 +1686,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -1466,9 +1704,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winit" @@ -1477,12 +1715,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "161598019a9da35ab6c34dc46cd13546cba9dbf9816475d4dd9a639455016563" dependencies = [ "ahash", - "android-activity", + "android-activity 0.5.0", "atomic-waker", "bitflags 2.4.1", "bytemuck", "calloop", - "cfg_aliases", + "cfg_aliases 0.1.1", "core-foundation", "core-graphics", "cursor-icon", @@ -1491,16 +1729,16 @@ dependencies = [ "libc", "log", "memmap2", - "ndk", - "ndk-sys", - "objc2", + "ndk 0.8.0", + "ndk-sys 0.5.0+25.2.9519653", + "objc2 0.4.1", "once_cell", "orbclient", "percent-encoding", "raw-window-handle", "redox_syscall 0.3.5", "rustix", - "sctk-adwaita", + "sctk-adwaita 0.7.0", "smithay-client-toolkit", "smol_str", "unicode-segmentation", @@ -1511,10 +1749,60 @@ dependencies = [ "wayland-protocols", "wayland-protocols-plasma", "web-sys", - "web-time", + "web-time 0.2.3", "windows-sys 0.48.0", "x11-dl", - "x11rb", + "x11rb 0.12.0", + "xkbcommon-dl", +] + +[[package]] +name = "winit" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea9e6d5d66cbf702e0dd820302144f51b69a95acdc495dd98ca280ff206562b1" +dependencies = [ + "ahash", + "android-activity 0.6.0", + "atomic-waker", + "bitflags 2.4.1", + "bytemuck", + "calloop", + "cfg_aliases 0.2.0", + "concurrent-queue", + "core-foundation", + "core-graphics", + "cursor-icon", + "dpi", + "js-sys", + "libc", + "memmap2", + "ndk 0.9.0", + "objc2 0.5.1", + "objc2-app-kit", + "objc2-foundation", + "orbclient", + "percent-encoding", + "pin-project", + "raw-window-handle", + "redox_syscall 0.4.1", + "rustix", + "sctk-adwaita 0.9.0", + "smithay-client-toolkit", + "smol_str", + "tracing", + "unicode-segmentation", + "wasm-bindgen", + "wasm-bindgen-futures", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-protocols-plasma", + "web-sys", + "web-time 1.1.0", + "windows-sys 0.52.0", + "x11-dl", + "x11rb 0.13.1", "xkbcommon-dl", ] @@ -1529,15 +1817,16 @@ dependencies = [ [[package]] name = "winvd" -version = "0.0.46" +version = "0.0.47" dependencies = [ "crossbeam-channel", "macro_rules_attribute", "once_cell", - "windows", - "windows-implement", - "windows-interface", - "winit", + "windows 0.56.0", + "windows-core 0.56.0", + "windows-implement 0.56.0", + "windows-interface 0.56.0", + "winit 0.30.0", ] [[package]] @@ -1558,14 +1847,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1641b26d4dec61337c35a1b1aaf9e3cba8f46f0b43636c609ab0291a648040a" dependencies = [ "as-raw-xcb-connection", - "gethostname", + "gethostname 0.3.0", "libc", "libloading 0.7.4", "nix", "once_cell", "winapi", "winapi-wsapoll", - "x11rb-protocol", + "x11rb-protocol 0.12.0", +] + +[[package]] +name = "x11rb" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" +dependencies = [ + "as-raw-xcb-connection", + "gethostname 0.4.3", + "libc", + "libloading 0.8.1", + "once_cell", + "rustix", + "x11rb-protocol 0.13.1", ] [[package]] @@ -1577,6 +1881,12 @@ dependencies = [ "nix", ] +[[package]] +name = "x11rb-protocol" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" + [[package]] name = "xcursor" version = "0.3.4" @@ -1588,9 +1898,9 @@ dependencies = [ [[package]] name = "xkbcommon-dl" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6924668544c48c0133152e7eec86d644a056ca3d09275eb8d5cdb9855f9d8699" +checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ "bitflags 2.4.1", "dlib", @@ -1607,18 +1917,18 @@ checksum = "054a8e68b76250b253f671d1268cb7f1ae089ec35e195b2efb2a4e9a836d0621" [[package]] name = "zerocopy" -version = "0.7.25" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd369a67c0edfef15010f980c3cbe45d7f651deac2cd67ce097cd801de16557" +checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.25" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2f140bda219a26ccc0cdb03dba58af72590c53b22642577d88a927bc5c87d6b" +checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 650384c..99f8a79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "winvd" -version = "0.0.46" +version = "0.0.47" authors = ["Jari Otto Oskari Pennanen"] license = "MIT" edition = "2021" @@ -10,7 +10,7 @@ homepage = "https://github.com/ciantic/VirtualDesktopAccessor/tree/rust/" repository = "https://github.com/ciantic/VirtualDesktopAccessor/tree/rust/" [dependencies] -windows = { version = "0.52", features = [ +windows = { version = "0.56", features = [ # Find WinApi features with searching here https://microsoft.github.io/windows-docs-rs/ "implement", "Win32_System_Com", @@ -19,10 +19,11 @@ windows = { version = "0.52", features = [ "Win32_Foundation", # for FindWindowW "Win32_System_Threading", # For CreateThread ] } -windows-interface = { version = "0.52" } -windows-implement = { version = "0.52" } +windows-core = { version = "0.56" } +windows-interface = { version = "0.56" } +windows-implement = { version = "0.56" } crossbeam-channel = { version = "0.5", optional = true } -winit = { version = "0.29.3", optional = true } +winit = { version = "0.30", optional = true } macro_rules_attribute = "0.2" [dev-dependencies] diff --git a/src/comobjects.rs b/src/comobjects.rs index 94becd9..06b2863 100644 --- a/src/comobjects.rs +++ b/src/comobjects.rs @@ -4,7 +4,6 @@ use super::Result; use std::convert::TryFrom; use std::rc::Rc; use std::{cell::RefCell, ffi::c_void}; -use windows::core::ComInterface; use windows::core::HRESULT; use windows::Win32::Foundation::HWND; use windows::Win32::System::Com::CoIncrementMTAUsage; diff --git a/src/interfaces.rs b/src/interfaces.rs index 34d7035..2598f60 100644 --- a/src/interfaces.rs +++ b/src/interfaces.rs @@ -38,7 +38,7 @@ use std::ffi::c_void; use std::ops::Deref; use windows::{ - core::{ComInterface, IUnknown, IUnknown_Vtbl, GUID, HRESULT, HSTRING}, + core::{IUnknown, IUnknown_Vtbl, Interface, GUID, HRESULT, HSTRING}, Win32::{Foundation::HWND, UI::Shell::Common::IObjectArray}, }; @@ -81,12 +81,12 @@ use windows::{ /// } /// ``` #[repr(transparent)] -pub struct ComIn<'a, T: ComInterface> { +pub struct ComIn<'a, T: Interface> { data: *mut c_void, _phantom: std::marker::PhantomData<&'a T>, } -impl<'a, T: ComInterface> ComIn<'a, T> { +impl<'a, T: Interface> ComIn<'a, T> { pub fn new(t: &'a T) -> Self { Self { // Copies the raw Inteface pointer @@ -96,7 +96,7 @@ impl<'a, T: ComInterface> ComIn<'a, T> { } } -impl<'a, T: ComInterface> Deref for ComIn<'a, T> { +impl<'a, T: Interface> Deref for ComIn<'a, T> { type Target = T; fn deref(&self) -> &Self::Target { unsafe { std::mem::transmute(&self.data) }