use core::mem::ManuallyDrop;
use windows::Win32::Foundation::{VARIANT_FALSE, VARIANT_TRUE};
use windows::Win32::System::Variant::{
VAR_CHANGE_FLAGS, VARENUM, VARIANT, VARIANT_0, VARIANT_0_0, VARIANT_0_0_0, VT_BOOL, VT_BSTR,
VariantChangeType, VariantClear,
};
use windows_core::BSTR;
fn assemble(vt: VARENUM, payload: VARIANT_0_0_0) -> VARIANT {
VARIANT {
Anonymous: VARIANT_0 {
Anonymous: ManuallyDrop::new(VARIANT_0_0 {
vt,
wReserved1: 0,
wReserved2: 0,
wReserved3: 0,
Anonymous: payload,
}),
},
}
}
pub unsafe fn to_string(value: &VARIANT) -> windows_core::Result<String> {
let mut coerced = VARIANT::default();
unsafe { VariantChangeType(&mut coerced, value, VAR_CHANGE_FLAGS(0), VT_BSTR)? };
let text = unsafe { coerced.Anonymous.Anonymous.Anonymous.bstrVal.to_string() };
unsafe {
let _ = VariantClear(&mut coerced);
}
Ok(text)
}
pub unsafe fn to_bool(value: &VARIANT) -> windows_core::Result<bool> {
let mut coerced = VARIANT::default();
unsafe { VariantChangeType(&mut coerced, value, VAR_CHANGE_FLAGS(0), VT_BOOL)? };
let value = unsafe { coerced.Anonymous.Anonymous.Anonymous.boolVal.0 != 0 };
unsafe {
let _ = VariantClear(&mut coerced);
}
Ok(value)
}
pub unsafe fn write_string(out: *mut VARIANT, text: &str) {
if out.is_null() {
return;
}
let value = assemble(
VT_BSTR,
VARIANT_0_0_0 {
bstrVal: ManuallyDrop::new(BSTR::from(text)),
},
);
unsafe { out.write(value) };
}
pub unsafe fn write_bool(out: *mut VARIANT, value: bool) {
if out.is_null() {
return;
}
let variant = assemble(
VT_BOOL,
VARIANT_0_0_0 {
boolVal: if value { VARIANT_TRUE } else { VARIANT_FALSE },
},
);
unsafe { out.write(variant) };
}
pub unsafe fn sole_argument<'a>(
params: *const windows::Win32::System::Com::DISPPARAMS,
) -> Option<&'a VARIANT> {
if params.is_null() {
return None;
}
let params = unsafe { &*params };
if params.cArgs == 0 || params.rgvarg.is_null() {
return None;
}
unsafe { params.rgvarg.as_ref() }
}