diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 69444def95..199d9f35a5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -101,6 +101,7 @@ jobs: cargo clippy -p windows_x86_64_gnu && cargo clippy -p windows_x86_64_msvc && cargo clippy -p test_agile && + cargo clippy -p test_agile_reference && cargo clippy -p test_alternate_success_code && cargo clippy -p test_arch && cargo clippy -p test_arch_feature && diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2af12cc4f1..e5e19d8815 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -70,6 +70,7 @@ jobs: cargo test --target ${{ matrix.target }} -p windows_x86_64_gnu && cargo test --target ${{ matrix.target }} -p windows_x86_64_msvc && cargo test --target ${{ matrix.target }} -p test_agile && + cargo test --target ${{ matrix.target }} -p test_agile_reference && cargo test --target ${{ matrix.target }} -p test_alternate_success_code && cargo test --target ${{ matrix.target }} -p test_arch && cargo test --target ${{ matrix.target }} -p test_arch_feature && diff --git a/crates/libs/windows/src/core/agile_reference.rs b/crates/libs/windows/src/core/agile_reference.rs new file mode 100644 index 0000000000..9f626c495b --- /dev/null +++ b/crates/libs/windows/src/core/agile_reference.rs @@ -0,0 +1,26 @@ +use super::*; +use bindings::*; +use core::marker::PhantomData; + +/// A type representing an agile reference to a COM/WinRT object. +#[repr(transparent)] +#[derive(Clone, PartialEq, Eq)] +pub struct AgileReference(IAgileReference, PhantomData); + +impl AgileReference { + /// Creates an agile reference to the object. + pub fn new<'a>(object: &'a T) -> Result + where + &'a T: IntoParam<'a, IUnknown>, + { + unsafe { RoGetAgileReference(AGILEREFERENCE_DEFAULT, &T::IID, object).map(|reference| Self(reference, Default::default())) } + } + + /// Retrieves a proxy to the target of the `AgileReference` object that may safely be used within any thread context in which get is called. + pub fn resolve(&self) -> Result { + unsafe { self.0.Resolve() } + } +} + +unsafe impl Send for AgileReference {} +unsafe impl Sync for AgileReference {} diff --git a/crates/libs/windows/src/core/bindings.rs b/crates/libs/windows/src/core/bindings.rs index d206d01002..ae40145ec7 100644 --- a/crates/libs/windows/src/core/bindings.rs +++ b/crates/libs/windows/src/core/bindings.rs @@ -2098,6 +2098,98 @@ pub unsafe fn WaitForSingleObject<'a, Param0: ::windows::core::IntoParam<'a, HAN unimplemented!("Unsupported target OS"); } #[repr(transparent)] +pub struct IAgileReference(::windows::core::IUnknown); +impl IAgileReference { + pub unsafe fn Resolve(&self) -> ::windows::core::Result { + let mut result__ = ::core::option::Option::None; + (::windows::core::Interface::vtable(self).Resolve)(::core::mem::transmute_copy(self), &::IID, &mut result__ as *mut _ as *mut _).and_some(result__) + } +} +impl ::core::convert::From for ::windows::core::IUnknown { + fn from(value: IAgileReference) -> Self { + unsafe { ::core::mem::transmute(value) } + } +} +impl ::core::convert::From<&IAgileReference> for ::windows::core::IUnknown { + fn from(value: &IAgileReference) -> Self { + ::core::convert::From::from(::core::clone::Clone::clone(value)) + } +} +impl<'a> ::windows::core::IntoParam<'a, ::windows::core::IUnknown> for IAgileReference { + fn into_param(self) -> ::windows::core::Param<'a, ::windows::core::IUnknown> { + ::windows::core::Param::Owned(unsafe { ::core::mem::transmute(self) }) + } +} +impl<'a> ::windows::core::IntoParam<'a, ::windows::core::IUnknown> for &IAgileReference { + fn into_param(self) -> ::windows::core::Param<'a, ::windows::core::IUnknown> { + ::windows::core::Param::Borrowed(unsafe { ::core::mem::transmute(self) }) + } +} +impl ::core::clone::Clone for IAgileReference { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} +impl ::core::cmp::PartialEq for IAgileReference { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} +impl ::core::cmp::Eq for IAgileReference {} +impl ::core::fmt::Debug for IAgileReference { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("IAgileReference").field(&self.0).finish() + } +} +unsafe impl ::windows::core::Interface for IAgileReference { + type Vtable = IAgileReference_Vtbl; + const IID: ::windows::core::GUID = ::windows::core::GUID::from_u128(0xc03f6a43_65a4_9818_987e_e0b810d2a6f2); +} +#[repr(C)] +#[doc(hidden)] +pub struct IAgileReference_Vtbl { + pub base: ::windows::core::IUnknownVtbl, + pub Resolve: unsafe extern "system" fn(this: *mut ::core::ffi::c_void, riid: *const ::windows::core::GUID, ppvobjectreference: *mut *mut ::core::ffi::c_void) -> ::windows::core::HRESULT, +} +#[repr(transparent)] +#[derive(:: core :: cmp :: PartialEq, :: core :: cmp :: Eq)] +pub struct AgileReferenceOptions(pub i32); +pub const AGILEREFERENCE_DEFAULT: AgileReferenceOptions = AgileReferenceOptions(0i32); +pub const AGILEREFERENCE_DELAYEDMARSHAL: AgileReferenceOptions = AgileReferenceOptions(1i32); +impl ::core::marker::Copy for AgileReferenceOptions {} +impl ::core::clone::Clone for AgileReferenceOptions { + fn clone(&self) -> Self { + *self + } +} +impl ::core::default::Default for AgileReferenceOptions { + fn default() -> Self { + Self(0) + } +} +unsafe impl ::windows::core::Abi for AgileReferenceOptions { + type Abi = Self; +} +impl ::core::fmt::Debug for AgileReferenceOptions { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("AgileReferenceOptions").field(&self.0).finish() + } +} +#[inline] +pub unsafe fn RoGetAgileReference<'a, Param2: ::windows::core::IntoParam<'a, ::windows::core::IUnknown>>(options: AgileReferenceOptions, riid: *const ::windows::core::GUID, punk: Param2) -> ::windows::core::Result { + #[cfg(windows)] + { + #[link(name = "windows")] + extern "system" { + fn RoGetAgileReference(options: AgileReferenceOptions, riid: *const ::windows::core::GUID, punk: *mut ::core::ffi::c_void, ppagilereference: *mut ::windows::core::RawPtr) -> ::windows::core::HRESULT; + } + let mut result__: ::windows::core::RawPtr = ::core::mem::zeroed(); + RoGetAgileReference(::core::mem::transmute(options), ::core::mem::transmute(riid), punk.into_param().abi(), ::core::mem::transmute(&mut result__)).from_abi::(result__) + } + #[cfg(not(windows))] + unimplemented!("Unsupported target OS"); +} +#[repr(transparent)] pub struct ILanguageExceptionErrorInfo(::windows::core::IUnknown); impl ILanguageExceptionErrorInfo { pub unsafe fn GetLanguageException(&self) -> ::windows::core::Result<::windows::core::IUnknown> { diff --git a/crates/libs/windows/src/core/mod.rs b/crates/libs/windows/src/core/mod.rs index 8625215db2..cf23f6f6e6 100644 --- a/crates/libs/windows/src/core/mod.rs +++ b/crates/libs/windows/src/core/mod.rs @@ -1,5 +1,6 @@ mod abi; mod activation_factory; +mod agile_reference; mod array; pub(crate) mod bindings; mod compose; @@ -28,6 +29,7 @@ mod weak_ref_count; pub use abi::*; #[doc(hidden)] pub use activation_factory::*; +pub use agile_reference::*; pub use array::*; #[doc(hidden)] pub use compose::*; diff --git a/crates/tests/agile_reference/Cargo.toml b/crates/tests/agile_reference/Cargo.toml new file mode 100644 index 0000000000..cbed3efda8 --- /dev/null +++ b/crates/tests/agile_reference/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "test_agile_reference" +version = "0.0.0" +authors = ["Microsoft"] +edition = "2018" + +[dependencies.windows] +path = "../../libs/windows" +features = [ + "Foundation", + "Media_Control", + "Foundation_Collections" +] diff --git a/crates/tests/agile_reference/src/lib.rs b/crates/tests/agile_reference/src/lib.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/crates/tests/agile_reference/src/lib.rs @@ -0,0 +1 @@ + diff --git a/crates/tests/agile_reference/tests/tests.rs b/crates/tests/agile_reference/tests/tests.rs new file mode 100644 index 0000000000..91ed3befb2 --- /dev/null +++ b/crates/tests/agile_reference/tests/tests.rs @@ -0,0 +1,16 @@ +use windows::core::{AgileReference, Result}; +use windows::Media::Control::GlobalSystemMediaTransportControlsSessionManager; + +#[test] +fn test() -> Result<()> { + let manager = GlobalSystemMediaTransportControlsSessionManager::RequestAsync()?.get()?; + let reference = AgileReference::new(&manager)?; + + let handle = std::thread::spawn(move || { + let manager = reference.resolve()?; + + manager.GetSessions()?; + Ok(()) + }); + handle.join().unwrap() +} diff --git a/crates/tools/bindings/src/main.rs b/crates/tools/bindings/src/main.rs index 152d2361e6..833943c0fd 100644 --- a/crates/tools/bindings/src/main.rs +++ b/crates/tools/bindings/src/main.rs @@ -50,6 +50,9 @@ fn main() -> std::io::Result<()> { "Windows.Win32.System.Threading.CreateEventA", "Windows.Win32.System.Threading.SetEvent", "Windows.Win32.System.Threading.WaitForSingleObject", + "Windows.Win32.System.WinRT.IAgileReference", + "Windows.Win32.System.WinRT.AgileReferenceOptions", + "Windows.Win32.System.WinRT.RoGetAgileReference", "Windows.Win32.System.WinRT.ILanguageExceptionErrorInfo", "Windows.Win32.System.WinRT.ILanguageExceptionErrorInfo2", "Windows.Win32.System.WinRT.IRestrictedErrorInfo",