use windows::Win32::System::Variant::{
VariantInit, VariantChangeType, VariantClear, VAR_CHANGE_FLAGS, VARENUM,
VT_BSTR, VT_I4, VT_BOOL, VT_DISPATCH,
};
use windows::core::VARIANT;
use windows::Win32::System::Com::IDispatch;
use windows::core::{Result as WinResult, BSTR, Interface};
pub fn variant_empty() -> VARIANT {
unsafe { VariantInit() }
}
pub fn variant_bstr(s: &str) -> VARIANT {
VARIANT::from(s)
}
pub fn variant_i4(i: i32) -> VARIANT {
VARIANT::from(i)
}
pub fn variant_r8(f: f64) -> VARIANT {
VARIANT::from(f)
}
pub fn variant_bool(val: bool) -> VARIANT {
VARIANT::from(val)
}
pub fn variant_bstr_array(items: &[&str]) -> VARIANT {
let _ = items;
variant_empty()
}
fn coerce(var: &VARIANT, vt: VARENUM) -> WinResult<VARIANT> {
let mut dest = unsafe { VariantInit() };
unsafe { VariantChangeType(&mut dest as *mut VARIANT, var as *const VARIANT, VAR_CHANGE_FLAGS(0), vt)?; }
Ok(dest)
}
pub fn variant_to_string(var: &VARIANT) -> WinResult<Option<String>> {
let mut coerced = coerce(var, VT_BSTR)?;
let ptr = unsafe { (*coerced.as_raw()).Anonymous.Anonymous.Anonymous.bstrVal };
let out = if ptr.is_null() {
None
} else {
let b = unsafe { BSTR::from_raw(ptr as *mut u16) };
let s = b.to_string();
std::mem::forget(b);
Some(s)
};
unsafe { VariantClear(&mut coerced as *mut VARIANT)?; }
Ok(out)
}
pub fn variant_to_i32(var: &VARIANT) -> WinResult<Option<i32>> {
let mut coerced = coerce(var, VT_I4)?;
let val = unsafe { (*coerced.as_raw()).Anonymous.Anonymous.Anonymous.lVal };
unsafe { VariantClear(&mut coerced as *mut VARIANT)?; }
Ok(Some(val))
}
pub fn variant_to_bool(var: &VARIANT) -> WinResult<Option<bool>> {
let mut coerced = coerce(var, VT_BOOL)?;
let vbool = unsafe { (*coerced.as_raw()).Anonymous.Anonymous.Anonymous.boolVal };
unsafe { VariantClear(&mut coerced as *mut VARIANT)?; }
Ok(Some(vbool != 0))
}
pub fn variant_to_dispatch(var: &VARIANT) -> WinResult<Option<IDispatch>> {
let mut coerced = coerce(var, VT_DISPATCH)?;
let ptr = unsafe { (*coerced.as_raw()).Anonymous.Anonymous.Anonymous.pdispVal };
if ptr.is_null() {
unsafe { VariantClear(&mut coerced as *mut VARIANT)?; }
return Ok(None);
}
let disp = unsafe { IDispatch::from_raw(ptr.cast()) };
let keep = disp.clone();
std::mem::forget(disp);
unsafe { VariantClear(&mut coerced as *mut VARIANT)?; }
Ok(Some(keep))
}