Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add static event test/sample for WinRT #3389

Merged
merged 1 commit into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/libs/core/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ impl<T: Interface> Default for Event<T> {

impl<T: Interface> Event<T> {
/// Creates a new, empty `Event<T>`.
pub fn new() -> Self {
pub const fn new() -> Self {
Self {
delegates: RwLock::new(None),
}
Expand Down
128 changes: 128 additions & 0 deletions crates/tests/winrt/events/src/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,47 @@ impl Class {
.ok()
}
}
pub fn StaticSignal(value: i32) -> windows_core::Result<i32> {
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<P0>(handler: P0) -> windows_core::Result<i64>
where
P0: windows_core::Param<windows::Foundation::EventHandler<i32>>,
{
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<R, F: FnOnce(&IClassStatics) -> windows_core::Result<R>>(
callback: F,
) -> windows_core::Result<R> {
static SHARED: windows_core::imp::FactoryCache<Class, IClassStatics> =
windows_core::imp::FactoryCache::new();
SHARED.call(callback)
}
}
impl windows_core::RuntimeType for Class {
const SIGNATURE: windows_core::imp::ConstBuffer =
Expand Down Expand Up @@ -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::<Self>();
}
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<i32>;
fn StaticEvent(
&self,
handler: windows_core::Ref<'_, windows::Foundation::EventHandler<i32>>,
) -> windows_core::Result<i64>;
fn RemoveStaticEvent(&self, token: i64) -> windows_core::Result<()>;
}
impl IClassStatics_Vtbl {
pub const fn new<Identity: IClassStatics_Impl, const OFFSET: isize>() -> 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<Identity: IClassStatics_Impl, const OFFSET: isize>(
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::<Identity, IClassStatics, OFFSET>(),
StaticSignal: StaticSignal::<Identity, OFFSET>,
StaticEvent: StaticEvent::<Identity, OFFSET>,
RemoveStaticEvent: RemoveStaticEvent::<Identity, OFFSET>,
}
}
pub fn matches(iid: &windows_core::GUID) -> bool {
iid == &<IClassStatics as windows_core::Interface>::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,
}
39 changes: 33 additions & 6 deletions crates/tests/winrt/events/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,49 @@
mod bindings;
use windows::{core::*, Foundation::*, Win32::Foundation::*, Win32::System::WinRT::*};

use windows::{core::*, Win32::Foundation::*, Win32::System::WinRT::*};
static CLASS_FACTORY: StaticComObject<ClassFactory> = ClassFactory::new().into_static();

#[no_mangle]
unsafe extern "system" fn DllGetActivationFactory(
name: Ref<HSTRING>,
factory: OutRef<IActivationFactory>,
) -> 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<EventHandler<i32>>);

impl ClassFactory {
const fn new() -> Self {
Self(Event::new())
}
}

impl bindings::IClassStatics_Impl for ClassFactory_Impl {
fn StaticSignal(&self, value: i32) -> Result<i32> {
let mut counter = 0;
self.0.call(|delegate| {
counter += 1;
delegate.Invoke(self.as_interface(), value)
});
Ok(counter)
}

fn StaticEvent(&self, handler: Ref<EventHandler<i32>>) -> Result<i64> {
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<IInspectable> {
Expand All @@ -25,7 +52,7 @@ impl IActivationFactory_Impl for ClassFactory_Impl {
}

#[implement(bindings::Class)]
struct Class(Event<windows::Foundation::TypedEventHandler<bindings::Class, i32>>);
struct Class(Event<TypedEventHandler<bindings::Class, i32>>);

impl bindings::IClass_Impl for Class_Impl {
fn Signal(&self, value: i32) -> Result<i32> {
Expand All @@ -39,7 +66,7 @@ impl bindings::IClass_Impl for Class_Impl {

fn Event(
&self,
handler: Ref<windows::Foundation::TypedEventHandler<bindings::Class, i32>>,
handler: Ref<TypedEventHandler<bindings::Class, i32>>,
) -> windows_core::Result<i64> {
self.0.add(handler.unwrap())
}
Expand Down
3 changes: 3 additions & 0 deletions crates/tests/winrt/events/src/metadata.idl
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,8 @@ namespace test_events

Int32 Signal(Int32 value);
event Windows.Foundation.TypedEventHandler<Class, Int32> Event;

static Int32 StaticSignal(Int32 value);
static event Windows.Foundation.EventHandler<Int32> StaticEvent;
}
}
63 changes: 63 additions & 0 deletions crates/tests/winrt/events_client/src/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,47 @@ impl Class {
.ok()
}
}
pub fn StaticSignal(value: i32) -> windows_core::Result<i32> {
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<P0>(handler: P0) -> windows_core::Result<i64>
where
P0: windows_core::Param<windows::Foundation::EventHandler<i32>>,
{
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<R, F: FnOnce(&IClassStatics) -> windows_core::Result<R>>(
callback: F,
) -> windows_core::Result<R> {
static SHARED: windows_core::imp::FactoryCache<Class, IClassStatics> =
windows_core::imp::FactoryCache::new();
SHARED.call(callback)
}
}
impl windows_core::RuntimeType for Class {
const SIGNATURE: windows_core::imp::ConstBuffer =
Expand Down Expand Up @@ -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::<Self>();
}
#[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,
}
28 changes: 28 additions & 0 deletions crates/tests/winrt/events_client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ fn test() -> Result<()> {
assert_eq!(0, class.Signal(3)?);

class.Event(&TypedEventHandler::new(
// TODO: ideally generics also use Ref<T> here
move |sender: &Option<Class>, args: &i32| {
assert_eq!(sender.as_ref().unwrap(), class);
assert_eq!(*args, 4);
Expand All @@ -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(())
}
Loading