clroxide 1.1.1

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

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

unsafe impl Sync for _AppDomain {}
unsafe impl Send for _AppDomain {}

#[repr(C)]
pub struct _AppDomainVtbl {
    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 InitializeLifetimeService: *const c_void,
    pub GetLifetimeService: *const c_void,
    pub get_Evidence: *const c_void,
    pub set_Evidence: *const c_void,
    pub get_DomainUnload: *const c_void,
    pub set_DomainUnload: *const c_void,
    pub get_AssemblyLoad: *const c_void,
    pub set_AssemblyLoad: *const c_void,
    pub get_ProcessExit: *const c_void,
    pub set_ProcessExit: *const c_void,
    pub get_TypeResolve: *const c_void,
    pub set_TypeResolve: *const c_void,
    pub get_ResourceResolve: *const c_void,
    pub set_ResourceResolve: *const c_void,
    pub get_AssemblyResolve: *const c_void,
    pub get_UnhandledException: *const c_void,
    pub set_UnhandledException: *const c_void,
    pub DefineDynamicAssembly: *const c_void,
    pub DefineDynamicAssembly_2: *const c_void,
    pub DefineDynamicAssembly_3: *const c_void,
    pub DefineDynamicAssembly_4: *const c_void,
    pub DefineDynamicAssembly_5: *const c_void,
    pub DefineDynamicAssembly_6: *const c_void,
    pub DefineDynamicAssembly_7: *const c_void,
    pub DefineDynamicAssembly_8: *const c_void,
    pub DefineDynamicAssembly_9: *const c_void,
    pub CreateInstance: *const c_void,
    pub CreateInstanceFrom: *const c_void,
    pub CreateInstance_2: *const c_void,
    pub CreateInstanceFrom_2: *const c_void,
    pub CreateInstance_3: *const c_void,
    pub CreateInstanceFrom_3: *const c_void,
    pub Load: *const c_void,
    pub Load_2: unsafe extern "system" fn(
        this: *mut c_void,
        assemblyString: *mut u16,
        pRetVal: *mut *mut _Assembly,
    ) -> HRESULT,
    pub Load_3: unsafe extern "system" fn(
        this: *mut c_void,
        rawAssembly: *mut SAFEARRAY,
        pRetVal: *mut *mut _Assembly,
    ) -> HRESULT,
    pub Load_4: *const c_void,
    pub Load_5: *const c_void,
    pub Load_6: *const c_void,
    pub Load_7: *const c_void,
    pub ExecuteAssembly: *const c_void,
    pub ExecuteAssembly_2: *const c_void,
    pub ExecuteAssembly_3: *const c_void,
    pub get_FriendlyName: *const c_void,
    pub get_BaseDirectory: *const c_void,
    pub get_RelativeSearchPath: *const c_void,
    pub get_ShadowCopyFiles: *const c_void,
    pub GetAssemblies: *const c_void,
    pub AppendPrivatePath: *const c_void,
    pub ClearPrivatePath: *const c_void,
    pub ClearShadowCopyPath: *const c_void,
    pub SetData: *const c_void,
    pub GetData: *const c_void,
    pub SetAppDomainPolicy: *const c_void,
    pub SetThreadPrincipal: *const c_void,
    pub SetPrincipalPolicy: *const c_void,
    pub DoCallBack: *const c_void,
    pub get_DynamicDirectory: *const c_void,
}

impl _AppDomain {
    pub fn load_library(&self, library: &str) -> Result<*mut _Assembly, String> {
        let library_buffer = BSTR::from(library);

        let mut library_ptr: *mut _Assembly = ptr::null_mut();

        let hr = unsafe { (*self).Load_2(library_buffer.into_raw() as *mut _, &mut library_ptr) };

        if hr.is_err() {
            return Err(format!("Could not retrieve `{}`: {:?}", library, hr));
        }

        if library_ptr.is_null() {
            return Err(format!("Could not retrieve `{}`", library));
        }

        Ok(library_ptr)
    }

    pub fn load_assembly(&self, bytes: &[u8]) -> Result<*mut _Assembly, String> {
        let assembly_bytes = prepare_assembly(bytes)?;

        let mut assembly_ptr: *mut _Assembly = ptr::null_mut();

        let hr = unsafe { (*self).Load_3(assembly_bytes, &mut assembly_ptr) };

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

        if assembly_ptr.is_null() {
            return Err("Could not retrieve assembly".into());
        }

        Ok(assembly_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 Load_2(&self, assemblyString: *mut u16, pRetVal: *mut *mut _Assembly) -> HRESULT {
        ((*self.vtable).Load_2)(self as *const _ as *mut _, assemblyString, pRetVal)
    }

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

impl Interface for _AppDomain {
    const IID: GUID = GUID::from_values(
        0x05F696DC,
        0x2B29,
        0x3663,
        [0xAD, 0x8B, 0xC4, 0x38, 0x9C, 0xF2, 0xA7, 0x13],
    );

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

impl Deref for _AppDomain {
    type Target = IUnknown;

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