From 08cf3e64f887f8a2bcd96271a404b3da94b6906c Mon Sep 17 00:00:00 2001 From: Kenny Kerr Date: Fri, 13 Dec 2024 08:08:22 -0600 Subject: [PATCH] static event test/sample --- crates/libs/core/src/event.rs | 2 +- crates/tests/winrt/events/src/bindings.rs | 128 ++++++++++++++++++ crates/tests/winrt/events/src/lib.rs | 39 +++++- crates/tests/winrt/events/src/metadata.idl | 3 + .../tests/winrt/events_client/src/bindings.rs | 63 +++++++++ crates/tests/winrt/events_client/src/lib.rs | 28 ++++ 6 files changed, 256 insertions(+), 7 deletions(-) diff --git a/crates/libs/core/src/event.rs b/crates/libs/core/src/event.rs index c04b2f8352..3951ef2cf8 100644 --- a/crates/libs/core/src/event.rs +++ b/crates/libs/core/src/event.rs @@ -21,7 +21,7 @@ impl Default for Event { impl Event { /// Creates a new, empty `Event`. - pub fn new() -> Self { + pub const fn new() -> Self { Self { delegates: RwLock::new(None), } diff --git a/crates/tests/winrt/events/src/bindings.rs b/crates/tests/winrt/events/src/bindings.rs index fe1d50de91..237df8e6f1 100644 --- a/crates/tests/winrt/events/src/bindings.rs +++ b/crates/tests/winrt/events/src/bindings.rs @@ -61,6 +61,47 @@ impl Class { .ok() } } + pub fn StaticSignal(value: i32) -> windows_core::Result { + Self::IClassStatics(|this| unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).StaticSignal)( + windows_core::Interface::as_raw(this), + value, + &mut result__, + ) + .map(|| result__) + }) + } + pub fn StaticEvent(handler: P0) -> windows_core::Result + where + P0: windows_core::Param>, + { + Self::IClassStatics(|this| unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).StaticEvent)( + windows_core::Interface::as_raw(this), + handler.param().abi(), + &mut result__, + ) + .map(|| result__) + }) + } + pub fn RemoveStaticEvent(token: i64) -> windows_core::Result<()> { + Self::IClassStatics(|this| unsafe { + (windows_core::Interface::vtable(this).RemoveStaticEvent)( + windows_core::Interface::as_raw(this), + token, + ) + .ok() + }) + } + fn IClassStatics windows_core::Result>( + callback: F, + ) -> windows_core::Result { + static SHARED: windows_core::imp::FactoryCache = + windows_core::imp::FactoryCache::new(); + SHARED.call(callback) + } } impl windows_core::RuntimeType for Class { const SIGNATURE: windows_core::imp::ConstBuffer = @@ -152,3 +193,90 @@ pub struct IClass_Vtbl { pub RemoveEvent: unsafe extern "system" fn(*mut core::ffi::c_void, i64) -> windows_core::HRESULT, } +windows_core::imp::define_interface!( + IClassStatics, + IClassStatics_Vtbl, + 0x47439b4f_f0b4_5a72_8777_4d60e34ec843 +); +impl windows_core::RuntimeType for IClassStatics { + const SIGNATURE: windows_core::imp::ConstBuffer = + windows_core::imp::ConstBuffer::for_interface::(); +} +impl windows_core::RuntimeName for IClassStatics { + const NAME: &'static str = "test_events.IClassStatics"; +} +pub trait IClassStatics_Impl: windows_core::IUnknownImpl { + fn StaticSignal(&self, value: i32) -> windows_core::Result; + fn StaticEvent( + &self, + handler: windows_core::Ref<'_, windows::Foundation::EventHandler>, + ) -> windows_core::Result; + fn RemoveStaticEvent(&self, token: i64) -> windows_core::Result<()>; +} +impl IClassStatics_Vtbl { + pub const fn new() -> Self { + unsafe extern "system" fn StaticSignal< + Identity: IClassStatics_Impl, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + value: i32, + result__: *mut i32, + ) -> windows_core::HRESULT { + let this: &Identity = &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IClassStatics_Impl::StaticSignal(this, value) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + unsafe extern "system" fn StaticEvent( + this: *mut core::ffi::c_void, + handler: *mut core::ffi::c_void, + result__: *mut i64, + ) -> windows_core::HRESULT { + let this: &Identity = &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IClassStatics_Impl::StaticEvent(this, core::mem::transmute_copy(&handler)) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + unsafe extern "system" fn RemoveStaticEvent< + Identity: IClassStatics_Impl, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + token: i64, + ) -> windows_core::HRESULT { + let this: &Identity = &*((this as *const *const ()).offset(OFFSET) as *const Identity); + IClassStatics_Impl::RemoveStaticEvent(this, token).into() + } + Self { + base__: windows_core::IInspectable_Vtbl::new::(), + StaticSignal: StaticSignal::, + StaticEvent: StaticEvent::, + RemoveStaticEvent: RemoveStaticEvent::, + } + } + pub fn matches(iid: &windows_core::GUID) -> bool { + iid == &::IID + } +} +#[repr(C)] +pub struct IClassStatics_Vtbl { + pub base__: windows_core::IInspectable_Vtbl, + pub StaticSignal: + unsafe extern "system" fn(*mut core::ffi::c_void, i32, *mut i32) -> windows_core::HRESULT, + pub StaticEvent: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut core::ffi::c_void, + *mut i64, + ) -> windows_core::HRESULT, + pub RemoveStaticEvent: + unsafe extern "system" fn(*mut core::ffi::c_void, i64) -> windows_core::HRESULT, +} diff --git a/crates/tests/winrt/events/src/lib.rs b/crates/tests/winrt/events/src/lib.rs index 87b051964c..2cb8ba0d4b 100644 --- a/crates/tests/winrt/events/src/lib.rs +++ b/crates/tests/winrt/events/src/lib.rs @@ -1,6 +1,7 @@ mod bindings; +use windows::{core::*, Foundation::*, Win32::Foundation::*, Win32::System::WinRT::*}; -use windows::{core::*, Win32::Foundation::*, Win32::System::WinRT::*}; +static CLASS_FACTORY: StaticComObject = ClassFactory::new().into_static(); #[no_mangle] unsafe extern "system" fn DllGetActivationFactory( @@ -8,15 +9,41 @@ unsafe extern "system" fn DllGetActivationFactory( factory: OutRef, ) -> HRESULT { if *name == "test_events.Class" { - factory.write(Some(ClassFactory.into())).into() + factory.write(Some(CLASS_FACTORY.to_interface())).into() } else { _ = factory.write(None); CLASS_E_CLASSNOTAVAILABLE } } -#[implement(IActivationFactory)] -struct ClassFactory; +#[implement(IActivationFactory, bindings::IClassStatics)] +struct ClassFactory(Event>); + +impl ClassFactory { + const fn new() -> Self { + Self(Event::new()) + } +} + +impl bindings::IClassStatics_Impl for ClassFactory_Impl { + fn StaticSignal(&self, value: i32) -> Result { + let mut counter = 0; + self.0.call(|delegate| { + counter += 1; + delegate.Invoke(self.as_interface(), value) + }); + Ok(counter) + } + + fn StaticEvent(&self, handler: Ref>) -> Result { + self.0.add(handler.unwrap()) + } + + fn RemoveStaticEvent(&self, token: i64) -> Result<()> { + self.0.remove(token); + Ok(()) + } +} impl IActivationFactory_Impl for ClassFactory_Impl { fn ActivateInstance(&self) -> Result { @@ -25,7 +52,7 @@ impl IActivationFactory_Impl for ClassFactory_Impl { } #[implement(bindings::Class)] -struct Class(Event>); +struct Class(Event>); impl bindings::IClass_Impl for Class_Impl { fn Signal(&self, value: i32) -> Result { @@ -39,7 +66,7 @@ impl bindings::IClass_Impl for Class_Impl { fn Event( &self, - handler: Ref>, + handler: Ref>, ) -> windows_core::Result { self.0.add(handler.unwrap()) } diff --git a/crates/tests/winrt/events/src/metadata.idl b/crates/tests/winrt/events/src/metadata.idl index 97164058f7..e6bff84d3d 100644 --- a/crates/tests/winrt/events/src/metadata.idl +++ b/crates/tests/winrt/events/src/metadata.idl @@ -6,5 +6,8 @@ namespace test_events Int32 Signal(Int32 value); event Windows.Foundation.TypedEventHandler Event; + + static Int32 StaticSignal(Int32 value); + static event Windows.Foundation.EventHandler StaticEvent; } } diff --git a/crates/tests/winrt/events_client/src/bindings.rs b/crates/tests/winrt/events_client/src/bindings.rs index 5756a0eabd..95c5f1ca2b 100644 --- a/crates/tests/winrt/events_client/src/bindings.rs +++ b/crates/tests/winrt/events_client/src/bindings.rs @@ -61,6 +61,47 @@ impl Class { .ok() } } + pub fn StaticSignal(value: i32) -> windows_core::Result { + Self::IClassStatics(|this| unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).StaticSignal)( + windows_core::Interface::as_raw(this), + value, + &mut result__, + ) + .map(|| result__) + }) + } + pub fn StaticEvent(handler: P0) -> windows_core::Result + where + P0: windows_core::Param>, + { + Self::IClassStatics(|this| unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).StaticEvent)( + windows_core::Interface::as_raw(this), + handler.param().abi(), + &mut result__, + ) + .map(|| result__) + }) + } + pub fn RemoveStaticEvent(token: i64) -> windows_core::Result<()> { + Self::IClassStatics(|this| unsafe { + (windows_core::Interface::vtable(this).RemoveStaticEvent)( + windows_core::Interface::as_raw(this), + token, + ) + .ok() + }) + } + fn IClassStatics windows_core::Result>( + callback: F, + ) -> windows_core::Result { + static SHARED: windows_core::imp::FactoryCache = + windows_core::imp::FactoryCache::new(); + SHARED.call(callback) + } } impl windows_core::RuntimeType for Class { const SIGNATURE: windows_core::imp::ConstBuffer = @@ -93,3 +134,25 @@ pub struct IClass_Vtbl { pub RemoveEvent: unsafe extern "system" fn(*mut core::ffi::c_void, i64) -> windows_core::HRESULT, } +windows_core::imp::define_interface!( + IClassStatics, + IClassStatics_Vtbl, + 0x47439b4f_f0b4_5a72_8777_4d60e34ec843 +); +impl windows_core::RuntimeType for IClassStatics { + const SIGNATURE: windows_core::imp::ConstBuffer = + windows_core::imp::ConstBuffer::for_interface::(); +} +#[repr(C)] +pub struct IClassStatics_Vtbl { + pub base__: windows_core::IInspectable_Vtbl, + pub StaticSignal: + unsafe extern "system" fn(*mut core::ffi::c_void, i32, *mut i32) -> windows_core::HRESULT, + pub StaticEvent: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut core::ffi::c_void, + *mut i64, + ) -> windows_core::HRESULT, + pub RemoveStaticEvent: + unsafe extern "system" fn(*mut core::ffi::c_void, i64) -> windows_core::HRESULT, +} diff --git a/crates/tests/winrt/events_client/src/lib.rs b/crates/tests/winrt/events_client/src/lib.rs index a73648977b..c4b13e67dc 100644 --- a/crates/tests/winrt/events_client/src/lib.rs +++ b/crates/tests/winrt/events_client/src/lib.rs @@ -26,6 +26,7 @@ fn test() -> Result<()> { assert_eq!(0, class.Signal(3)?); class.Event(&TypedEventHandler::new( + // TODO: ideally generics also use Ref here move |sender: &Option, args: &i32| { assert_eq!(sender.as_ref().unwrap(), class); assert_eq!(*args, 4); @@ -44,3 +45,30 @@ fn test() -> Result<()> { assert_eq!(2, class.Signal(4)?); Ok(()) } + +#[test] +fn test_static() -> Result<()> { + assert_eq!(0, Class::StaticSignal(1)?); + + let token = Class::StaticEvent(&EventHandler::new(move |_, args| { + assert_eq!(*args, 2); + Ok(()) + }))?; + + assert_eq!(1, Class::StaticSignal(2)?); + Class::RemoveStaticEvent(token)?; + assert_eq!(0, Class::StaticSignal(3)?); + + Class::StaticEvent(&EventHandler::new(move |_, args| { + assert_eq!(*args, 4); + Ok(()) + }))?; + + Class::StaticEvent(&EventHandler::new(move |_, args| { + assert_eq!(*args, 4); + Ok(()) + }))?; + + assert_eq!(2, Class::StaticSignal(4)?); + Ok(()) +}