clroxide 1.1.1

A library that allows you to host the CLR and execute dotnet binaries.
Documentation
use crate::primitives::{
    empty_variant_array, get_array_length, itype::_Type, IUnknown, IUnknownVtbl, Interface, GUID,
    HRESULT,
};
use std::{
    ffi::{c_long, c_void},
    ops::Deref,
};
use windows::{
    core::BSTR,
    Win32::System::{
        Com::{SAFEARRAY, VARIANT, VT_UNKNOWN},
        Ole::SafeArrayCreateVector,
    },
};

#[repr(C)]
pub struct _ConstructorInfo {
    pub vtable: *const _ConstructorInfoVtbl,
}

#[repr(C)]
pub struct _ConstructorInfoVtbl {
    pub parent: IUnknownVtbl,
    pub GetTypeInfoCount: *const c_void,
    pub GetTypeInfo: *const c_void,
    pub GetIDsOfNames: *const c_void,
    pub Invoke: *const c_void,
    pub ToString: unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut u16) -> HRESULT,
    pub Equals: *const c_void,
    pub GetHashCode: unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut c_long) -> HRESULT,
    pub GetType: unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut _Type) -> HRESULT,
    pub get_MemberType: *const c_void,
    pub get_name: unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut u16) -> HRESULT,
    pub get_DeclaringType: *const c_void,
    pub get_ReflectedType: *const c_void,
    pub GetCustomAttributes: *const c_void,
    pub GetCustomAttributes_2: *const c_void,
    pub IsDefined: *const c_void,
    pub GetParameters:
        unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut SAFEARRAY) -> HRESULT,
    pub GetMethodImplementationFlags: *const c_void,
    pub get_MethodHandle: *const c_void,
    pub get_Attributes: *const c_void,
    pub get_CallingConvention: *const c_void,
    pub Invoke_2: *const c_void,
    pub get_IsPublic: *const c_void,
    pub get_IsPrivate: *const c_void,
    pub get_IsFamily: *const c_void,
    pub get_IsAssembly: *const c_void,
    pub get_IsFamilyAndAssembly: *const c_void,
    pub get_IsFamilyOrAssembly: *const c_void,
    pub get_IsStatic: *const c_void,
    pub get_IsFinal: *const c_void,
    pub get_IsVirtual: *const c_void,
    pub get_IsHideBySig: *const c_void,
    pub get_IsAbstract: *const c_void,
    pub get_IsSpecialName: *const c_void,
    pub get_IsConstructor: *const c_void,
    pub Invoke_3: unsafe extern "system" fn(
        this: *mut c_void,
        obj: VARIANT,
        parameters: *mut SAFEARRAY,
        pRetVal: *mut VARIANT,
    ) -> HRESULT,
    pub Invoke_4: *const c_void,
    pub Invoke_5: unsafe extern "system" fn(
        this: *mut c_void,
        parameters: *mut SAFEARRAY,
        pRetVal: *mut VARIANT,
    ) -> HRESULT,
}

impl _ConstructorInfo {
    pub fn invoke(&self, args: *mut SAFEARRAY) -> Result<VARIANT, String> {
        let args_len = get_array_length(args);
        let parameter_count = (*self).get_parameter_count()?;

        if args_len != parameter_count {
            return Err(format!(
                "Arguments do not match method signature: {} given, {} expected",
                args_len, parameter_count
            ));
        }

        let mut return_value: VARIANT = unsafe { std::mem::zeroed() };

        let hr = unsafe { (*self).Invoke_5(args, &mut return_value) };

        if hr.is_err() {
            return Err(format!("Could not invoke method: {:?}", hr));
        }

        Ok(return_value)
    }

    pub fn invoke_without_args(&self) -> Result<VARIANT, String> {
        (*self).invoke(empty_variant_array())
    }

    pub fn get_parameter_count(&self) -> Result<i32, String> {
        let mut safe_array_ptr: *mut SAFEARRAY =
            unsafe { SafeArrayCreateVector(VT_UNKNOWN, 0, 255) };

        let hr = unsafe { (*self).GetParameters(&mut safe_array_ptr) };

        if hr.is_err() {
            return Err(format!("Could not get parameter count: {:?}", hr));
        }

        Ok(get_array_length(safe_array_ptr))
    }

    pub fn to_string(&self) -> Result<String, String> {
        let mut buffer = BSTR::new();

        let hr = unsafe { (*self).ToString(&mut buffer as *mut _ as *mut *mut u16) };

        if hr.is_err() {
            return Err(format!("Failed while running `ToString`: {:?}", hr));
        }

        Ok(buffer.to_string())
    }

    #[inline]
    pub unsafe fn ToString(&self, pRetVal: *mut *mut u16) -> HRESULT {
        ((*self.vtable).ToString)(self as *const _ as *mut _, pRetVal)
    }

    #[inline]
    pub unsafe fn GetHashCode(&self, pRetVal: *mut c_long) -> HRESULT {
        ((*self.vtable).GetHashCode)(self as *const _ as *mut _, pRetVal)
    }

    #[inline]
    pub unsafe fn GetType(&self, pRetVal: *mut *mut _Type) -> HRESULT {
        ((*self.vtable).GetType)(self as *const _ as *mut _, pRetVal)
    }

    #[inline]
    pub unsafe fn get_name(&self, pRetVal: *mut *mut u16) -> HRESULT {
        ((*self.vtable).get_name)(self as *const _ as *mut _, pRetVal)
    }

    #[inline]
    pub unsafe fn GetParameters(&self, pRetVal: *mut *mut SAFEARRAY) -> HRESULT {
        ((*self.vtable).GetParameters)(self as *const _ as *mut _, pRetVal)
    }

    #[inline]
    pub unsafe fn Invoke_3(
        &self,
        obj: VARIANT,
        parameters: *mut SAFEARRAY,
        pRetVal: *mut VARIANT,
    ) -> HRESULT {
        ((*self.vtable).Invoke_3)(self as *const _ as *mut _, obj, parameters, pRetVal)
    }

    #[inline]
    pub unsafe fn Invoke_5(&self, parameters: *mut SAFEARRAY, pRetVal: *mut VARIANT) -> HRESULT {
        ((*self.vtable).Invoke_5)(self as *const _ as *mut _, parameters, pRetVal)
    }
}

impl Interface for _ConstructorInfo {
    const IID: GUID = GUID::from_values(
        0xe9a19478,
        0x9646,
        0x3679,
        [0x9b, 0x10, 0x84, 0x11, 0xae, 0x1f, 0xd5, 0x7d],
    );

    fn vtable(&self) -> *const c_void {
        self.vtable as *const _ as *const c_void
    }
}

impl Deref for _ConstructorInfo {
    type Target = IUnknown;

    #[inline]
    fn deref(&self) -> &IUnknown {
        unsafe { &*(self as *const _ConstructorInfo as *const IUnknown) }
    }
}