use std::{
convert::{TryFrom, TryInto},
ptr,
};
use log::trace;
use widestring::U16CString;
use winapi::{
shared::{
minwindef::{UINT, ULONG},
winerror::NOERROR,
wtypes::{
VARTYPE, VT_BOOL, VT_BSTR, VT_EMPTY, VT_I2, VT_I4, VT_I8, VT_INT, VT_R4, VT_R8,
VT_SAFEARRAY, VT_UI2, VT_UI4, VT_UI8, VT_UINT,
},
},
um::{
oaidl::{SAFEARRAY, SAFEARRAYBOUND, VARIANT},
oleauto::{
SafeArrayCreateVector, SafeArrayDestroy, SafeArrayGetLBound, SafeArrayGetUBound,
SysAllocStringLen, VariantInit,
},
winnt::{HRESULT, LONG, PVOID},
},
};
use crate::{errors::SafeArrayError, BOOL_FALSE, BOOL_TRUE};
mod multidim;
mod serialize;
#[cfg(test)]
mod tests;
extern "system" {
pub fn SafeArrayGetElement(psa: *mut SAFEARRAY, rgIndices: *const LONG, pv: PVOID) -> HRESULT;
pub fn SafeArrayGetVartype(psa: *mut SAFEARRAY, pvt: *const VARTYPE) -> HRESULT;
pub fn SafeArrayPutElement(psa: *mut SAFEARRAY, rgIndices: *const LONG, pv: PVOID) -> HRESULT;
}
#[derive(Debug)]
pub struct SafeArray {
psa: *mut SAFEARRAY,
prevent_destroy: bool,
}
impl Drop for SafeArray {
fn drop(&mut self) {
if !self.prevent_destroy {
self.destroy().unwrap();
}
}
}
impl SafeArray {
pub fn new_vector(
vt: VARTYPE,
lower_bound: LONG,
length: u32,
) -> Result<SafeArray, SafeArrayError> {
let arr = unsafe { SafeArrayCreateVector(vt, lower_bound, length) };
if arr.is_null() {
Err(SafeArrayError::NullPointer)
} else {
trace!("allocated safe array {:?}", arr);
Ok(SafeArray {
psa: arr,
prevent_destroy: false,
})
}
}
pub fn destroy(&mut self) -> Result<(), SafeArrayError> {
if self.psa.is_null() {
return Ok(());
}
unsafe {
trace!("destroying safe array {:?}", self.psa);
match SafeArrayDestroy(self.psa) {
NOERROR => {
self.psa = ptr::null_mut();
Ok(())
}
hr => Err(SafeArrayError::from(hr)),
}
}
}
pub fn dimensions_count(&self) -> Result<u16, SafeArrayError> {
trace!("getting dimension count: {:?}", self.psa);
unsafe {
let r = self.psa.as_ref().ok_or(SafeArrayError::NullPointer)?;
Ok(r.cDims)
}
}
pub fn dimension_lower_bound(&self, dimension: u32) -> Result<LONG, SafeArrayError> {
trace!("getting dimension lower: {:?}", self.psa);
unsafe {
let mut value: LONG = 0;
match SafeArrayGetLBound(self.psa, dimension, &mut value) {
NOERROR => Ok(value),
hr => Err(SafeArrayError::from(hr)),
}
}
}
pub fn dimension_upper_bound(&self, dimension: u32) -> Result<LONG, SafeArrayError> {
trace!("getting dimension upper: {:?}", self.psa);
unsafe {
let mut value: LONG = 0;
match SafeArrayGetUBound(self.psa, dimension, &mut value) {
NOERROR => Ok(value),
hr => Err(SafeArrayError::from(hr)),
}
}
}
pub fn dimensions(&self) -> Result<Vec<SAFEARRAYBOUND>, SafeArrayError> {
trace!("getting dimensions: {:?}", self.psa);
unsafe {
let r = self.psa.as_ref().ok_or(SafeArrayError::NullPointer)?;
let mut bounds: Vec<SAFEARRAYBOUND> = Vec::with_capacity(r.cDims as usize);
for i in 1..(r.cDims + 1) as u32 {
let lower = self.dimension_lower_bound(i)?;
let upper = self.dimension_upper_bound(i)?;
bounds.push(SAFEARRAYBOUND {
lLbound: lower,
cElements: (1 + upper - lower) as ULONG,
});
}
Ok(bounds)
}
}
pub fn get_vartype(&self) -> Result<VARTYPE, SafeArrayError> {
trace!("getting var type: {:?}", self.psa);
let mut vt: VARTYPE = VT_EMPTY as u16;
let vt_ref: *mut VARTYPE = &mut vt;
let result = unsafe { SafeArrayGetVartype(self.psa, vt_ref) };
if result != NOERROR {
return Err(SafeArrayError::from(result));
}
Ok(vt)
}
fn to_vector<R>(&self, expected_type: VARTYPE) -> Result<Vec<R>, SafeArrayError>
where
R: Default,
{
let vt = self.get_vartype()?;
if vt != expected_type {
return Err(SafeArrayError::IncorrectDataType(vt));
}
if self.dimensions_count()? != 1 {
return Err(SafeArrayError::DimensionMismatch);
}
let lower = self.dimension_lower_bound(1)?;
let upper = self.dimension_upper_bound(1)?;
let mut result_arr: Vec<R> = Vec::with_capacity((upper - lower) as usize);
for i in lower..=upper {
let mut indices: [i32; 1] = [i];
let mut v: R = R::default();
let v_ref: *mut R = &mut v;
let result =
unsafe { SafeArrayGetElement(self.psa, indices.as_mut_ptr(), v_ref as PVOID) };
if result != NOERROR {
return Err(SafeArrayError::from(result));
}
result_arr.push(v);
}
Ok(result_arr)
}
fn from_vector<T>(src: &[T], vt: VARTYPE) -> Result<SafeArray, SafeArrayError> {
let sa = SafeArray::new_vector(vt, 0, src.len() as u32)?;
for (i, item) in src.iter().enumerate() {
let mut indices: [i32; 1] = [i as i32];
let v: *const T = item;
let result = unsafe { SafeArrayPutElement(sa.psa, indices.as_mut_ptr(), v as PVOID) };
if result != NOERROR {
return Err(SafeArrayError::from(result));
}
}
Ok(sa)
}
fn from_str_vector<S>(src: &[S]) -> Result<SafeArray, SafeArrayError>
where
S: AsRef<str>,
{
let sa = SafeArray::new_vector(VT_BSTR as u16, 0, src.len() as u32)?;
for (i, item) in src.iter().enumerate() {
let mut indices: [i32; 1] = [i as i32];
let bstr = U16CString::from_str(item)?;
let result = unsafe {
let bstr_ptr = SysAllocStringLen(bstr.as_ptr(), bstr.len() as UINT);
SafeArrayPutElement(sa.psa, indices.as_mut_ptr(), bstr_ptr as PVOID)
};
if result != NOERROR {
return Err(SafeArrayError::from(result));
}
}
Ok(sa)
}
fn to_string_vector(&self) -> Result<Vec<String>, SafeArrayError> {
let vt = self.get_vartype()?;
if vt != VT_BSTR as u16 {
return Err(SafeArrayError::IncorrectDataType(vt));
}
if self.dimensions_count()? != 1 {
return Err(SafeArrayError::DimensionMismatch);
}
let lower = self.dimension_lower_bound(1)?;
let upper = self.dimension_upper_bound(1)?;
let mut result_arr = Vec::with_capacity((upper - lower) as usize);
for i in lower..=upper {
let mut indices: [i32; 1] = [i];
let v = unsafe {
let mut v_ptr = ptr::null();
let v_ptr_ptr: *mut *const u16 = &mut v_ptr;
match SafeArrayGetElement(self.psa, indices.as_mut_ptr(), v_ptr_ptr as PVOID) {
NOERROR => (),
hr => return Err(SafeArrayError::from(hr)),
};
let u16_str = U16CString::from_ptr_str(v_ptr);
u16_str.to_string()?
};
result_arr.push(v);
}
Ok(result_arr)
}
}
impl From<*mut SAFEARRAY> for SafeArray {
fn from(psa: *mut SAFEARRAY) -> Self {
SafeArray {
psa,
prevent_destroy: false,
}
}
}
impl From<SafeArray> for VARIANT {
fn from(mut sa: SafeArray) -> VARIANT {
sa.prevent_destroy = true;
let mut v = VARIANT::default();
unsafe {
VariantInit(&mut v);
let n2 = v.n1.n2_mut();
n2.vt = VT_SAFEARRAY as u16;
let _val = n2.n3.parray_mut();
*_val = sa.psa;
}
v
}
}
impl TryFrom<&Vec<bool>> for SafeArray {
type Error = SafeArrayError;
fn try_from(val: &Vec<bool>) -> Result<Self, Self::Error> {
let converted: Vec<i16> = val
.iter()
.map(|v| if *v { BOOL_TRUE } else { BOOL_FALSE })
.collect();
SafeArray::from_vector(&converted, VT_BOOL as u16)
}
}
impl TryInto<Vec<bool>> for SafeArray {
type Error = SafeArrayError;
fn try_into(self) -> Result<Vec<bool>, Self::Error> {
let result: Vec<i16> = self.to_vector(VT_BOOL as u16)?;
Ok(result.iter().map(|v| *v == BOOL_TRUE).collect())
}
}
impl TryFrom<&Vec<i16>> for SafeArray {
type Error = SafeArrayError;
fn try_from(value: &Vec<i16>) -> Result<Self, Self::Error> {
SafeArray::from_vector(value, VT_I2 as u16)
}
}
impl TryInto<Vec<i16>> for SafeArray {
type Error = SafeArrayError;
fn try_into(self) -> Result<Vec<i16>, Self::Error> {
self.to_vector(VT_I2 as u16)
}
}
impl TryFrom<&Vec<i32>> for SafeArray {
type Error = SafeArrayError;
fn try_from(value: &Vec<i32>) -> Result<Self, Self::Error> {
SafeArray::from_vector(value, VT_I4 as u16)
}
}
impl TryInto<Vec<i32>> for SafeArray {
type Error = SafeArrayError;
fn try_into(self) -> Result<Vec<i32>, Self::Error> {
match self.get_vartype()? as u32 {
VT_I4 => self.to_vector(VT_I4 as u16),
VT_INT => self.to_vector(VT_INT as u16),
vt => Err(SafeArrayError::IncorrectDataType(vt as u16)),
}
}
}
impl TryFrom<&Vec<i64>> for SafeArray {
type Error = SafeArrayError;
fn try_from(value: &Vec<i64>) -> Result<Self, Self::Error> {
SafeArray::from_vector(value, VT_I8 as u16)
}
}
impl TryInto<Vec<i64>> for SafeArray {
type Error = SafeArrayError;
fn try_into(self) -> Result<Vec<i64>, Self::Error> {
self.to_vector(VT_I8 as u16)
}
}
impl TryFrom<&Vec<f32>> for SafeArray {
type Error = SafeArrayError;
fn try_from(value: &Vec<f32>) -> Result<Self, Self::Error> {
SafeArray::from_vector(value, VT_R4 as u16)
}
}
impl TryInto<Vec<f32>> for SafeArray {
type Error = SafeArrayError;
fn try_into(self) -> Result<Vec<f32>, Self::Error> {
self.to_vector(VT_R4 as u16)
}
}
impl TryFrom<&Vec<f64>> for SafeArray {
type Error = SafeArrayError;
fn try_from(value: &Vec<f64>) -> Result<Self, Self::Error> {
SafeArray::from_vector(value, VT_R8 as u16)
}
}
impl TryInto<Vec<f64>> for SafeArray {
type Error = SafeArrayError;
fn try_into(self) -> Result<Vec<f64>, Self::Error> {
self.to_vector(VT_R8 as u16)
}
}
impl TryFrom<&Vec<u16>> for SafeArray {
type Error = SafeArrayError;
fn try_from(value: &Vec<u16>) -> Result<Self, Self::Error> {
SafeArray::from_vector(value, VT_UI2 as u16)
}
}
impl TryInto<Vec<u16>> for SafeArray {
type Error = SafeArrayError;
fn try_into(self) -> Result<Vec<u16>, Self::Error> {
self.to_vector(VT_UI2 as u16)
}
}
impl TryFrom<&Vec<u32>> for SafeArray {
type Error = SafeArrayError;
fn try_from(value: &Vec<u32>) -> Result<Self, Self::Error> {
SafeArray::from_vector(value, VT_UI4 as u16)
}
}
impl TryInto<Vec<u32>> for SafeArray {
type Error = SafeArrayError;
fn try_into(self) -> Result<Vec<u32>, Self::Error> {
match self.get_vartype()? as u32 {
VT_UI4 => self.to_vector(VT_UI4 as u16),
VT_UINT => self.to_vector(VT_UINT as u16),
vt => Err(SafeArrayError::IncorrectDataType(vt as u16)),
}
}
}
impl TryFrom<&Vec<u64>> for SafeArray {
type Error = SafeArrayError;
fn try_from(value: &Vec<u64>) -> Result<Self, Self::Error> {
SafeArray::from_vector(value, VT_UI8 as u16)
}
}
impl TryInto<Vec<u64>> for SafeArray {
type Error = SafeArrayError;
fn try_into(self) -> Result<Vec<u64>, Self::Error> {
self.to_vector(VT_UI8 as u16)
}
}
impl TryFrom<&Vec<&str>> for SafeArray {
type Error = SafeArrayError;
fn try_from(value: &Vec<&str>) -> Result<Self, Self::Error> {
SafeArray::from_str_vector(value)
}
}
impl TryFrom<&Vec<&String>> for SafeArray {
type Error = SafeArrayError;
fn try_from(value: &Vec<&String>) -> Result<Self, Self::Error> {
SafeArray::from_str_vector(value)
}
}
impl TryFrom<&Vec<String>> for SafeArray {
type Error = SafeArrayError;
fn try_from(value: &Vec<String>) -> Result<Self, Self::Error> {
SafeArray::from_str_vector(value)
}
}
impl TryInto<Vec<String>> for SafeArray {
type Error = SafeArrayError;
fn try_into(self) -> Result<Vec<String>, Self::Error> {
self.to_string_vector()
}
}