clroxide 1.1.1

A library that allows you to host the CLR and execute dotnet binaries.
Documentation
use std::{ffi::c_void, mem::ManuallyDrop, ptr};
use windows::{
    core::BSTR,
    Win32::{
        Foundation::VARIANT_BOOL,
        System::{
            Com::{
                SAFEARRAY, SAFEARRAYBOUND, VARENUM, VARIANT, VARIANT_0, VARIANT_0_0, VARIANT_0_0_0,
                VT_ARRAY, VT_BOOL, VT_BSTR, VT_EMPTY, VT_I8, VT_UI1, VT_UNKNOWN, VT_VARIANT,
            },
            Ole::{
                SafeArrayAccessData, SafeArrayCreate, SafeArrayCreateVector, SafeArrayGetElement,
                SafeArrayGetLBound, SafeArrayGetUBound, SafeArrayPutElement, SafeArrayUnaccessData,
            },
        },
    },
};

pub fn prepare_assembly(bytes: &[u8]) -> Result<*mut SAFEARRAY, String> {
    let mut bounds = SAFEARRAYBOUND {
        cElements: bytes.len() as _,
        lLbound: 0,
    };

    let safe_array_ptr: *mut SAFEARRAY = unsafe { SafeArrayCreate(VT_UI1, 1, &mut bounds) };
    let mut pv_data: *mut c_void = ptr::null_mut();

    match unsafe { SafeArrayAccessData(safe_array_ptr, &mut pv_data) } {
        Ok(_) => {},
        Err(e) => {
            return Err(format!(
                "Could not prepare assembly due to a safe array related error: {:?}",
                e.code()
            ))
        },
    }

    unsafe { ptr::copy_nonoverlapping(bytes.as_ptr(), pv_data.cast(), bytes.len()) };

    match unsafe { SafeArrayUnaccessData(safe_array_ptr) } {
        Ok(_) => {},
        Err(e) => {
            return Err(format!(
                "Could not prepare assembly due to a safe array related error: {:?}",
                e.code()
            ))
        },
    };

    Ok(safe_array_ptr)
}

pub fn get_array_length(array_ptr: *mut SAFEARRAY) -> i32 {
    let upper = unsafe { SafeArrayGetUBound(array_ptr, 1) }.unwrap_or(0);
    let lower = unsafe { SafeArrayGetLBound(array_ptr, 1) }.unwrap_or(0);

    match upper - lower {
        0 => 0,
        delta => delta + 1,
    }
}

pub fn empty_array() -> *mut SAFEARRAY {
    unsafe { SafeArrayCreateVector(VT_EMPTY, 0, 0) }
}

pub fn empty_variant_array() -> *mut SAFEARRAY {
    unsafe { SafeArrayCreateVector(VT_VARIANT, 0, 0) }
}

pub fn wrap_unknown_ptr_in_variant(unknown_ptr: *mut c_void) -> VARIANT {
    let unknown = unsafe { std::mem::transmute(unknown_ptr) };

    VARIANT {
        Anonymous: VARIANT_0 {
            Anonymous: ManuallyDrop::new(VARIANT_0_0 {
                vt: VT_UNKNOWN,
                wReserved1: 0,
                wReserved2: 0,
                wReserved3: 0,
                Anonymous: VARIANT_0_0_0 {
                    punkVal: ManuallyDrop::new(Some(unknown)),
                },
            }),
        },
    }
}

pub fn wrap_bool_in_variant(value: bool) -> VARIANT {
    VARIANT {
        Anonymous: VARIANT_0 {
            Anonymous: ManuallyDrop::new(VARIANT_0_0 {
                vt: VT_BOOL,
                wReserved1: 0,
                wReserved2: 0,
                wReserved3: 0,
                Anonymous: VARIANT_0_0_0 {
                    boolVal: VARIANT_BOOL::from(value),
                },
            }),
        },
    }
}

pub fn wrap_i64_in_variant(value: i64) -> VARIANT {
    VARIANT {
        Anonymous: VARIANT_0 {
            Anonymous: ManuallyDrop::new(VARIANT_0_0 {
                vt: VT_I8,
                wReserved1: 0,
                wReserved2: 0,
                wReserved3: 0,
                Anonymous: VARIANT_0_0_0 { llVal: value },
            }),
        },
    }
}

pub fn wrap_string_in_variant(string: &str) -> VARIANT {
    let inner = BSTR::from(string);

    VARIANT {
        Anonymous: VARIANT_0 {
            Anonymous: ManuallyDrop::new(VARIANT_0_0 {
                vt: VT_BSTR,
                wReserved1: 0,
                wReserved2: 0,
                wReserved3: 0,
                Anonymous: VARIANT_0_0_0 {
                    bstrVal: ManuallyDrop::new(inner),
                },
            }),
        },
    }
}

pub fn wrap_strings_in_array(strings: &[String]) -> Result<VARIANT, String> {
    let mut inner = vec![];

    for string in strings.iter() {
        inner.push(BSTR::from(string).into_raw())
    }

    let safe_array_ptr: *mut SAFEARRAY =
        unsafe { SafeArrayCreateVector(VT_BSTR, 0, inner.len() as u32) };

    for i in 0..inner.len() {
        let indices: [i32; 1] = [i as _];
        let v_ref = &inner[i];
        match unsafe { SafeArrayPutElement(safe_array_ptr, indices.as_ptr(), *v_ref as *const _) } {
            Ok(_) => {},
            Err(e) => {
                return Err(format!(
                    "Could not create an array of strings: {:?}",
                    e.code()
                ))
            },
        }
    }

    Ok(VARIANT {
        Anonymous: VARIANT_0 {
            Anonymous: ManuallyDrop::new(VARIANT_0_0 {
                vt: VARENUM(VT_BSTR.0 | VT_ARRAY.0),
                wReserved1: 0,
                wReserved2: 0,
                wReserved3: 0,
                Anonymous: VARIANT_0_0_0 {
                    parray: safe_array_ptr,
                },
            }),
        },
    })
}

pub fn wrap_method_arguments(arguments: Vec<VARIANT>) -> Result<*mut SAFEARRAY, String> {
    let variant_array_ptr: *mut SAFEARRAY =
        unsafe { SafeArrayCreateVector(VT_VARIANT, 0, arguments.len() as u32) };

    for i in 0..arguments.len() {
        let indices: [i32; 1] = [i as _];
        let v_ref: *const _ = &arguments[i];
        match unsafe { SafeArrayPutElement(variant_array_ptr, indices.as_ptr(), v_ref as *const _) }
        {
            Ok(_) => {},
            Err(e) => {
                return Err(format!(
                    "Could not create an array of arguments: {:?}",
                    e.code()
                ))
            },
        }
    }

    Ok(variant_array_ptr)
}

pub fn unpack_byte_array(safe_array_ptr: *mut SAFEARRAY) -> Result<Vec<u8>, String> {
    let ubound = unsafe { SafeArrayGetUBound(safe_array_ptr, 1) }.unwrap_or(0);
    let mut results: Vec<u8> = vec![];

    for i in 0..ubound {
        let indices: [i32; 1] = [i as _];
        let mut variant: u8 = 0;
        let pv = &mut variant as *mut _ as *mut c_void;

        match unsafe { SafeArrayGetElement(safe_array_ptr, indices.as_ptr(), pv) } {
            Ok(_) => {},
            Err(e) => return Err(format!("Could not access safe array: {:?}", e.code())),
        }

        if !pv.is_null() {
            results.push(variant);
        }
    }

    Ok(results)
}