diff --git a/crates/libs/bindgen/src/rust/extensions/mod.rs b/crates/libs/bindgen/src/rust/extensions/mod.rs index 39faef9863..45be29f15f 100644 --- a/crates/libs/bindgen/src/rust/extensions/mod.rs +++ b/crates/libs/bindgen/src/rust/extensions/mod.rs @@ -15,6 +15,7 @@ pub fn gen_mod(writer: &Writer, namespace: &str) -> TokenStream { "Windows.Win32.Foundation" => concat!(include_str!("mod/Win32/Foundation/BOOL.rs"), include_str!("mod/Win32/Foundation/BOOLEAN.rs"), include_str!("mod/Win32/Foundation/NTSTATUS.rs"), include_str!("mod/Win32/Foundation/VARIANT_BOOL.rs"), include_str!("mod/Win32/Foundation/WIN32_ERROR.rs"),), "Windows.Win32.Networking.WinSock" => concat!(include_str!("mod/Win32/Networking/WinSock/IN_ADDR.rs"), include_str!("mod/Win32/Networking/WinSock/IN6_ADDR.rs"), include_str!("mod/Win32/Networking/WinSock/SOCKADDR_IN.rs"), include_str!("mod/Win32/Networking/WinSock/SOCKADDR_IN6.rs"), include_str!("mod/Win32/Networking/WinSock/SOCKADDR_INET.rs"),), "Windows.Win32.System.Rpc" => include_str!("mod/Win32/System/Rpc/RPC_STATUS.rs"), + "Windows.Win32.System.Com" => include_str!("mod/Win32/System/Com/IDispatch.rs"), "Windows.Win32.UI.WindowsAndMessaging" => { include_str!("mod/Win32/UI/WindowsAndMessaging/WindowLong.rs") } diff --git a/crates/libs/bindgen/src/rust/extensions/mod/Win32/System/Com/IDispatch.rs b/crates/libs/bindgen/src/rust/extensions/mod/Win32/System/Com/IDispatch.rs new file mode 100644 index 0000000000..cd6ff970e6 --- /dev/null +++ b/crates/libs/bindgen/src/rust/extensions/mod/Win32/System/Com/IDispatch.rs @@ -0,0 +1,65 @@ +impl From for ::windows_core::VARIANT { + fn from(value: IDispatch) -> Self { + unsafe { + Self::from_raw(::windows_core::imp::VARIANT { + Anonymous: ::windows_core::imp::VARIANT_0 { + Anonymous: ::windows_core::imp::VARIANT_0_0 { + vt: 9, + wReserved1: 0, + wReserved2: 0, + wReserved3: 0, + Anonymous: ::windows_core::imp::VARIANT_0_0_0 { pdispVal: ::std::mem::transmute(value) }, + }, + }, + }) + } + } +} + +impl From for ::windows_core::PROPVARIANT { + fn from(value: IDispatch) -> Self { + unsafe { + Self::from_raw(::windows_core::imp::PROPVARIANT { + Anonymous: ::windows_core::imp::PROPVARIANT_0 { + Anonymous: ::windows_core::imp::PROPVARIANT_0_0 { + vt: 9, + wReserved1: 0, + wReserved2: 0, + wReserved3: 0, + Anonymous: ::windows_core::imp::PROPVARIANT_0_0_0 { pdispVal: ::std::mem::transmute(value) }, + }, + }, + }) + } + } +} + +impl TryFrom<&::windows_core::VARIANT> for IDispatch { + type Error = ::windows_core::Error; + fn try_from(from: &::windows_core::VARIANT) -> ::windows_core::Result { + let from = from.as_raw(); + unsafe { + if from.Anonymous.Anonymous.vt == 9 && !from.Anonymous.Anonymous.Anonymous.pdispVal.is_null() { + let dispatch: &IDispatch = std::mem::transmute(&from.Anonymous.Anonymous.Anonymous.pdispVal); + Ok(dispatch.clone()) + } else { + Err(::windows_core::Error::from_hresult(::windows_core::imp::TYPE_E_TYPEMISMATCH)) + } + } + } +} + +impl TryFrom<&::windows_core::PROPVARIANT> for IDispatch { + type Error = ::windows_core::Error; + fn try_from(from: &::windows_core::PROPVARIANT) -> ::windows_core::Result { + let from = from.as_raw(); + unsafe { + if from.Anonymous.Anonymous.vt == 9 && !from.Anonymous.Anonymous.Anonymous.pdispVal.is_null() { + let dispatch: &IDispatch = std::mem::transmute(&from.Anonymous.Anonymous.Anonymous.pdispVal); + Ok(dispatch.clone()) + } else { + Err(::windows_core::Error::from_hresult(::windows_core::imp::TYPE_E_TYPEMISMATCH)) + } + } + } +} diff --git a/crates/libs/core/src/variant.rs b/crates/libs/core/src/variant.rs index f3b3c353a5..0ddb94e403 100644 --- a/crates/libs/core/src/variant.rs +++ b/crates/libs/core/src/variant.rs @@ -143,6 +143,20 @@ impl VARIANT { pub const fn is_empty(&self) -> bool { unsafe { self.0.Anonymous.Anonymous.vt == imp::VT_EMPTY } } + + /// Creates a `VARIANT` by taking ownership of the raw data. + /// + /// # Safety + /// + /// The raw data must be owned by the caller and represent a valid `VARIANT` data structure. + pub unsafe fn from_raw(raw: imp::VARIANT) -> Self { + Self(raw) + } + + /// Returns the underlying raw data for the `VARIANT`. + pub fn as_raw(&self) -> &imp::VARIANT { + &self.0 + } } impl PROPVARIANT { @@ -157,6 +171,20 @@ impl PROPVARIANT { pub const fn is_empty(&self) -> bool { unsafe { self.0.Anonymous.Anonymous.vt == imp::VT_EMPTY } } + + /// Creates a `PROPVARIANT` by taking ownership of the raw data. + /// + /// # Safety + /// + /// The raw data must be owned by the caller and represent a valid `PROPVARIANT` data structure. + pub unsafe fn from_raw(raw: imp::PROPVARIANT) -> Self { + Self(raw) + } + + /// Returns the underlying raw data for the `PROPVARIANT`. + pub fn as_raw(&self) -> &imp::PROPVARIANT { + &self.0 + } } impl TryFrom<&VARIANT> for PROPVARIANT { diff --git a/crates/libs/windows/src/Windows/Win32/System/Com/mod.rs b/crates/libs/windows/src/Windows/Win32/System/Com/mod.rs index 109604e7b5..b1c8448cf4 100644 --- a/crates/libs/windows/src/Windows/Win32/System/Com/mod.rs +++ b/crates/libs/windows/src/Windows/Win32/System/Com/mod.rs @@ -8137,5 +8137,58 @@ pub type LPEXCEPFINO_DEFERRED_FILLIN = ::core::option::Option ::windows_core::HRESULT>; pub type LPFNGETCLASSOBJECT = ::core::option::Option ::windows_core::HRESULT>; pub type PFNCONTEXTCALL = ::core::option::Option ::windows_core::HRESULT>; +impl From for ::windows_core::VARIANT { + fn from(value: IDispatch) -> Self { + unsafe { + Self::from_raw(::windows_core::imp::VARIANT { + Anonymous: ::windows_core::imp::VARIANT_0 { + Anonymous: ::windows_core::imp::VARIANT_0_0 { vt: 9, wReserved1: 0, wReserved2: 0, wReserved3: 0, Anonymous: ::windows_core::imp::VARIANT_0_0_0 { pdispVal: ::std::mem::transmute(value) } }, + }, + }) + } + } +} + +impl From for ::windows_core::PROPVARIANT { + fn from(value: IDispatch) -> Self { + unsafe { + Self::from_raw(::windows_core::imp::PROPVARIANT { + Anonymous: ::windows_core::imp::PROPVARIANT_0 { + Anonymous: ::windows_core::imp::PROPVARIANT_0_0 { vt: 9, wReserved1: 0, wReserved2: 0, wReserved3: 0, Anonymous: ::windows_core::imp::PROPVARIANT_0_0_0 { pdispVal: ::std::mem::transmute(value) } }, + }, + }) + } + } +} + +impl TryFrom<&::windows_core::VARIANT> for IDispatch { + type Error = ::windows_core::Error; + fn try_from(from: &::windows_core::VARIANT) -> ::windows_core::Result { + let from = from.as_raw(); + unsafe { + if from.Anonymous.Anonymous.vt == 9 && !from.Anonymous.Anonymous.Anonymous.pdispVal.is_null() { + let dispatch: &IDispatch = std::mem::transmute(&from.Anonymous.Anonymous.Anonymous.pdispVal); + Ok(dispatch.clone()) + } else { + Err(::windows_core::Error::from_hresult(::windows_core::imp::TYPE_E_TYPEMISMATCH)) + } + } + } +} + +impl TryFrom<&::windows_core::PROPVARIANT> for IDispatch { + type Error = ::windows_core::Error; + fn try_from(from: &::windows_core::PROPVARIANT) -> ::windows_core::Result { + let from = from.as_raw(); + unsafe { + if from.Anonymous.Anonymous.vt == 9 && !from.Anonymous.Anonymous.Anonymous.pdispVal.is_null() { + let dispatch: &IDispatch = std::mem::transmute(&from.Anonymous.Anonymous.Anonymous.pdispVal); + Ok(dispatch.clone()) + } else { + Err(::windows_core::Error::from_hresult(::windows_core::imp::TYPE_E_TYPEMISMATCH)) + } + } + } +} #[cfg(feature = "implement")] ::core::include!("impl.rs"); diff --git a/crates/tests/variant/Cargo.toml b/crates/tests/variant/Cargo.toml index ab95754b9d..38b262dd07 100644 --- a/crates/tests/variant/Cargo.toml +++ b/crates/tests/variant/Cargo.toml @@ -12,4 +12,5 @@ path = "../../libs/windows" features = [ "Foundation", "Win32_Foundation", + "Win32_System_Com_Events", ] diff --git a/crates/tests/variant/tests/tests.rs b/crates/tests/variant/tests/tests.rs index b348a15cc6..4ba9cfcfad 100644 --- a/crates/tests/variant/tests/tests.rs +++ b/crates/tests/variant/tests/tests.rs @@ -1,9 +1,12 @@ use windows::Foundation::Uri; -use windows::Win32::Foundation::TYPE_E_TYPEMISMATCH; +use windows::Win32::Foundation::{E_INVALIDARG, TYPE_E_TYPEMISMATCH}; +use windows::Win32::System::Com; use windows_core::*; #[test] fn test_variant() -> Result<()> { + unsafe { Com::CoIncrementMTAUsage()? }; + let empty: VARIANT = VARIANT::new(); assert!(empty.is_empty()); @@ -83,6 +86,19 @@ fn test_variant() -> Result<()> { TYPE_E_TYPEMISMATCH ); + let dispatch: Com::IDispatch = + unsafe { Com::CoCreateInstance(&Com::Events::CEventSystem, None, Com::CLSCTX_ALL)? }; + let v = VARIANT::from(dispatch); + let dispatch = Com::IDispatch::try_from(&v)?; + dispatch.cast::()?; + assert_eq!(i32::try_from(&v).unwrap_err().code(), E_INVALIDARG); + assert_eq!( + Com::IDispatch::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!( @@ -115,6 +131,8 @@ fn test_variant() -> Result<()> { #[test] fn test_propvariant() -> Result<()> { + unsafe { Com::CoIncrementMTAUsage()? }; + let empty: PROPVARIANT = PROPVARIANT::new(); assert!(empty.is_empty()); @@ -200,6 +218,19 @@ fn test_propvariant() -> Result<()> { TYPE_E_TYPEMISMATCH ); + let dispatch: Com::IDispatch = + unsafe { Com::CoCreateInstance(&Com::Events::CEventSystem, None, Com::CLSCTX_ALL)? }; + let v = PROPVARIANT::from(dispatch); + let dispatch = Com::IDispatch::try_from(&v)?; + dispatch.cast::()?; + assert_eq!(i32::try_from(&v).unwrap_err().code(), E_INVALIDARG); + assert_eq!( + Com::IDispatch::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!(