diff --git a/crates/libs/bindgen/src/rust/handles.rs b/crates/libs/bindgen/src/rust/handles.rs index 993905d6d9d..844fff0dbe7 100644 --- a/crates/libs/bindgen/src/rust/handles.rs +++ b/crates/libs/bindgen/src/rust/handles.rs @@ -120,7 +120,7 @@ pub fn gen_win_handle(writer: &Writer, def: metadata::TypeDef) -> TokenStream { dependency.push_str(type_name.name()); tokens.combine("e! { - impl windows_core::CanInto<#dependency> for #ident {} + impl windows_core::imp::CanInto<#dependency> for #ident {} impl From<#ident> for #dependency { fn from(value: #ident) -> Self { Self(value.0) diff --git a/crates/libs/bindgen/src/rust/interfaces.rs b/crates/libs/bindgen/src/rust/interfaces.rs index dfea95062ce..0cdb6c74ca8 100644 --- a/crates/libs/bindgen/src/rust/interfaces.rs +++ b/crates/libs/bindgen/src/rust/interfaces.rs @@ -126,7 +126,7 @@ fn gen_win_interface(writer: &Writer, def: metadata::TypeDef) -> TokenStream { let cfg = writer.cfg_features(&cfg.union(cfg::type_cfg(writer, ty))); tokens.combine("e! { #cfg - impl<#constraints> windows_core::CanInto<#into> for #ident {} + impl<#constraints> windows_core::imp::CanInto<#into> for #ident {} }); } } @@ -152,7 +152,7 @@ fn gen_win_interface(writer: &Writer, def: metadata::TypeDef) -> TokenStream { let cfg = writer.cfg_features(&cfg.union(cfg::type_cfg(writer, &interface.ty))); tokens.combine("e! { #cfg - impl<#constraints> windows_core::CanInto<#into> for #ident { const QUERY: bool = true; } + impl<#constraints> windows_core::imp::CanInto<#into> for #ident { const QUERY: bool = true; } }); } } diff --git a/crates/libs/core/src/imp/can_into.rs b/crates/libs/core/src/imp/can_into.rs new file mode 100644 index 00000000000..47ee7838c4b --- /dev/null +++ b/crates/libs/core/src/imp/can_into.rs @@ -0,0 +1,5 @@ +pub trait CanInto<T>: Sized { + const QUERY: bool = false; +} + +impl<T> CanInto<T> for T where T: Clone {} diff --git a/crates/libs/core/src/imp/com_bindings.rs b/crates/libs/core/src/imp/com_bindings.rs index 07889c1c643..d999a00463e 100644 --- a/crates/libs/core/src/imp/com_bindings.rs +++ b/crates/libs/core/src/imp/com_bindings.rs @@ -428,9 +428,9 @@ impl<T: windows_core::RuntimeType + 'static> std::ops::Deref for IReference<T> { unsafe { std::mem::transmute(self) } } } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IUnknown> for IReference<T> {} -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IInspectable> for IReference<T> {} -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<IPropertyValue> for IReference<T> { +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> for IReference<T> {} +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> for IReference<T> {} +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<IPropertyValue> for IReference<T> { const QUERY: bool = true; } impl<T: windows_core::RuntimeType + 'static> IReference<T> { diff --git a/crates/libs/core/src/imp/mod.rs b/crates/libs/core/src/imp/mod.rs index 0dfa52d4367..84f27d8f872 100644 --- a/crates/libs/core/src/imp/mod.rs +++ b/crates/libs/core/src/imp/mod.rs @@ -1,4 +1,5 @@ mod bindings; +mod can_into; mod com_bindings; mod delay_load; mod factory_cache; @@ -10,6 +11,7 @@ mod waiter; mod weak_ref_count; pub use bindings::*; +pub use can_into::*; pub use com_bindings::*; pub use delay_load::*; pub use factory_cache::*; @@ -34,7 +36,7 @@ pub fn wide_trim_end(mut wide: &[u16]) -> &[u16] { #[macro_export] macro_rules! interface_hierarchy { ($child:ident, $parent:ty) => { - impl ::windows_core::CanInto<$parent> for $child {} + impl ::windows_core::imp::CanInto<$parent> for $child {} impl ::core::convert::From<&$child> for &$parent { fn from(value: &$child) -> Self { unsafe { ::core::mem::transmute(value) } @@ -59,7 +61,7 @@ pub use interface_hierarchy; #[macro_export] macro_rules! required_hierarchy { ($child:ident, $parent:ty) => { - impl ::windows_core::CanInto<$parent> for $child { const QUERY: bool = true; } + impl ::windows_core::imp::CanInto<$parent> for $child { const QUERY: bool = true; } }; ($child:ident, $first:ty, $($rest:ty),+) => { $crate::imp::required_hierarchy!($child, $first); diff --git a/crates/libs/core/src/lib.rs b/crates/libs/core/src/lib.rs index 44d0ef46d2b..997ab2afd52 100644 --- a/crates/libs/core/src/lib.rs +++ b/crates/libs/core/src/lib.rs @@ -19,7 +19,11 @@ mod guid; mod handles; mod inspectable; mod interface; +mod out_param; +mod out_ref; mod param; +mod param_value; +mod r#ref; mod runtime_name; mod runtime_type; mod scoped_interface; @@ -37,7 +41,11 @@ pub use guid::*; pub use handles::*; pub use inspectable::*; pub use interface::*; +pub use out_param::*; +pub use out_ref::*; pub use param::*; +pub use param_value::*; +pub use r#ref::*; pub use r#type::*; pub use runtime_name::*; pub use runtime_type::*; diff --git a/crates/libs/core/src/out_param.rs b/crates/libs/core/src/out_param.rs new file mode 100644 index 00000000000..e39093054ac --- /dev/null +++ b/crates/libs/core/src/out_param.rs @@ -0,0 +1,56 @@ +use super::*; + +/// Provides automatic parameter conversion in cases where the Windows API expects implicit conversion support. +/// +/// This is a mutable version of [Param] meant to support out parameters. +/// There is no need to implement this trait. Blanket implementations are provided for all applicable Windows types. +pub trait OutParam<T: TypeKind, C = <T as TypeKind>::TypeKind>: Sized +where + T: Type<T>, +{ + #[doc(hidden)] + unsafe fn borrow_mut(&self) -> OutRef<'_, T>; +} + +impl<T> OutParam<T, CloneType> for &mut T +where + T: TypeKind<TypeKind = CloneType> + Clone + Default, +{ + unsafe fn borrow_mut(&self) -> OutRef<'_, T> { + let this: &mut T = std::mem::transmute_copy(self); + std::mem::take(this); + std::mem::transmute_copy(self) + } +} + +impl<T> OutParam<T, CopyType> for &mut T +where + T: TypeKind<TypeKind = CopyType> + Clone + Default, +{ + unsafe fn borrow_mut(&self) -> OutRef<'_, T> { + std::mem::transmute_copy(self) + } +} + +impl<T> OutParam<T, InterfaceType> for &mut Option<T> +where + T: TypeKind<TypeKind = InterfaceType> + Clone, +{ + unsafe fn borrow_mut(&self) -> OutRef<'_, T> { + let this: &mut Option<T> = std::mem::transmute_copy(self); + std::mem::take(this); + std::mem::transmute_copy(self) + } +} + +impl<T> OutParam<T> for Option<&mut T> +where + T: Type<T>, +{ + unsafe fn borrow_mut(&self) -> OutRef<'_, T> { + match self { + Some(this) => std::mem::transmute_copy(this), + None => std::mem::zeroed(), + } + } +} diff --git a/crates/libs/core/src/out_ref.rs b/crates/libs/core/src/out_ref.rs new file mode 100644 index 00000000000..efd0b09d30b --- /dev/null +++ b/crates/libs/core/src/out_ref.rs @@ -0,0 +1,25 @@ +use super::*; + +/// A borrowed type with the same memory layout as the type itself that can be used to construct ABI-compatible function signatures. +/// +/// This is a mutable version of [Ref] meant to support out parameters. +#[repr(transparent)] +pub struct OutRef<'a, T: Type<T>>(*mut T::Abi, std::marker::PhantomData<&'a T>); + +impl<'a, T: Type<T>> OutRef<'a, T> { + /// Returns `true` if the argument is null. + pub fn is_null(&self) -> bool { + self.0.is_null() + } + + /// Overwrites a memory location with the given value without reading or dropping the old value. + pub fn write(self, value: T::Default) -> Result<()> { + if self.0.is_null() { + Err(Error::from_hresult(imp::E_POINTER)) + } else { + unsafe { *self.0 = std::mem::transmute_copy(&value) } + std::mem::forget(value); + Ok(()) + } + } +} diff --git a/crates/libs/core/src/param.rs b/crates/libs/core/src/param.rs index 81272e1ff12..132a1b6bef6 100644 --- a/crates/libs/core/src/param.rs +++ b/crates/libs/core/src/param.rs @@ -28,7 +28,7 @@ where T: TypeKind<TypeKind = InterfaceType> + Clone, T: Interface, U: Interface, - U: CanInto<T>, + U: imp::CanInto<T>, { unsafe fn param(self) -> ParamValue<T> { if U::QUERY { @@ -52,7 +52,7 @@ impl<T, U> Param<T, CopyType> for U where T: TypeKind<TypeKind = CopyType> + Clone, U: TypeKind<TypeKind = CopyType> + Clone, - U: CanInto<T>, + U: imp::CanInto<T>, { unsafe fn param(self) -> ParamValue<T> { ParamValue::Owned(std::mem::transmute_copy(&self)) @@ -82,27 +82,3 @@ impl Param<PCSTR> for PSTR { ParamValue::Owned(PCSTR(self.0)) } } - -#[doc(hidden)] -pub enum ParamValue<T: Type<T>> { - Owned(T), - Borrowed(T::Abi), -} - -impl<T: Type<T>> ParamValue<T> { - pub fn abi(&self) -> T::Abi { - unsafe { - match self { - Self::Owned(item) => std::mem::transmute_copy(item), - Self::Borrowed(borrowed) => std::mem::transmute_copy(borrowed), - } - } - } -} - -#[doc(hidden)] -pub trait CanInto<T>: Sized { - const QUERY: bool = false; -} - -impl<T> CanInto<T> for T where T: Clone {} diff --git a/crates/libs/core/src/param_value.rs b/crates/libs/core/src/param_value.rs new file mode 100644 index 00000000000..cbe2aba6f23 --- /dev/null +++ b/crates/libs/core/src/param_value.rs @@ -0,0 +1,23 @@ +use super::*; + +#[doc(hidden)] +pub enum ParamValue<T: Type<T>> { + Owned(T), + Borrowed(T::Abi), +} + +impl<T: Type<T>> ParamValue<T> { + // TODO: replace with `borrow` in windows-bindgen + pub fn abi(&self) -> T::Abi { + unsafe { + match self { + Self::Owned(item) => std::mem::transmute_copy(item), + Self::Borrowed(borrowed) => std::mem::transmute_copy(borrowed), + } + } + } + + pub fn borrow(&self) -> Ref<'_, T> { + unsafe { std::mem::transmute_copy(&self.abi()) } + } +} diff --git a/crates/libs/core/src/ref.rs b/crates/libs/core/src/ref.rs new file mode 100644 index 00000000000..c96a4c47ccc --- /dev/null +++ b/crates/libs/core/src/ref.rs @@ -0,0 +1,12 @@ +use super::*; + +/// A borrowed type with the same memory layout as the type itself that can be used to construct ABI-compatible function signatures. +#[repr(transparent)] +pub struct Ref<'a, T: Type<T>>(T::Abi, std::marker::PhantomData<&'a T>); + +impl<'a, T: Type<T>> std::ops::Deref for Ref<'a, T> { + type Target = T::Default; + fn deref(&self) -> &Self::Target { + unsafe { std::mem::transmute(&self.0) } + } +} diff --git a/crates/libs/interface/Cargo.toml b/crates/libs/interface/Cargo.toml index a5785d9a03c..301e5ae2307 100644 --- a/crates/libs/interface/Cargo.toml +++ b/crates/libs/interface/Cargo.toml @@ -19,6 +19,6 @@ targets = [] proc-macro = true [dependencies] -syn = { version = "2.0", default-features = false, features = ["parsing", "proc-macro", "printing", "full", "derive"] } +syn = { version = "2.0", default-features = false, features = ["parsing", "proc-macro", "printing", "full", "derive", "clone-impls"] } quote = "1.0" proc-macro2 = "1.0" diff --git a/crates/libs/interface/src/lib.rs b/crates/libs/interface/src/lib.rs index 929889f59fe..16cefaa277d 100644 --- a/crates/libs/interface/src/lib.rs +++ b/crates/libs/interface/src/lib.rs @@ -125,19 +125,22 @@ impl Interface { let vis = &m.visibility; let name = &m.name; - let args = m.gen_args(); - let params = &m - .args - .iter() - .map(|a| { - let pat = &a.pat; - quote! { #pat } - }) - .collect::<Vec<_>>(); + let generics = m.gen_consume_generics(); + let params = m.gen_consume_params(); + let args = m.gen_consume_args(); let ret = &m.ret; - quote! { - #vis unsafe fn #name(&self, #(#args),*) #ret { - (::windows_core::Interface::vtable(self).#name)(::windows_core::Interface::as_raw(self), #(#params),*) + + if m.is_result() { + quote! { + #vis unsafe fn #name<#(#generics),*>(&self, #(#params),*) #ret { + (::windows_core::Interface::vtable(self).#name)(::windows_core::Interface::as_raw(self), #(#args),*).ok() + } + } + } else { + quote! { + #vis unsafe fn #name<#(#generics),*>(&self, #(#params),*) #ret { + (::windows_core::Interface::vtable(self).#name)(::windows_core::Interface::as_raw(self), #(#args),*) + } } } }) @@ -190,8 +193,15 @@ impl Interface { let name = &m.name; let ret = &m.ret; let args = m.gen_args(); - quote! { - pub #name: unsafe extern "system" fn(this: *mut ::core::ffi::c_void, #(#args),*) #ret, + + if m.is_result() { + quote! { + pub #name: unsafe extern "system" fn(this: *mut ::core::ffi::c_void, #(#args),*) -> ::windows_core::HRESULT, + } + } else { + quote! { + pub #name: unsafe extern "system" fn(this: *mut ::core::ffi::c_void, #(#args),*) #ret, + } } }) .collect::<Vec<_>>(); @@ -214,6 +224,13 @@ impl Interface { }) .collect::<Vec<_>>(); let ret = &m.ret; + + let ret = if m.is_result() { + quote! { -> ::windows_core::HRESULT } + } else { + quote! { #ret } + }; + if parent_vtable.is_some() { quote! { unsafe extern "system" fn #name<Identity: ::windows_core::IUnknownImpl<Impl = Impl>, Impl: #trait_name, const OFFSET: isize>(this: *mut ::core::ffi::c_void, #(#args),*) #ret { @@ -505,6 +522,25 @@ struct InterfaceMethod { } impl InterfaceMethod { + fn is_result(&self) -> bool { + if let syn::ReturnType::Type(_, ty) = &self.ret { + if let syn::Type::Path(path) = &**ty { + if let Some(segment) = path.path.segments.last() { + let ident = segment.ident.to_string(); + if ident == "Result" { + if let syn::PathArguments::AngleBracketed(args) = &segment.arguments { + if args.args.len() == 1 { + return true; + } + } + } + } + } + } + + false + } + /// Generates arguments (of the form `$pat: $type`) fn gen_args(&self) -> Vec<proc_macro2::TokenStream> { self.args @@ -516,6 +552,62 @@ impl InterfaceMethod { }) .collect::<Vec<_>>() } + + fn gen_consume_generics(&self) -> Vec<proc_macro2::TokenStream> { + self.args + .iter() + .enumerate() + .filter_map(|(generic_index, a)| { + if let Some((ty, ident)) = a.borrow_type() { + let generic_ident = quote::format_ident!("P{generic_index}"); + if ident == "Ref" { + Some(quote! { #generic_ident: ::windows_core::Param<#ty> }) + } else { + Some(quote! { #generic_ident: ::windows_core::OutParam<#ty> }) + } + } else { + None + } + }) + .collect::<Vec<_>>() + } + + fn gen_consume_params(&self) -> Vec<proc_macro2::TokenStream> { + self.args + .iter() + .enumerate() + .map(|(generic_index, a)| { + let pat = &a.pat; + + if a.borrow_type().is_some() { + let generic_ident = quote::format_ident!("P{generic_index}"); + quote! { #pat: #generic_ident } + } else { + let ty = &a.ty; + quote! { #pat: #ty } + } + }) + .collect::<Vec<_>>() + } + + fn gen_consume_args(&self) -> Vec<proc_macro2::TokenStream> { + self.args + .iter() + .map(|a| { + let pat = &a.pat; + + if let Some((_, ident)) = a.borrow_type() { + if ident == "Ref" { + quote! { #pat.param().borrow() } + } else { + quote! { #pat.borrow_mut() } + } + } else { + quote! { #pat } + } + }) + .collect::<Vec<_>>() + } } impl syn::parse::Parse for InterfaceMethod { @@ -554,3 +646,24 @@ struct InterfaceMethodArg { /// The name of the argument pub pat: Box<syn::Pat>, } + +impl InterfaceMethodArg { + fn borrow_type(&self) -> Option<(syn::Type, String)> { + if let syn::Type::Path(path) = &*self.ty { + if let Some(segment) = path.path.segments.last() { + let ident = segment.ident.to_string(); + if matches!(ident.as_str(), "Ref" | "OutRef") { + if let syn::PathArguments::AngleBracketed(args) = &segment.arguments { + if args.args.len() == 1 { + if let Some(syn::GenericArgument::Type(ty)) = args.args.first() { + return Some((ty.clone(), ident)); + } + } + } + } + } + } + + None + } +} diff --git a/crates/libs/windows/src/Windows/Foundation/Collections/mod.rs b/crates/libs/windows/src/Windows/Foundation/Collections/mod.rs index 53bea775cd5..da1a6264c6e 100644 --- a/crates/libs/windows/src/Windows/Foundation/Collections/mod.rs +++ b/crates/libs/windows/src/Windows/Foundation/Collections/mod.rs @@ -9,8 +9,8 @@ impl<T: windows_core::RuntimeType + 'static> std::ops::Deref for IIterable<T> { unsafe { std::mem::transmute(self) } } } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IUnknown> for IIterable<T> {} -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IInspectable> for IIterable<T> {} +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> for IIterable<T> {} +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> for IIterable<T> {} impl<T: windows_core::RuntimeType + 'static> IIterable<T> { pub fn First(&self) -> windows_core::Result<IIterator<T>> { let this = self; @@ -61,8 +61,8 @@ impl<T: windows_core::RuntimeType + 'static> std::ops::Deref for IIterator<T> { unsafe { std::mem::transmute(self) } } } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IUnknown> for IIterator<T> {} -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IInspectable> for IIterator<T> {} +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> for IIterator<T> {} +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> for IIterator<T> {} impl<T: windows_core::RuntimeType + 'static> IIterator<T> { pub fn Current(&self) -> windows_core::Result<T> { let this = self; @@ -134,8 +134,8 @@ impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'sta unsafe { std::mem::transmute(self) } } } -impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IUnknown> for IKeyValuePair<K, V> {} -impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IInspectable> for IKeyValuePair<K, V> {} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> for IKeyValuePair<K, V> {} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> for IKeyValuePair<K, V> {} impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> IKeyValuePair<K, V> { pub fn Key(&self) -> windows_core::Result<K> { let this = self; @@ -183,9 +183,9 @@ impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'sta unsafe { std::mem::transmute(self) } } } -impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IUnknown> for IMap<K, V> {} -impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IInspectable> for IMap<K, V> {} -impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> windows_core::CanInto<IIterable<IKeyValuePair<K, V>>> for IMap<K, V> { +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> for IMap<K, V> {} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> for IMap<K, V> {} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<IIterable<IKeyValuePair<K, V>>> for IMap<K, V> { const QUERY: bool = true; } impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> IMap<K, V> { @@ -302,8 +302,8 @@ impl<K: windows_core::RuntimeType + 'static> std::ops::Deref for IMapChangedEven unsafe { std::mem::transmute(self) } } } -impl<K: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IUnknown> for IMapChangedEventArgs<K> {} -impl<K: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IInspectable> for IMapChangedEventArgs<K> {} +impl<K: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> for IMapChangedEventArgs<K> {} +impl<K: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> for IMapChangedEventArgs<K> {} impl<K: windows_core::RuntimeType + 'static> IMapChangedEventArgs<K> { pub fn CollectionChange(&self) -> windows_core::Result<CollectionChange> { let this = self; @@ -349,9 +349,9 @@ impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'sta unsafe { std::mem::transmute(self) } } } -impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IUnknown> for IMapView<K, V> {} -impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IInspectable> for IMapView<K, V> {} -impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> windows_core::CanInto<IIterable<IKeyValuePair<K, V>>> for IMapView<K, V> { +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> for IMapView<K, V> {} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> for IMapView<K, V> {} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<IIterable<IKeyValuePair<K, V>>> for IMapView<K, V> { const QUERY: bool = true; } impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> IMapView<K, V> { @@ -441,12 +441,12 @@ impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'sta unsafe { std::mem::transmute(self) } } } -impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IUnknown> for IObservableMap<K, V> {} -impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IInspectable> for IObservableMap<K, V> {} -impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> windows_core::CanInto<IIterable<IKeyValuePair<K, V>>> for IObservableMap<K, V> { +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> for IObservableMap<K, V> {} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> for IObservableMap<K, V> {} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<IIterable<IKeyValuePair<K, V>>> for IObservableMap<K, V> { const QUERY: bool = true; } -impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> windows_core::CanInto<IMap<K, V>> for IObservableMap<K, V> { +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<IMap<K, V>> for IObservableMap<K, V> { const QUERY: bool = true; } impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> IObservableMap<K, V> { @@ -572,12 +572,12 @@ impl<T: windows_core::RuntimeType + 'static> std::ops::Deref for IObservableVect unsafe { std::mem::transmute(self) } } } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IUnknown> for IObservableVector<T> {} -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IInspectable> for IObservableVector<T> {} -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<IIterable<T>> for IObservableVector<T> { +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> for IObservableVector<T> {} +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> for IObservableVector<T> {} +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<IIterable<T>> for IObservableVector<T> { const QUERY: bool = true; } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<IVector<T>> for IObservableVector<T> { +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<IVector<T>> for IObservableVector<T> { const QUERY: bool = true; } impl<T: windows_core::RuntimeType + 'static> IObservableVector<T> { @@ -819,9 +819,9 @@ impl<T: windows_core::RuntimeType + 'static> std::ops::Deref for IVector<T> { unsafe { std::mem::transmute(self) } } } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IUnknown> for IVector<T> {} -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IInspectable> for IVector<T> {} -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<IIterable<T>> for IVector<T> { +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> for IVector<T> {} +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> for IVector<T> {} +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<IIterable<T>> for IVector<T> { const QUERY: bool = true; } impl<T: windows_core::RuntimeType + 'static> IVector<T> { @@ -1011,9 +1011,9 @@ impl<T: windows_core::RuntimeType + 'static> std::ops::Deref for IVectorView<T> unsafe { std::mem::transmute(self) } } } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IUnknown> for IVectorView<T> {} -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IInspectable> for IVectorView<T> {} -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<IIterable<T>> for IVectorView<T> { +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> for IVectorView<T> {} +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> for IVectorView<T> {} +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<IIterable<T>> for IVectorView<T> { const QUERY: bool = true; } impl<T: windows_core::RuntimeType + 'static> IVectorView<T> { diff --git a/crates/libs/windows/src/Windows/Foundation/mod.rs b/crates/libs/windows/src/Windows/Foundation/mod.rs index 88bb44a88f3..c2d18ce7aec 100644 --- a/crates/libs/windows/src/Windows/Foundation/mod.rs +++ b/crates/libs/windows/src/Windows/Foundation/mod.rs @@ -116,9 +116,9 @@ impl<TProgress: windows_core::RuntimeType + 'static> std::ops::Deref for IAsyncA unsafe { std::mem::transmute(self) } } } -impl<TProgress: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IUnknown> for IAsyncActionWithProgress<TProgress> {} -impl<TProgress: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IInspectable> for IAsyncActionWithProgress<TProgress> {} -impl<TProgress: windows_core::RuntimeType + 'static> windows_core::CanInto<IAsyncInfo> for IAsyncActionWithProgress<TProgress> { +impl<TProgress: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> for IAsyncActionWithProgress<TProgress> {} +impl<TProgress: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> for IAsyncActionWithProgress<TProgress> {} +impl<TProgress: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<IAsyncInfo> for IAsyncActionWithProgress<TProgress> { const QUERY: bool = true; } impl<TProgress: windows_core::RuntimeType + 'static> IAsyncActionWithProgress<TProgress> { @@ -297,9 +297,9 @@ impl<TResult: windows_core::RuntimeType + 'static> std::ops::Deref for IAsyncOpe unsafe { std::mem::transmute(self) } } } -impl<TResult: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IUnknown> for IAsyncOperation<TResult> {} -impl<TResult: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IInspectable> for IAsyncOperation<TResult> {} -impl<TResult: windows_core::RuntimeType + 'static> windows_core::CanInto<IAsyncInfo> for IAsyncOperation<TResult> { +impl<TResult: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> for IAsyncOperation<TResult> {} +impl<TResult: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> for IAsyncOperation<TResult> {} +impl<TResult: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<IAsyncInfo> for IAsyncOperation<TResult> { const QUERY: bool = true; } impl<TResult: windows_core::RuntimeType + 'static> IAsyncOperation<TResult> { @@ -415,9 +415,9 @@ impl<TResult: windows_core::RuntimeType + 'static, TProgress: windows_core::Runt unsafe { std::mem::transmute(self) } } } -impl<TResult: windows_core::RuntimeType + 'static, TProgress: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IUnknown> for IAsyncOperationWithProgress<TResult, TProgress> {} -impl<TResult: windows_core::RuntimeType + 'static, TProgress: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IInspectable> for IAsyncOperationWithProgress<TResult, TProgress> {} -impl<TResult: windows_core::RuntimeType + 'static, TProgress: windows_core::RuntimeType + 'static> windows_core::CanInto<IAsyncInfo> for IAsyncOperationWithProgress<TResult, TProgress> { +impl<TResult: windows_core::RuntimeType + 'static, TProgress: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> for IAsyncOperationWithProgress<TResult, TProgress> {} +impl<TResult: windows_core::RuntimeType + 'static, TProgress: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> for IAsyncOperationWithProgress<TResult, TProgress> {} +impl<TResult: windows_core::RuntimeType + 'static, TProgress: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<IAsyncInfo> for IAsyncOperationWithProgress<TResult, TProgress> { const QUERY: bool = true; } impl<TResult: windows_core::RuntimeType + 'static, TProgress: windows_core::RuntimeType + 'static> IAsyncOperationWithProgress<TResult, TProgress> { @@ -1030,9 +1030,9 @@ impl<T: windows_core::RuntimeType + 'static> std::ops::Deref for IReference<T> { unsafe { std::mem::transmute(self) } } } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IUnknown> for IReference<T> {} -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IInspectable> for IReference<T> {} -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<IPropertyValue> for IReference<T> { +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> for IReference<T> {} +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> for IReference<T> {} +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<IPropertyValue> for IReference<T> { const QUERY: bool = true; } impl<T: windows_core::RuntimeType + 'static> IReference<T> { @@ -1287,9 +1287,9 @@ impl<T: windows_core::RuntimeType + 'static> std::ops::Deref for IReferenceArray unsafe { std::mem::transmute(self) } } } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IUnknown> for IReferenceArray<T> {} -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IInspectable> for IReferenceArray<T> {} -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<IPropertyValue> for IReferenceArray<T> { +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> for IReferenceArray<T> {} +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> for IReferenceArray<T> {} +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<IPropertyValue> for IReferenceArray<T> { const QUERY: bool = true; } impl<T: windows_core::RuntimeType + 'static> IReferenceArray<T> { diff --git a/crates/libs/windows/src/Windows/Win32/Foundation/mod.rs b/crates/libs/windows/src/Windows/Win32/Foundation/mod.rs index 361e63377a5..93e07590ef0 100644 --- a/crates/libs/windows/src/Windows/Win32/Foundation/mod.rs +++ b/crates/libs/windows/src/Windows/Win32/Foundation/mod.rs @@ -10824,7 +10824,7 @@ impl Default for HINSTANCE { impl windows_core::TypeKind for HINSTANCE { type TypeKind = windows_core::CopyType; } -impl windows_core::CanInto<HMODULE> for HINSTANCE {} +impl windows_core::imp::CanInto<HMODULE> for HINSTANCE {} impl From<HINSTANCE> for HMODULE { fn from(value: HINSTANCE) -> Self { Self(value.0) @@ -10887,7 +10887,7 @@ impl Default for HMODULE { impl windows_core::TypeKind for HMODULE { type TypeKind = windows_core::CopyType; } -impl windows_core::CanInto<HINSTANCE> for HMODULE {} +impl windows_core::imp::CanInto<HINSTANCE> for HMODULE {} impl From<HMODULE> for HINSTANCE { fn from(value: HMODULE) -> Self { Self(value.0) @@ -10953,7 +10953,7 @@ impl Default for HWND { impl windows_core::TypeKind for HWND { type TypeKind = windows_core::CopyType; } -impl windows_core::CanInto<HANDLE> for HWND {} +impl windows_core::imp::CanInto<HANDLE> for HWND {} impl From<HWND> for HANDLE { fn from(value: HWND) -> Self { Self(value.0) diff --git a/crates/libs/windows/src/Windows/Win32/Graphics/Gdi/mod.rs b/crates/libs/windows/src/Windows/Win32/Graphics/Gdi/mod.rs index b3659db718c..0e6c7c90b38 100644 --- a/crates/libs/windows/src/Windows/Win32/Graphics/Gdi/mod.rs +++ b/crates/libs/windows/src/Windows/Win32/Graphics/Gdi/mod.rs @@ -10683,7 +10683,7 @@ impl Default for HBITMAP { impl windows_core::TypeKind for HBITMAP { type TypeKind = windows_core::CopyType; } -impl windows_core::CanInto<HGDIOBJ> for HBITMAP {} +impl windows_core::imp::CanInto<HGDIOBJ> for HBITMAP {} impl From<HBITMAP> for HGDIOBJ { fn from(value: HBITMAP) -> Self { Self(value.0) @@ -10712,7 +10712,7 @@ impl Default for HBRUSH { impl windows_core::TypeKind for HBRUSH { type TypeKind = windows_core::CopyType; } -impl windows_core::CanInto<HGDIOBJ> for HBRUSH {} +impl windows_core::imp::CanInto<HGDIOBJ> for HBRUSH {} impl From<HBRUSH> for HGDIOBJ { fn from(value: HBRUSH) -> Self { Self(value.0) @@ -10780,7 +10780,7 @@ impl Default for HFONT { impl windows_core::TypeKind for HFONT { type TypeKind = windows_core::CopyType; } -impl windows_core::CanInto<HGDIOBJ> for HFONT {} +impl windows_core::imp::CanInto<HGDIOBJ> for HFONT {} impl From<HFONT> for HGDIOBJ { fn from(value: HFONT) -> Self { Self(value.0) @@ -10864,7 +10864,7 @@ impl Default for HPALETTE { impl windows_core::TypeKind for HPALETTE { type TypeKind = windows_core::CopyType; } -impl windows_core::CanInto<HGDIOBJ> for HPALETTE {} +impl windows_core::imp::CanInto<HGDIOBJ> for HPALETTE {} impl From<HPALETTE> for HGDIOBJ { fn from(value: HPALETTE) -> Self { Self(value.0) @@ -10893,7 +10893,7 @@ impl Default for HPEN { impl windows_core::TypeKind for HPEN { type TypeKind = windows_core::CopyType; } -impl windows_core::CanInto<HGDIOBJ> for HPEN {} +impl windows_core::imp::CanInto<HGDIOBJ> for HPEN {} impl From<HPEN> for HGDIOBJ { fn from(value: HPEN) -> Self { Self(value.0) @@ -10922,7 +10922,7 @@ impl Default for HRGN { impl windows_core::TypeKind for HRGN { type TypeKind = windows_core::CopyType; } -impl windows_core::CanInto<HGDIOBJ> for HRGN {} +impl windows_core::imp::CanInto<HGDIOBJ> for HRGN {} impl From<HRGN> for HGDIOBJ { fn from(value: HRGN) -> Self { Self(value.0) diff --git a/crates/libs/windows/src/Windows/Win32/Security/Cryptography/mod.rs b/crates/libs/windows/src/Windows/Win32/Security/Cryptography/mod.rs index 915d1975ea3..b280e86bb5b 100644 --- a/crates/libs/windows/src/Windows/Win32/Security/Cryptography/mod.rs +++ b/crates/libs/windows/src/Windows/Win32/Security/Cryptography/mod.rs @@ -8814,7 +8814,7 @@ impl Default for BCRYPT_ALG_HANDLE { impl windows_core::TypeKind for BCRYPT_ALG_HANDLE { type TypeKind = windows_core::CopyType; } -impl windows_core::CanInto<BCRYPT_HANDLE> for BCRYPT_ALG_HANDLE {} +impl windows_core::imp::CanInto<BCRYPT_HANDLE> for BCRYPT_ALG_HANDLE {} impl From<BCRYPT_ALG_HANDLE> for BCRYPT_HANDLE { fn from(value: BCRYPT_ALG_HANDLE) -> Self { Self(value.0) @@ -9209,7 +9209,7 @@ impl Default for BCRYPT_HASH_HANDLE { impl windows_core::TypeKind for BCRYPT_HASH_HANDLE { type TypeKind = windows_core::CopyType; } -impl windows_core::CanInto<BCRYPT_HANDLE> for BCRYPT_HASH_HANDLE {} +impl windows_core::imp::CanInto<BCRYPT_HANDLE> for BCRYPT_HASH_HANDLE {} impl From<BCRYPT_HASH_HANDLE> for BCRYPT_HANDLE { fn from(value: BCRYPT_HASH_HANDLE) -> Self { Self(value.0) @@ -9328,7 +9328,7 @@ impl Default for BCRYPT_KEY_HANDLE { impl windows_core::TypeKind for BCRYPT_KEY_HANDLE { type TypeKind = windows_core::CopyType; } -impl windows_core::CanInto<BCRYPT_HANDLE> for BCRYPT_KEY_HANDLE {} +impl windows_core::imp::CanInto<BCRYPT_HANDLE> for BCRYPT_KEY_HANDLE {} impl From<BCRYPT_KEY_HANDLE> for BCRYPT_HANDLE { fn from(value: BCRYPT_KEY_HANDLE) -> Self { Self(value.0) @@ -9663,7 +9663,7 @@ impl Default for BCRYPT_SECRET_HANDLE { impl windows_core::TypeKind for BCRYPT_SECRET_HANDLE { type TypeKind = windows_core::CopyType; } -impl windows_core::CanInto<BCRYPT_HANDLE> for BCRYPT_SECRET_HANDLE {} +impl windows_core::imp::CanInto<BCRYPT_HANDLE> for BCRYPT_SECRET_HANDLE {} impl From<BCRYPT_SECRET_HANDLE> for BCRYPT_HANDLE { fn from(value: BCRYPT_SECRET_HANDLE) -> Self { Self(value.0) @@ -19742,7 +19742,7 @@ impl Default for NCRYPT_KEY_HANDLE { impl windows_core::TypeKind for NCRYPT_KEY_HANDLE { type TypeKind = windows_core::CopyType; } -impl windows_core::CanInto<NCRYPT_HANDLE> for NCRYPT_KEY_HANDLE {} +impl windows_core::imp::CanInto<NCRYPT_HANDLE> for NCRYPT_KEY_HANDLE {} impl From<NCRYPT_KEY_HANDLE> for NCRYPT_HANDLE { fn from(value: NCRYPT_KEY_HANDLE) -> Self { Self(value.0) @@ -19978,7 +19978,7 @@ impl Default for NCRYPT_PROV_HANDLE { impl windows_core::TypeKind for NCRYPT_PROV_HANDLE { type TypeKind = windows_core::CopyType; } -impl windows_core::CanInto<NCRYPT_HANDLE> for NCRYPT_PROV_HANDLE {} +impl windows_core::imp::CanInto<NCRYPT_HANDLE> for NCRYPT_PROV_HANDLE {} impl From<NCRYPT_PROV_HANDLE> for NCRYPT_HANDLE { fn from(value: NCRYPT_PROV_HANDLE) -> Self { Self(value.0) diff --git a/crates/libs/windows/src/Windows/Win32/UI/WindowsAndMessaging/mod.rs b/crates/libs/windows/src/Windows/Win32/UI/WindowsAndMessaging/mod.rs index f88e68af112..ed4fc0d86d3 100644 --- a/crates/libs/windows/src/Windows/Win32/UI/WindowsAndMessaging/mod.rs +++ b/crates/libs/windows/src/Windows/Win32/UI/WindowsAndMessaging/mod.rs @@ -8882,7 +8882,7 @@ impl Default for HCURSOR { impl windows_core::TypeKind for HCURSOR { type TypeKind = windows_core::CopyType; } -impl windows_core::CanInto<HICON> for HCURSOR {} +impl windows_core::imp::CanInto<HICON> for HCURSOR {} impl From<HCURSOR> for HICON { fn from(value: HCURSOR) -> Self { Self(value.0) diff --git a/crates/samples/components/json_validator_winrt/src/lib.rs b/crates/samples/components/json_validator_winrt/src/lib.rs index b816b0d4780..7c39d6e0240 100644 --- a/crates/samples/components/json_validator_winrt/src/lib.rs +++ b/crates/samples/components/json_validator_winrt/src/lib.rs @@ -64,8 +64,8 @@ fn json_from_hstring(value: &HSTRING) -> Result<serde_json::Value> { } #[no_mangle] -extern "system" fn DllGetActivationFactory( - name: std::mem::ManuallyDrop<HSTRING>, +unsafe extern "system" fn DllGetActivationFactory( + name: Ref<HSTRING>, result: *mut *mut std::ffi::c_void, ) -> HRESULT { if result.is_null() { diff --git a/crates/tests/component/src/lib.rs b/crates/tests/component/src/lib.rs index 08785be5c7a..d53dbdb1b81 100644 --- a/crates/tests/component/src/lib.rs +++ b/crates/tests/component/src/lib.rs @@ -68,21 +68,16 @@ impl IActivationFactory_Impl for ClassFactory { } } +// HRESULT __stdcall DllGetActivationFactory(HSTRING, IActivationFactory**) #[no_mangle] unsafe extern "system" fn DllGetActivationFactory( - name: std::mem::ManuallyDrop<HSTRING>, - result: *mut *mut std::ffi::c_void, + name: Ref<HSTRING>, + factory: OutRef<IActivationFactory>, ) -> HRESULT { - let factory: Option<IActivationFactory> = match (*name).to_string().as_str() { - "test_component.Class" => Some(ClassFactory.into()), - _ => None, - }; - - if let Some(factory) = factory { - *result = factory.into_raw(); - S_OK + if *name == "test_component.Class" { + factory.write(Some(ClassFactory.into())).into() } else { - *result = std::ptr::null_mut(); + _ = factory.write(None); CLASS_E_CLASSNOTAVAILABLE } } diff --git a/crates/tests/interface_core/tests/ref.rs b/crates/tests/interface_core/tests/ref.rs new file mode 100644 index 00000000000..e103dc23513 --- /dev/null +++ b/crates/tests/interface_core/tests/ref.rs @@ -0,0 +1,133 @@ +#![allow(non_snake_case)] + +use windows_core::*; + +pub const S_OK: HRESULT = HRESULT(0); +pub const S_FALSE: HRESULT = HRESULT(1); +pub const E_INVALIDARG: HRESULT = HRESULT(0x80070057_u32 as _); +pub const E_POINTER: HRESULT = HRESULT(0x80004003_u32 as _); + +#[interface("09428a59-5b40-4e4c-9175-e7a78514316d")] +unsafe trait ITest: IUnknown { + // TODO: compile error if param type is not Ref/OutRef and is not Copy + + unsafe fn usize(&self, input: usize, output: OutRef<usize>) -> HRESULT; + unsafe fn hstring(&self, input: Ref<HSTRING>, output: OutRef<HSTRING>) -> HRESULT; + unsafe fn interface(&self, input: Ref<ITest>, output: OutRef<ITest>) -> HRESULT; + unsafe fn required_input(&self, input: Ref<ITest>, output: OutRef<ITest>) -> HRESULT; + unsafe fn optional_output(&self, input: Ref<ITest>, output: OutRef<ITest>) -> HRESULT; + + unsafe fn result_usize(&self, input: usize, output: OutRef<usize>) -> Result<()>; + unsafe fn result_hstring(&self, input: Ref<HSTRING>, output: OutRef<HSTRING>) -> Result<()>; + unsafe fn result_interface(&self, input: Ref<ITest>, output: OutRef<ITest>) -> Result<()>; + unsafe fn result_required_input(&self, input: Ref<ITest>, output: OutRef<ITest>) -> Result<()>; +} + +#[implement(ITest)] +struct Test; + +impl ITest_Impl for Test { + unsafe fn usize(&self, input: usize, output: OutRef<usize>) -> HRESULT { + output.write(input).into() + } + unsafe fn hstring(&self, input: Ref<HSTRING>, output: OutRef<HSTRING>) -> HRESULT { + output.write(input.clone()).into() + } + unsafe fn interface(&self, input: Ref<ITest>, output: OutRef<ITest>) -> HRESULT { + output.write(input.clone()).into() + } + unsafe fn required_input(&self, input: Ref<ITest>, output: OutRef<ITest>) -> HRESULT { + if input.is_none() { + E_INVALIDARG + } else { + self.interface(input, output) + } + } + + unsafe fn optional_output(&self, input: Ref<ITest>, output: OutRef<ITest>) -> HRESULT { + if output.is_null() { + S_FALSE + } else { + self.interface(input, output) + } + } + + unsafe fn result_usize(&self, input: usize, output: OutRef<usize>) -> Result<()> { + output.write(input) + } + unsafe fn result_hstring(&self, input: Ref<HSTRING>, output: OutRef<HSTRING>) -> Result<()> { + output.write(input.clone()) + } + unsafe fn result_interface(&self, input: Ref<ITest>, output: OutRef<ITest>) -> Result<()> { + output.write(input.clone()) + } + unsafe fn result_required_input(&self, input: Ref<ITest>, output: OutRef<ITest>) -> Result<()> { + if input.is_none() { + E_INVALIDARG.ok() + } else { + self.result_interface(input, output) + } + } +} + +#[test] +fn test() { + unsafe { + let test: ITest = Test.into(); + + assert_eq!(test.usize(0, None), E_POINTER); + assert_eq!(test.hstring(h!("hello"), None), E_POINTER); + assert_eq!(test.interface(None, None), E_POINTER); + assert_eq!(test.required_input(None, None), E_INVALIDARG); + + let mut output = 0; + assert_eq!(test.usize(123, &mut output), S_OK); + assert_eq!(output, 123); + + let mut output = HSTRING::from("will be dropped"); + // `output` will be dropped before receiving value, avoiding a leak. + assert_eq!(test.hstring(h!("hello"), &mut output), S_OK); + assert_eq!(&output, h!("hello")); + + let mut output = None; + assert_eq!(test.interface(&test, &mut output), S_OK); + assert_eq!(output.as_ref(), Some(&test)); + + // `output` will be dropped before receiving next value, avoiding a leak. + assert_eq!(test.required_input(&test, &mut output), S_OK); + assert_eq!(output.as_ref(), Some(&test)); + + assert_eq!(test.optional_output(&test, None), S_FALSE); + assert_eq!(test.optional_output(&test, &mut output), S_OK); + assert_eq!(output, Some(test)); + } +} + +#[test] +fn test_result() { + unsafe { + let test: ITest = Test.into(); + + assert_eq!(test.result_usize(0, None), E_POINTER.ok()); + assert_eq!(test.result_hstring(h!("hello"), None), E_POINTER.ok()); + assert_eq!(test.result_interface(None, None), E_POINTER.ok()); + assert_eq!(test.result_required_input(None, None), E_INVALIDARG.ok()); + + let mut output = 0; + assert_eq!(test.result_usize(123, &mut output), Ok(())); + assert_eq!(output, 123); + + let mut output = HSTRING::from("will be dropped"); + // `output` will be dropped before receiving value, avoiding a leak. + assert_eq!(test.result_hstring(h!("hello"), &mut output), Ok(())); + assert_eq!(&output, h!("hello")); + + let mut output = None; + assert_eq!(test.result_interface(&test, &mut output), Ok(())); + assert_eq!(output.as_ref(), Some(&test)); + + // `output` will be dropped before receiving next value, avoiding a leak. + assert_eq!(test.result_required_input(&test, &mut output), Ok(())); + assert_eq!(output, Some(test)); + } +} diff --git a/crates/tests/interface_core/tests/result.rs b/crates/tests/interface_core/tests/result.rs new file mode 100644 index 00000000000..c5d8b8edc12 --- /dev/null +++ b/crates/tests/interface_core/tests/result.rs @@ -0,0 +1,44 @@ +#![allow(non_snake_case)] + +use windows_core::*; + +pub const S_OK: HRESULT = HRESULT(0); +pub const S_FALSE: HRESULT = HRESULT(1); +pub const E_INVALIDARG: HRESULT = HRESULT(0x80070057_u32 as _); + +#[interface("09428a59-5b40-4e4c-9175-e7a78514316d")] +unsafe trait ITest: IUnknown { + unsafe fn Void(&self); + unsafe fn Code(&self, code: HRESULT) -> HRESULT; + unsafe fn Result(&self, code: HRESULT) -> Result<()>; +} + +#[implement(ITest)] +struct Test; + +impl ITest_Impl for Test { + unsafe fn Void(&self) {} + unsafe fn Code(&self, code: HRESULT) -> HRESULT { + code + } + unsafe fn Result(&self, code: HRESULT) -> Result<()> { + code.ok() + } +} + +#[test] +fn test() { + unsafe { + let test: ITest = Test.into(); + + test.Void(); + + assert_eq!(test.Code(S_OK), S_OK); + assert_eq!(test.Code(S_FALSE), S_FALSE); + assert_eq!(test.Code(E_INVALIDARG), E_INVALIDARG); + + assert!(test.Result(S_OK).is_ok()); + assert!(test.Result(S_FALSE).is_ok()); + assert_eq!(test.Result(E_INVALIDARG), E_INVALIDARG.ok()); + } +} diff --git a/crates/tests/riddle/src/generic_interfaces.rs b/crates/tests/riddle/src/generic_interfaces.rs index 44bc22ee74b..c177c06b74a 100644 --- a/crates/tests/riddle/src/generic_interfaces.rs +++ b/crates/tests/riddle/src/generic_interfaces.rs @@ -16,11 +16,11 @@ impl<T: windows_core::RuntimeType + 'static> std::ops::Deref for IIterable<T> { unsafe { std::mem::transmute(self) } } } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IUnknown> +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> for IIterable<T> { } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IInspectable> +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> for IIterable<T> { } @@ -75,11 +75,11 @@ impl<T: windows_core::RuntimeType + 'static> std::ops::Deref for IIterator<T> { unsafe { std::mem::transmute(self) } } } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IUnknown> +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> for IIterator<T> { } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IInspectable> +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> for IIterator<T> { } @@ -168,11 +168,11 @@ impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'sta } } impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> - windows_core::CanInto<windows_core::IUnknown> for IKeyValuePair<K, V> + windows_core::imp::CanInto<windows_core::IUnknown> for IKeyValuePair<K, V> { } impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> - windows_core::CanInto<windows_core::IInspectable> for IKeyValuePair<K, V> + windows_core::imp::CanInto<windows_core::IInspectable> for IKeyValuePair<K, V> { } impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> @@ -259,15 +259,15 @@ impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'sta } } impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> - windows_core::CanInto<windows_core::IUnknown> for IMapView<K, V> + windows_core::imp::CanInto<windows_core::IUnknown> for IMapView<K, V> { } impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> - windows_core::CanInto<windows_core::IInspectable> for IMapView<K, V> + windows_core::imp::CanInto<windows_core::IInspectable> for IMapView<K, V> { } impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> - windows_core::CanInto<IIterable<IKeyValuePair<K, V>>> for IMapView<K, V> + windows_core::imp::CanInto<IIterable<IKeyValuePair<K, V>>> for IMapView<K, V> { const QUERY: bool = true; } diff --git a/crates/tests/standalone/src/b_calendar.rs b/crates/tests/standalone/src/b_calendar.rs index 51fd0f9079c..1dce3a9d371 100644 --- a/crates/tests/standalone/src/b_calendar.rs +++ b/crates/tests/standalone/src/b_calendar.rs @@ -1653,11 +1653,11 @@ impl<T: windows_core::RuntimeType + 'static> std::ops::Deref for IIterable<T> { unsafe { std::mem::transmute(self) } } } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IUnknown> +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> for IIterable<T> { } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IInspectable> +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> for IIterable<T> { } @@ -1726,11 +1726,11 @@ impl<T: windows_core::RuntimeType + 'static> std::ops::Deref for IIterator<T> { unsafe { std::mem::transmute(self) } } } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IUnknown> +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> for IIterator<T> { } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IInspectable> +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> for IIterator<T> { } @@ -1873,15 +1873,15 @@ impl<T: windows_core::RuntimeType + 'static> std::ops::Deref for IVectorView<T> unsafe { std::mem::transmute(self) } } } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IUnknown> +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> for IVectorView<T> { } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IInspectable> +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> for IVectorView<T> { } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<IIterable<T>> +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<IIterable<T>> for IVectorView<T> { const QUERY: bool = true; diff --git a/crates/tests/standalone/src/b_uri.rs b/crates/tests/standalone/src/b_uri.rs index 4de4eed61c7..2b7f7863e80 100644 --- a/crates/tests/standalone/src/b_uri.rs +++ b/crates/tests/standalone/src/b_uri.rs @@ -16,11 +16,11 @@ impl<T: windows_core::RuntimeType + 'static> std::ops::Deref for IIterable<T> { unsafe { std::mem::transmute(self) } } } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IUnknown> +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> for IIterable<T> { } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IInspectable> +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> for IIterable<T> { } @@ -89,11 +89,11 @@ impl<T: windows_core::RuntimeType + 'static> std::ops::Deref for IIterator<T> { unsafe { std::mem::transmute(self) } } } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IUnknown> +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> for IIterator<T> { } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IInspectable> +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> for IIterator<T> { } @@ -393,15 +393,15 @@ impl<T: windows_core::RuntimeType + 'static> std::ops::Deref for IVectorView<T> unsafe { std::mem::transmute(self) } } } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IUnknown> +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> for IVectorView<T> { } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<windows_core::IInspectable> +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> for IVectorView<T> { } -impl<T: windows_core::RuntimeType + 'static> windows_core::CanInto<IIterable<T>> +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<IIterable<T>> for IVectorView<T> { const QUERY: bool = true;