From f3b9ca38dd50f2cb80dc2c96bd1be0de71fdcacc Mon Sep 17 00:00:00 2001 From: Kenny Kerr Date: Thu, 11 Jan 2024 11:56:06 -0600 Subject: [PATCH] Add `VT_UNKNOWN` support for `VARIANT` and `PROPVARIANT` (#2788) --- crates/libs/core/src/error.rs | 2 +- crates/libs/core/src/imp/bindings.rs | 2 +- crates/libs/core/src/imp/com_bindings.rs | 2 + crates/libs/core/src/variant.rs | 50 ++++++++++++++++++++++++ crates/tests/variant/Cargo.toml | 7 ++++ crates/tests/variant/tests/tests.rs | 26 ++++++++++++ crates/tools/core/bindings.txt | 2 +- crates/tools/core/com_bindings.txt | 4 +- 8 files changed, 91 insertions(+), 4 deletions(-) diff --git a/crates/libs/core/src/error.rs b/crates/libs/core/src/error.rs index c5a0111810..26f6a1336f 100644 --- a/crates/libs/core/src/error.rs +++ b/crates/libs/core/src/error.rs @@ -93,7 +93,7 @@ impl From for Error { impl From for Error { fn from(_: std::num::TryFromIntError) -> Self { - Self { code: HRESULT(crate::imp::E_INVALIDARG), info: None } + Self { code: crate::imp::E_INVALIDARG, info: None } } } diff --git a/crates/libs/core/src/imp/bindings.rs b/crates/libs/core/src/imp/bindings.rs index e064629a52..ffe27b497b 100644 --- a/crates/libs/core/src/imp/bindings.rs +++ b/crates/libs/core/src/imp/bindings.rs @@ -482,7 +482,6 @@ impl ::core::clone::Clone for EXCEPINFO { *self } } -pub const E_INVALIDARG: HRESULT = -2147024809i32; pub type FARPROC = ::core::option::Option isize>; #[repr(C)] pub struct FILETIME { @@ -999,5 +998,6 @@ pub const VT_UI1: VARENUM = 17u16; pub const VT_UI2: VARENUM = 18u16; pub const VT_UI4: VARENUM = 19u16; pub const VT_UI8: VARENUM = 21u16; +pub const VT_UNKNOWN: VARENUM = 13u16; pub type WAIT_EVENT = u32; pub type WIN32_ERROR = u32; diff --git a/crates/libs/core/src/imp/com_bindings.rs b/crates/libs/core/src/imp/com_bindings.rs index 9439e0f06e..9cb5f8783f 100644 --- a/crates/libs/core/src/imp/com_bindings.rs +++ b/crates/libs/core/src/imp/com_bindings.rs @@ -77,6 +77,7 @@ impl ::core::default::Default for DateTime { } } pub const E_BOUNDS: ::windows_core::HRESULT = ::windows_core::HRESULT(-2147483637i32); +pub const E_INVALIDARG: ::windows_core::HRESULT = ::windows_core::HRESULT(-2147024809i32); pub const E_NOINTERFACE: ::windows_core::HRESULT = ::windows_core::HRESULT(-2147467262i32); pub const E_OUTOFMEMORY: ::windows_core::HRESULT = ::windows_core::HRESULT(-2147024882i32); ::windows_core::imp::com_interface!(IAgileObject, IAgileObject_Vtbl, 0x94ea2b94_e9cc_49e0_c0ff_ee64ca8f5b90); @@ -1225,6 +1226,7 @@ impl ::core::default::Default for Size { unsafe { ::core::mem::zeroed() } } } +pub const TYPE_E_TYPEMISMATCH: ::windows_core::HRESULT = ::windows_core::HRESULT(-2147316576i32); #[repr(C)] pub struct TimeSpan { pub Duration: i64, diff --git a/crates/libs/core/src/variant.rs b/crates/libs/core/src/variant.rs index 93732291c4..a0b3e59dfe 100644 --- a/crates/libs/core/src/variant.rs +++ b/crates/libs/core/src/variant.rs @@ -157,6 +157,56 @@ impl TryFrom<&PROPVARIANT> for VARIANT { } } +// VT_UNKNOWN + +impl From for VARIANT { + fn from(value: IUnknown) -> Self { + Self(imp::VARIANT { + Anonymous: imp::VARIANT_0 { + Anonymous: imp::VARIANT_0_0 { vt: imp::VT_UNKNOWN, wReserved1: 0, wReserved2: 0, wReserved3: 0, Anonymous: imp::VARIANT_0_0_0 { punkVal: value.into_raw() } }, + }, + }) + } +} + +impl From for PROPVARIANT { + fn from(value: IUnknown) -> Self { + Self(imp::PROPVARIANT { + Anonymous: imp::PROPVARIANT_0 { + Anonymous: imp::PROPVARIANT_0_0 { vt: imp::VT_UNKNOWN, wReserved1: 0, wReserved2: 0, wReserved3: 0, Anonymous: imp::PROPVARIANT_0_0_0 { punkVal: value.into_raw() } }, + }, + }) + } +} + +impl TryFrom<&VARIANT> for IUnknown { + type Error = Error; + fn try_from(from: &VARIANT) -> Result { + unsafe { + if from.0.Anonymous.Anonymous.vt == imp::VT_UNKNOWN && !from.0.Anonymous.Anonymous.Anonymous.punkVal.is_null() { + let unknown: &IUnknown = std::mem::transmute(&from.0.Anonymous.Anonymous.Anonymous.punkVal); + Ok(unknown.clone()) + } else { + Err(Error { code: imp::TYPE_E_TYPEMISMATCH, info: None }) + } + } + } +} + +impl TryFrom<&PROPVARIANT> for IUnknown { + type Error = Error; + fn try_from(from: &PROPVARIANT) -> Result { + unsafe { + if from.0.Anonymous.Anonymous.vt == imp::VT_UNKNOWN && !from.0.Anonymous.Anonymous.Anonymous.punkVal.is_null() { + let unknown: &IUnknown = std::mem::transmute(&from.0.Anonymous.Anonymous.Anonymous.punkVal); + Ok(unknown.clone()) + } else { + Err(Error { code: imp::TYPE_E_TYPEMISMATCH, info: None }) + } + } + } +} + // VT_BSTR impl From for VARIANT { diff --git a/crates/tests/variant/Cargo.toml b/crates/tests/variant/Cargo.toml index 2d34b26a59..ab95754b9d 100644 --- a/crates/tests/variant/Cargo.toml +++ b/crates/tests/variant/Cargo.toml @@ -6,3 +6,10 @@ publish = false [dependencies.windows-core] path = "../../libs/core" + +[dependencies.windows] +path = "../../libs/windows" +features = [ + "Foundation", + "Win32_Foundation", +] diff --git a/crates/tests/variant/tests/tests.rs b/crates/tests/variant/tests/tests.rs index 0fe860e5d0..c7b6115080 100644 --- a/crates/tests/variant/tests/tests.rs +++ b/crates/tests/variant/tests/tests.rs @@ -1,3 +1,5 @@ +use windows::Foundation::Uri; +use windows::Win32::Foundation::TYPE_E_TYPEMISMATCH; use windows_core::*; #[test] @@ -69,6 +71,18 @@ fn test_variant() -> Result<()> { assert_eq!(VARIANT::from(3.5f64), VARIANT::from(3.5f64)); assert_ne!(VARIANT::from(3.5f64), VARIANT::from(0.0f64)); + let unknown: IUnknown = Uri::CreateUri(h!("https://github.com/"))?.into(); + let v = VARIANT::from(unknown); + let unknown = IUnknown::try_from(&v)?; + assert_eq!(unknown.cast::()?.Domain()?, "github.com"); + assert_eq!(i32::try_from(&v).unwrap_err().code(), TYPE_E_TYPEMISMATCH); + assert_eq!( + IUnknown::try_from(&VARIANT::from(3.5f64)) + .unwrap_err() + .code(), + TYPE_E_TYPEMISMATCH + ); + let v = VARIANT::from(BSTR::from("hello")); assert_eq!(BSTR::try_from(&v)?, "hello"); assert_eq!( @@ -168,6 +182,18 @@ fn test_propvariant() -> Result<()> { assert_eq!(PROPVARIANT::from(3.5f64), PROPVARIANT::from(3.5f64)); assert_ne!(PROPVARIANT::from(3.5f64), PROPVARIANT::from(0.0f64)); + let unknown: IUnknown = Uri::CreateUri(h!("https://github.com/"))?.into(); + let v = PROPVARIANT::from(unknown); + let unknown = IUnknown::try_from(&v)?; + assert_eq!(unknown.cast::()?.Domain()?, "github.com"); + assert_eq!(i32::try_from(&v).unwrap_err().code(), TYPE_E_TYPEMISMATCH); + assert_eq!( + IUnknown::try_from(&PROPVARIANT::from(3.5f64)) + .unwrap_err() + .code(), + TYPE_E_TYPEMISMATCH + ); + let v = PROPVARIANT::from(BSTR::from("hello")); assert_eq!(BSTR::try_from(&v)?, "hello"); assert_eq!( diff --git a/crates/tools/core/bindings.txt b/crates/tools/core/bindings.txt index 1e73f4e69b..4b1c71cb4c 100644 --- a/crates/tools/core/bindings.txt +++ b/crates/tools/core/bindings.txt @@ -5,7 +5,6 @@ --filter Windows.Win32.Foundation.CloseHandle - Windows.Win32.Foundation.E_INVALIDARG Windows.Win32.Foundation.ERROR_NO_UNICODE_TRANSLATION Windows.Win32.Foundation.FreeLibrary Windows.Win32.Foundation.GetLastError @@ -67,3 +66,4 @@ Windows.Win32.System.Variant.VT_UI2 Windows.Win32.System.Variant.VT_UI4 Windows.Win32.System.Variant.VT_UI8 + Windows.Win32.System.Variant.VT_UNKNOWN diff --git a/crates/tools/core/com_bindings.txt b/crates/tools/core/com_bindings.txt index d79351646c..6c506ece7f 100644 --- a/crates/tools/core/com_bindings.txt +++ b/crates/tools/core/com_bindings.txt @@ -10,10 +10,12 @@ Windows.Win32.Foundation.CLASS_E_CLASSNOTAVAILABLE Windows.Win32.Foundation.CO_E_NOTINITIALIZED Windows.Win32.Foundation.E_BOUNDS + Windows.Win32.Foundation.E_INVALIDARG Windows.Win32.Foundation.E_NOINTERFACE Windows.Win32.Foundation.E_OUTOFMEMORY Windows.Win32.Foundation.JSCRIPT_E_CANTEXECUTE Windows.Win32.Foundation.RPC_E_DISCONNECTED + Windows.Win32.Foundation.TYPE_E_TYPEMISMATCH Windows.Win32.System.Com.CoCreateGuid Windows.Win32.System.Com.GetErrorInfo Windows.Win32.System.Com.IAgileObject @@ -24,4 +26,4 @@ Windows.Win32.System.WinRT.ILanguageExceptionErrorInfo2 Windows.Win32.System.WinRT.IRestrictedErrorInfo Windows.Win32.System.WinRT.IWeakReferenceSource - Windows.Win32.System.WinRT.RoGetAgileReference \ No newline at end of file + Windows.Win32.System.WinRT.RoGetAgileReference