Vec<*const c_void> to **const c_void

I'm using windows api in my project and I start a thread for some usage.
I want to pass my clap handled parameters (which is Vec<String> ) to *const c_void.
The length of Vec can only be known in runtime and the length of it won't change.

I use the code below,but I'm not sure about whether I can directly transform slice to *const c_void

    unsafe {
        // cli.params are Vec<String>
        let param : Vec<*const c_void> = cli.params.into_iter().map(|x| CString::new(x).expect("failed to convert String to CString").into_raw() as _).collect();
        let param = param.as_slice();
        // Can &[*const c_void] convert to **const c_void?
        let handle = CreateThread(None, 0, std::mem::transmute(load_file("/path/to/file")?), Some(param.as_ptr() as *const _), 0, None)?;
        WaitForSingleObject(handle,INFINITE);
    }

Am I doing right here?if not,please help me to correctly transform it.

It is never right to transmute pointers. (Heck, it's never right to transmute anything. For every transmute, there's a better way.)

You are probably looking for <[_]>::as_ptr().

No I don't mean that

You'll need to provide more information then. Your question so far clearly states that you want to convert a slice to a raw pointer.

**const c_void is not a Rust type but *consr *const c_void and *mut *const c_void are. You can convert it to the former but not the latter (well, you can technically convert it to both, but actually writing to the latter will be UB).


You're also likely leaking your CStrings.

You'll probably want to be using a CString type which guarantees having the same layout as that of a char * in C (*const/mut c_char in Rust), such as:

Indeed, using such a type simplifies things quite a bit (otherwise you'll need two Vecs, one for the owned CStrings, and one having .iter().map(|cstr| cstr.as_ptr()).collect::<Vec<_>>()):

use ::safer_ffi::prelude::*;

let params: Vec<char_p::Box> = cli.params.into_iter().map(|s| char_p::new(s)).collect();
let params_ptr: *const char_p::Box = params.as_ptr();
let params_void_ptr: *const *const c_void = params_ptr.cast();
unsafe {
    let handle = CreateThread(None, 0, …, Some(params_void_ptr), 0, None)?;
    WaitForSingleObject(handle, INFINITE);
}

The easiest solution is to push a nullptr to the Vec/chain a iter::once(nullptr()) so the thread can get the number of arguments from that.

The transmute to LPTHREAD_START_ROUTINE::Some looks very fishy to me. What is the signature of load_file? Is the function written in rust or some external C code? Do you control it?

the signature of load_file is fn(impl AsRef<Path>) -> usize where usize is a entry address of a exe program,I control that.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.