I'd like to double check I'm using Manual Drop correctly. I'm writing a function that is called via the C ABI that returns multiple strings in a Windows Safe Array.
For context, the reason I'm using a Safe Array with BSTRs is that the function will be called by C#, and C#'s interop system knows how to properly translate an Safe Array of BSTRs into its own string array, and frees the memory automatically with the appropriate Windows allocator).
To show the problem, I've written an example function here:
type Lpcwstr = *const u16
#[unsafe(no_mangle)]
pub extern "C" fn split_string(s: Lpcwstr) -> *const SAFEARRAY {
// convert the null-terminated wide string into a Rust native string
let s: &widestring::U16CStr = unsafe {widestring::U16CStr::from_ptr_str(s)};
let s = s.to_string().unwrap();
// let's simulate getting multiple strings to return by splitting the string,
// and then creating BSTRs
let v = s.split(" ").map(|x| BSTR::from(x)).collect::<Vec<BSTR>>();
let len = v.len();
let sarray = unsafe {
// create a 1 dimensional safe array
Ole::SafeArrayCreateVector(Variant::VARENUM(8), 0, len as u32)
};
for (idx, s) in v.into_iter().enumerate() {
let s = ManuallyDrop::new(s); //is this correct?
unsafe {
//insert a reference to the bstr as a c_void pointer
//this works, but I'm not sure if there's a more elegant way
let _ = SafeArrayPutElement(sarray, &(idx as i32), std::mem::transmute_copy(&s));
// we want to avoid the BSTR's drop function being called, otherwise it will be freed when there's
// still a reference to it in the array.
}
}
sarray
}
The windows-strings
crate provides a BSTR type, which is great, except that the type implements drop, and if it goes out of scope will destroy my BSTR, which I need to stay valid after inserting it into the array.
Is this the appropriate way to handle this?