diff --git a/crates/libs/core/src/out_ref.rs b/crates/libs/core/src/out_ref.rs index d9ecb7931c..24ba06ca0e 100644 --- a/crates/libs/core/src/out_ref.rs +++ b/crates/libs/core/src/out_ref.rs @@ -23,3 +23,9 @@ impl> OutRef<'_, T> { } } } + +impl<'a, T: Type> From<&'a mut T::Default> for OutRef<'a, T> { + fn from(from: &'a mut T::Default) -> Self { + unsafe { core::mem::transmute(from) } + } +} diff --git a/crates/tests/bindgen/src/delegate_cpp_ref.rs b/crates/tests/bindgen/src/delegate_cpp_ref.rs new file mode 100644 index 0000000000..4e06e81f4c --- /dev/null +++ b/crates/tests/bindgen/src/delegate_cpp_ref.rs @@ -0,0 +1,92 @@ +#![allow( + non_snake_case, + non_upper_case_globals, + non_camel_case_types, + dead_code, + clippy::all +)] + +pub const CLASS_E_CLASSNOTAVAILABLE: windows_core::HRESULT = + windows_core::HRESULT(0x80040111_u32 as _); +#[repr(transparent)] +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] +pub struct D3D_FEATURE_LEVEL(pub i32); +windows_core::imp::define_interface!( + IActivationFactory, + IActivationFactory_Vtbl, + 0x00000035_0000_0000_c000_000000000046 +); +windows_core::imp::interface_hierarchy!( + IActivationFactory, + windows_core::IUnknown, + windows_core::IInspectable +); +impl IActivationFactory { + pub unsafe fn ActivateInstance(&self) -> windows_core::Result { + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(self).ActivateInstance)( + windows_core::Interface::as_raw(self), + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } + } +} +#[repr(C)] +pub struct IActivationFactory_Vtbl { + pub base__: windows_core::IInspectable_Vtbl, + pub ActivateInstance: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT, +} +pub trait IActivationFactory_Impl: windows_core::IUnknownImpl { + fn ActivateInstance(&self) -> windows_core::Result; +} +impl IActivationFactory_Vtbl { + pub const fn new() -> Self { + unsafe extern "system" fn ActivateInstance< + Identity: IActivationFactory_Impl, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + instance: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IActivationFactory_Impl::ActivateInstance(this) { + Ok(ok__) => { + instance.write(core::mem::transmute(ok__)); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + Self { + base__: windows_core::IInspectable_Vtbl::new::(), + ActivateInstance: ActivateInstance::, + } + } + pub fn matches(iid: &windows_core::GUID) -> bool { + iid == &::IID + } +} +impl windows_core::RuntimeName for IActivationFactory {} +pub type PFNGETACTIVATIONFACTORY = Option< + unsafe extern "system" fn( + param0: windows_core::Ref, + param1: windows_core::OutRef<'_, IActivationFactory>, + ) -> windows_core::HRESULT, +>; +pub type PFN_D3D12_CREATE_DEVICE = Option< + unsafe extern "system" fn( + param0: windows_core::Ref, + param1: D3D_FEATURE_LEVEL, + param2: *const windows_core::GUID, + param3: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT, +>; +pub const S_OK: windows_core::HRESULT = windows_core::HRESULT(0x0_u32 as _); diff --git a/crates/tests/bindgen/src/lib.rs b/crates/tests/bindgen/src/lib.rs index b36d2d63aa..dc6d42401a 100644 --- a/crates/tests/bindgen/src/lib.rs +++ b/crates/tests/bindgen/src/lib.rs @@ -21,6 +21,7 @@ pub mod default_assumed; pub mod default_default; pub mod delegate; pub mod delegate_cpp; +pub mod delegate_cpp_ref; pub mod delegate_generic; pub mod deps; pub mod derive_cpp_enum; diff --git a/crates/tests/bindgen/tests/delegate_cpp_ref.rs b/crates/tests/bindgen/tests/delegate_cpp_ref.rs new file mode 100644 index 0000000000..4ba4513690 --- /dev/null +++ b/crates/tests/bindgen/tests/delegate_cpp_ref.rs @@ -0,0 +1,61 @@ +use test_bindgen::delegate_cpp_ref::*; +use windows_core::*; + +#[test] +fn test_factory() { + static FACTORY: StaticComObject = Factory.into_static(); + + #[implement(IActivationFactory)] + struct Factory; + + impl IActivationFactory_Impl for Factory_Impl { + fn ActivateInstance(&self) -> Result { + todo!() + } + } + + unsafe extern "system" fn callback( + name: Ref, + factory: OutRef, + ) -> HRESULT { + if *name == "Factory" { + factory.write(Some(FACTORY.to_interface())).into() + } else { + _ = factory.write(None); + CLASS_E_CLASSNOTAVAILABLE + } + } + + // This is a roundabout way to test that PFNGETACTIVATIONFACTORY can be both implemented and called in Rust. + let _callback: PFNGETACTIVATIONFACTORY = Some(callback); + + unsafe { + let mut factory: Option = None; + + assert_eq!( + CLASS_E_CLASSNOTAVAILABLE, + callback( + // transmute_copy is required here since Ref doesn't have a lifetime parameter and thus is unsafe + // to implement From or construct a Ref without unsafe code. + std::mem::transmute_copy(h!("invalid")), + // OutRef provides a safe From implementation since it includes a lifetime parameter. + OutRef::from(&mut factory) + ) + ); + + assert!(factory.is_none()); + + assert_eq!( + S_OK, + callback( + std::mem::transmute_copy(h!("Factory")), + OutRef::from(&mut factory) + ) + ); + + assert_eq!( + FACTORY.to_interface::(), + factory.unwrap() + ); + } +} diff --git a/crates/tools/bindgen/src/main.rs b/crates/tools/bindgen/src/main.rs index 0815dec0c5..04ba64c625 100644 --- a/crates/tools/bindgen/src/main.rs +++ b/crates/tools/bindgen/src/main.rs @@ -99,6 +99,7 @@ fn main() { test("--out delegate.rs --filter DeferralCompletedHandler"); test("--out delegate_generic.rs --filter EventHandler"); test("--out delegate_cpp.rs --filter GetProcAddress EnumWindows"); + test("--out delegate_cpp_ref.rs --filter PFN_D3D12_CREATE_DEVICE PFNGETACTIVATIONFACTORY S_OK CLASS_E_CLASSNOTAVAILABLE"); // Tests for classes test("--out class.rs --filter Deferral");