diff --git a/crates/libs/core/src/imp/weak_ref_count.rs b/crates/libs/core/src/imp/weak_ref_count.rs index ee46a6bc33..1f6a70a28a 100644 --- a/crates/libs/core/src/imp/weak_ref_count.rs +++ b/crates/libs/core/src/imp/weak_ref_count.rs @@ -126,6 +126,10 @@ impl TearOff { unsafe extern "system" fn StrongQueryInterface(ptr: *mut std::ffi::c_void, iid: *const crate::GUID, interface: *mut *mut std::ffi::c_void) -> crate::HRESULT { let this = Self::from_strong_ptr(ptr); + if iid.is_null() || interface.is_null() { + return ::windows_core::HRESULT(-2147467261); // E_POINTER + } + // Only directly respond to queries for the the tear-off's strong interface. This is // effectively a self-query. if *iid == IWeakReferenceSource::IID { @@ -142,6 +146,10 @@ impl TearOff { unsafe extern "system" fn WeakQueryInterface(ptr: *mut std::ffi::c_void, iid: *const crate::GUID, interface: *mut *mut std::ffi::c_void) -> crate::HRESULT { let this = Self::from_weak_ptr(ptr); + if iid.is_null() || interface.is_null() { + return ::windows_core::HRESULT(-2147467261); // E_POINTER + } + // While the weak vtable is packed into the same allocation as the strong vtable and // tear-off, it represents a distinct COM identity and thus does not share or delegate to // the object. diff --git a/crates/tests/implement/tests/query.rs b/crates/tests/implement/tests/query.rs index 9efbe75ae9..dc01b93e33 100644 --- a/crates/tests/implement/tests/query.rs +++ b/crates/tests/implement/tests/query.rs @@ -1,38 +1,4 @@ -use windows::{core::*, Foundation::*, Win32::Foundation::*}; - -#[test] -fn delegate() { - unsafe { - let interface: EventHandler = EventHandler::::new(move |_, _| todo!()); - - // Successful query - { - let mut unknown: Option = None; - let hr = interface.query(&IUnknown::IID, &mut unknown as *mut _ as *mut _); - assert_eq!(hr, S_OK); - assert_eq!(interface.cast::().unwrap(), unknown.unwrap()); - } - // Unsuccessful query - { - let mut closable: Option = None; - let hr = interface.query(&IClosable::IID, &mut closable as *mut _ as *mut _); - assert_eq!(hr, E_NOINTERFACE); - assert_eq!(closable, None); - } - // iid param is null - { - let mut unknown: Option = None; - let hr = interface.query(std::ptr::null(), &mut unknown as *mut _ as *mut _); - assert_eq!(hr, E_POINTER); - assert_eq!(unknown, None); - } - // interface param is null - { - let hr = interface.query(&IUnknown::IID, std::ptr::null_mut()); - assert_eq!(hr, E_POINTER); - } - } -} +use windows::{core::*, Foundation::*, Win32::Foundation::*, Win32::System::WinRT::*}; #[implement(IStringable)] struct Stringable; @@ -44,10 +10,26 @@ impl IStringable_Impl for Stringable { } #[test] -fn implement() { +fn test() { unsafe { + // This covers the four distinct implementations of QueryInterface. + + let delegate: EventHandler = EventHandler::::new(move |_, _| todo!()); + test_query(&delegate); + let interface: IStringable = Stringable.into(); + test_query(&interface); + + let source: IWeakReferenceSource = interface.cast().unwrap(); + test_query(&source); + + let weak = source.GetWeakReference().unwrap(); + test_query(&weak); + } +} +fn test_query(interface: &I) { + unsafe { // Successful query { let mut unknown: Option = None; @@ -55,6 +37,7 @@ fn implement() { assert_eq!(hr, S_OK); assert_eq!(interface.cast::().unwrap(), unknown.unwrap()); } + // Unsuccessful query { let mut closable: Option = None; @@ -62,6 +45,7 @@ fn implement() { assert_eq!(hr, E_NOINTERFACE); assert_eq!(closable, None); } + // iid param is null { let mut unknown: Option = None; @@ -69,6 +53,7 @@ fn implement() { assert_eq!(hr, E_POINTER); assert_eq!(unknown, None); } + // interface param is null { let hr = interface.query(&IUnknown::IID, std::ptr::null_mut());