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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
use super::*;
use bindings::Windows::Foundation::{IReference, IStringable, PropertyValue};

/// A WinRT object that may be used as a polymorphic stand-in for any WinRT class, interface, or boxed value.
/// `Object` implements the
/// [IInspectable](https://docs.microsoft.com/en-us/windows/win32/api/inspectable/nn-inspectable-iinspectable)
/// interface.
#[repr(transparent)]
#[derive(Clone, PartialEq, Eq)]
pub struct Object(IUnknown);

impl Object {
    /// Returns the canonical type name for the underlying object.
    pub fn type_name(&self) -> Result<HString> {
        unsafe {
            let mut abi = std::ptr::null_mut();
            (self.vtable().4)(self.abi(), &mut abi).ok()?;
            Ok(std::mem::transmute(abi))
        }
    }
}

#[repr(C)]
pub struct Object_vtable(
    pub unsafe extern "system" fn(this: RawPtr, iid: &Guid, interface: *mut RawPtr) -> ErrorCode,
    pub unsafe extern "system" fn(this: RawPtr) -> u32,
    pub unsafe extern "system" fn(this: RawPtr) -> u32,
    pub  unsafe extern "system" fn(
        this: RawPtr,
        count: *mut u32,
        values: *mut *mut Guid,
    ) -> ErrorCode,
    pub unsafe extern "system" fn(this: RawPtr, value: *mut RawPtr) -> ErrorCode,
    pub unsafe extern "system" fn(this: RawPtr, value: *mut i32) -> ErrorCode,
);

unsafe impl Interface for Object {
    type Vtable = Object_vtable;

    const IID: Guid = Guid::from_values(
        0xAF86_E2E0,
        0xB12D,
        0x4C6A,
        [0x9C, 0x5A, 0xD7, 0xAA, 0x65, 0x10, 0x1E, 0x90],
    );
}

unsafe impl RuntimeType for Object {
    type DefaultType = Option<Self>;

    const SIGNATURE: crate::ConstBuffer =
        crate::ConstBuffer::from_slice(b"cinterface(IInspectable)");
}

impl std::fmt::Debug for Object {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        // Attempts to retrieve the string representation of the object via the
        // IStringable interface. If that fails, it will use the canonical type
        // name to give some idea of what the object represents. This implementation
        // is used by all of the generated `Debug` implementations for WinRT
        // classes and interfaces.

        let name = self
            .cast::<IStringable>()
            .and_then(|s| s.ToString())
            .or_else(|_| self.type_name())
            .unwrap_or_default();

        write!(f, "{:?} {}", self.0, name)
    }
}

macro_rules! primitive_boxed_type {
    ($(($t:ty, $m:ident)),+) => {
        $(impl std::convert::TryFrom<$t> for Object {
            type Error = Error;
            fn try_from(value: $t) -> Result<Self> {
                PropertyValue::$m(value)
            }
        }
        impl std::convert::TryFrom<Object> for $t {
            type Error = Error;
            fn try_from(value: Object) -> Result<Self> {
                <Object as Interface>::cast::<IReference<$t>>(&value)?.Value()
            }
        }
        impl std::convert::TryFrom<&Object> for $t {
            type Error = Error;
            fn try_from(value: &Object) -> Result<Self> {
                <Object as Interface>::cast::<IReference<$t>>(value)?.Value()
            }
        })*
    };
}

primitive_boxed_type! {
    (bool, CreateBoolean),
    (u8, CreateUInt8),
    (i16, CreateInt16),
    (u16, CreateUInt16),
    (i32, CreateInt32),
    (u32, CreateUInt32),
    (i64, CreateInt64),
    (u64, CreateUInt64),
    (f32, CreateSingle),
    (f64, CreateDouble)
}

impl std::convert::TryFrom<&str> for Object {
    type Error = Error;
    fn try_from(value: &str) -> Result<Self> {
        PropertyValue::CreateString(value)
    }
}
impl std::convert::TryFrom<HString> for Object {
    type Error = Error;
    fn try_from(value: HString) -> Result<Self> {
        PropertyValue::CreateString(value)
    }
}
impl std::convert::TryFrom<&HString> for Object {
    type Error = Error;
    fn try_from(value: &HString) -> Result<Self> {
        PropertyValue::CreateString(value)
    }
}
impl std::convert::TryFrom<Object> for HString {
    type Error = Error;
    fn try_from(value: Object) -> Result<Self> {
        <Object as Interface>::cast::<IReference<HString>>(&value)?.Value()
    }
}
impl std::convert::TryFrom<&Object> for HString {
    type Error = Error;
    fn try_from(value: &Object) -> Result<Self> {
        <Object as Interface>::cast::<IReference<HString>>(value)?.Value()
    }
}