1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//! # win-variant
//!
//! win-variant is a crate to improve the ergonomics of working with VARIANTS
//! from winapi.
//!
//! The crate uses enums and conversion traits to allow for modern rust usage
//! as well as provides utilities to easily free VARIANTS correctly.

mod arg;
mod errors;
mod result;

use winapi::{
    shared::wtypes::{VARENUM, VT_BSTR},
    um::{
        oaidl::VARIANT,
        oleauto::{SysFreeString, VariantClear},
    },
};

pub use arg::VariantArg;
pub use errors::{VariantArgError, VariantResultError};
pub use result::VariantResult;

/// free_variants is a utility to properly free the allocated resources of
/// variants.
pub fn free_variants(variants: &mut Vec<VARIANT>) {
    for variant in variants {
        unsafe {
            free_variant(variant);
        }
    }
}

/// free_variant is a utility to properly free the allocated resources of a
/// variant.
pub unsafe fn free_variant(variant: &mut VARIANT) {
    match variant.n1.n2().vt as VARENUM {
        VT_BSTR => {
            let p = variant.n1.n2_mut().n3.bstrVal();
            println!("freeing BSTR: {:?}", p);
            SysFreeString(*p);
        }
        _ => (),
    };
    VariantClear(variant);
}

#[cfg(test)]
mod tests {
    use crate::{free_variant, VariantArg, VariantResult};
    use std::convert::TryFrom;
    use winapi::um::oaidl::VARIANT;

    #[test]
    fn it_converts_to_result_from_bstr_arg() {
        let src = "Test Value";
        let _arg = VariantArg::try_from(src).unwrap();

        let mut v: VARIANT = _arg.into();
        let result = VariantResult::try_from(v).unwrap();
        unsafe {
            free_variant(&mut v);
        }

        if let VariantResult::String(v) = result {
            if !src.eq(&v) {
                panic!(format!("expected {:?}, got {:?}", src, v));
            }
        } else {
            panic!(format!("expected String, got: {:?}", result));
        }
    }

    #[test]
    fn it_converts_to_result_from_int_arg() {
        let src: i32 = 1234;
        let _arg = VariantArg::from(src);

        let mut v: VARIANT = _arg.into();
        let result = VariantResult::try_from(v).unwrap();
        unsafe {
            free_variant(&mut v);
        }

        if let VariantResult::Int(v) = result {
            if src != v {
                panic!(format!("expected {:}, got {:}", src, v));
            }
        } else {
            panic!(format!("expected Int, got {:?}", result));
        }
    }

    #[test]
    fn it_converts_to_result_from_uint_arg() {
        let src: u32 = 1234;
        let _arg = VariantArg::from(src);

        let mut v: VARIANT = _arg.into();
        let result = VariantResult::try_from(v).unwrap();
        unsafe {
            free_variant(&mut v);
        }

        if let VariantResult::Uint(v) = result {
            if src != v {
                panic!(format!("expected {:}, got {:}", src, v));
            }
        } else {
            panic!(format!("expected Int, got {:?}", result));
        }
    }
}