winsafe/oleaut/structs/
variant.rs

1#![allow(non_snake_case)]
2
3use std::mem::ManuallyDrop;
4
5use crate::co;
6use crate::oleaut::ffi;
7use crate::prelude::*;
8
9/// [`VARIANT`](https://learn.microsoft.com/en-us/windows/win32/api/oaidl/ns-oaidl-variant)
10/// struct.
11///
12/// Automatically calls
13/// [`VariantClear`](https://learn.microsoft.com/en-us/windows/win32/api/oleauto/nf-oleauto-variantclear)
14/// when the object goes out of scope.
15///
16/// The [`Default`](std::default::Default) implementation returns a
17/// [`co::VT::EMPTY`](crate::co::VT::EMPTY) value.
18#[repr(C)]
19pub struct VARIANT {
20	vt: co::VT,
21	wReserved1: u16,
22	wReserved2: u16,
23	wReserved3: u16,
24	data: [u8; 16],
25}
26
27impl Drop for VARIANT {
28	fn drop(&mut self) {
29		if self.vt() != co::VT::EMPTY {
30			unsafe { ffi::VariantClear(self as *mut _ as _); } // ignore errors
31		}
32	}
33}
34
35impl Default for VARIANT {
36	fn default() -> Self {
37		let mut obj = unsafe { std::mem::zeroed::<Self>() };
38		unsafe { ffi::VariantInit(&mut obj as *mut _ as _); }
39		obj
40	}
41}
42
43impl oleaut_Variant for VARIANT {
44	fn raw(&self) -> &[u8; 16] {
45		&self.data
46	}
47
48	unsafe fn from_raw(vt: co::VT, data: &[u8]) -> Self {
49		let mut obj = Self::default();
50		obj.vt = vt;
51		data.iter()
52			.zip(&mut obj.data)
53			.for_each(|(src, dest)| *dest = *src);
54		obj
55	}
56
57	fn vt(&self) -> co::VT {
58		self.vt
59	}
60}
61
62impl VARIANT {
63	/// Creates a new object holding an [`IDispatch`](crate::IDispatch) COM
64	/// value.
65	///
66	/// Note that `val` will be cloned into the `VARIANT` – that is,
67	/// [`IUnknown::AddRef`](https://learn.microsoft.com/en-us/windows/win32/api/unknwn/nf-unknwn-iunknown-addref)
68	/// will be called –, so `val` will remain valid to be used thereafter.
69	#[must_use]
70	pub fn new_idispatch(val: &impl oleaut_IDispatch) -> Self {
71		let mut cloned = val.clone();
72		let ptr = cloned.leak() as usize;
73		unsafe { Self::from_raw(co::VT::DISPATCH, &ptr.to_ne_bytes()) }
74	}
75
76	/// If the object holds an [`IDispatch`](crate::IDispatch) COM value,
77	/// returns it, otherwise `None`.
78	///
79	/// Note that the returned object will be a clone – that is,
80	/// [`IUnknown::AddRef`](https://learn.microsoft.com/en-us/windows/win32/api/unknwn/nf-unknwn-iunknown-addref)
81	/// will be called.
82	#[must_use]
83	pub fn idispatch<T>(&self) -> Option<T>
84		where T: oleaut_IDispatch,
85	{
86		if self.vt() == co::VT::DISPATCH {
87			let ptr = usize::from_ne_bytes(self.raw()[..8].try_into().unwrap());
88			let obj = ManuallyDrop::new(unsafe { T::from_ptr(ptr as *mut _) }); // won't release the stored pointer
89			let cloned = T::clone(&obj); // call AddRef
90			Some(cloned)
91		} else {
92			None
93		}
94	}
95
96	/// Creates a new object holding an [`IUnknown`](crate::IUnknown) COM value.
97	///
98	/// Note that `val` will be cloned into the `VARIANT` – that is,
99	/// [`IUnknown::AddRef`](https://learn.microsoft.com/en-us/windows/win32/api/unknwn/nf-unknwn-iunknown-addref)
100	/// will be called –, so `val` will remain valid to be used thereafter.
101	#[must_use]
102	pub fn new_iunknown<T>(val: &impl ole_IUnknown) -> Self {
103		let mut cloned = val.clone();
104		let ptr = cloned.leak() as usize;
105		unsafe { Self::from_raw(co::VT::UNKNOWN, &ptr.to_ne_bytes()) }
106	}
107
108	/// If the object holds an [`IUnknown`](crate::IUnknown) COM value, returns
109	/// it, otherwise `None`.
110	///
111	/// Note that the returned object will be a clone – that is,
112	/// [`IUnknown::AddRef`](https://learn.microsoft.com/en-us/windows/win32/api/unknwn/nf-unknwn-iunknown-addref)
113	/// will be called.
114	#[must_use]
115	pub fn iunknown<T>(&self) -> Option<T>
116		where T: ole_IUnknown,
117	{
118		if self.vt() == co::VT::UNKNOWN {
119			let ptr = usize::from_ne_bytes(self.raw()[..8].try_into().unwrap());
120			let obj = ManuallyDrop::new(unsafe { T::from_ptr(ptr as *mut _) }); // won't release the stored pointer
121			let cloned = T::clone(&obj); // call AddRef
122			Some(cloned)
123		} else {
124			None
125		}
126	}
127}