Convert *mut c_void to HWND - rust

I'm trying to convert a *mut c_void to HWND (https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/Foundation/struct.HWND.html) but it keeps throwing this error:
mismatched types
expected struct `HWND`
found raw pointer `*mut c_void`
How can I safely convert a *mut c_void to HWND (since HWND is built out of a c_void).
let hwnd = match parent.handle {
RawWindowHandle::Win32(_handle) => _handle.hwnd,
_ => panic!()
};
let mut test: windows::Win32::Foundation::HWND = hwnd;
I want an HWND from hwnd, but it throws this error:
mismatched types
expected struct HWND
found raw pointer *mut c_void
Thank you.

You can cast your pointer to isize and then construct HWND:
fn ptr_to_hwnd(ptr: *mut c_void) -> HWND {
HWND(ptr as _) // struct HWND(pub isize)
}
I'd just transmute though 😂

Related

How to fill Rust function pointer from C++

I want to call C++ from Rust. C++ then allocates and fills a buffer, then Rust uses it and deallocates. However, I'd like to deliver back the function pointer to deallocate the data. This is what I tried:
In Rust:
extern "C" {
pub fn openvpn_receive(
instance: *mut OpenVpnInstance,
size: *mut size_t,
deallocate: extern "C" fn(*mut u8),
) -> *mut u8;
}
fn main() {
let size: *mut size_t;
let deallocate = extern "C" fn(*mut u8);
let data: *mut u8 = openvpn_receive(self.instance, size, deallocate);
//use data
deallocate(data);
}
In C++:
uint8_t* openvpn_receive(size_t *size, void (*deallocate_function)(uint8_t *))
{
deallocate_function = &cpp_deallocate_u8;
uint8*t data = receive_data(size);
}
But the Rust code is not valid. How can I make such thing happen?
Maybe it will help You.
https://doc.rust-lang.org/std/keyword.extern.html
https://rust-embedded.github.io/book/interoperability/rust-with-c.html
C++ -> C -> Rust
use libc::{size_t, c_void};
#[repr(C)]
pub struct OpenVpnInstance();
//#[link(name = "your_c_library")]
extern "C" {
pub fn openvpn_receive(
instance: *mut OpenVpnInstance,
size: *mut size_t,
deallocate: *mut c_void,
) -> *mut u8;
}
pub fn my_callback(arg: *mut u8)
{
println!("CB!");
}
fn main()
{
let size: size_t = 42;
let instance = OpenVpnInstance{};
let dummy_arg: u8 = 42;
unsafe {
let cb = my_callback as *mut c_void;
let instance_ptr = &instance as *const _ as *mut OpenVpnInstance;
let arg_ptr = &dummy_arg as *const _ as *mut u8;
openvpn_receive(instance_ptr, size as *mut size_t, cb);
my_callback(arg_ptr)
}
}

How to get a mutable u32 pointer and cast it into an int pointer of C

Let's say I have a C function:
void func(char *buf, unsigned int *len);
To call it in Rust, I declared:
pub fn func(buf: *mut ::std::os::raw::c_char, len: *mut ::std::os::raw::c_uint) {
unimplemented!()
}
Then I wrote another wrapper:
pub fn another_func() -> String {
let mut capacity: u32 = 256;
let mut vec = Vec::with_capacity(capacity as usize);
unsafe {
func(vec.as_ptr() as *mut c_char, &capacity as *mut c_uint)
};
String::from_utf8(vec).unwrap();
unimplemented!()
}
But the compiler told me:
error[E0606]: casting `&u32` as `*mut u32` is invalid
--> src/main.rs:...:28
|
307 | &capacity as *mut c_uint)
Why can't I cast capacity into *mut c_unit?
It turns out I have to make the reference mutable.
func(vec.as_ptr() as *mut c_char, &mut capacity as *mut c_uint)

How can I pass an unsafe function when a safe function is expected without wrapping the unsafe function?

I want to point pthread_create to a C function I later link to. That C function will use pthread_cleanup_push and pthread_cleanup_pop which are C macros and thus cannot be ported to Rust.
This is my code:
extern crate libc;
use std::ptr::null_mut;
use libc::c_void;
extern "C" {
fn thr_fn1(arg:*mut c_void) -> *mut c_void;
}
fn main() {
let mut tid1 = std::mem::zeroed();
libc::pthread_create(&mut tid1, null_mut(), thr_fn1, null_mut());
}
I expected that since I'm calling libc's FFI anyway, I can just point to an external C function, but I get an error:
error[E0308]: mismatched types
--> src/bin/11-threads/f05-thread-cleanup.rs:25:49
|
25 | libc::pthread_create(&mut tid1, null_mut(), thr_fn1, null_mut());
| ^^^^^^^ expected normal fn, found unsafe fn
|
= note: expected type `extern "C" fn(*mut libc::c_void) -> *mut libc::c_void`
found type `unsafe extern "C" fn(*mut libc::c_void) -> *mut libc::c_void {thr_fn1}`
I could write a wrapper which calls the C function in an unsafe{} block, but is there any way to avoid that?
The libc function definition is wrong: The C header /usr/include/pthread.h:
extern int pthread_create (pthread_t *__restrict __newthread,
const pthread_attr_t *__restrict __attr,
void *(*__start_routine) (void *),
void *__restrict __arg) __THROWNL __nonnull ((1, 3));
bindgen produces this function definition:
pub fn pthread_create(arg1: *mut pthread_t,
arg2: *const pthread_attr_t,
arg3: Option<unsafe extern "C" fn(arg1: *mut c_void) -> *mut c_void>,
arg4: *mut c_void) -> c_int;
Which compiles both on macOS and Linux. I'm not sure Option is a good idea here; why would anyone start a thread which doesn't call a function?
I opened a PR for libc to correct the issue (without the Option part)

How do I pass a closure through raw pointers as an argument to a C function?

I'm working with WinAPI in Rust and there are some functions (like EnumWindows()) which require a callback. The callback usually accepts an additional argument (of type LPARAM which is an alias for i64), which you can use to pass some custom data to the callback.
I have sent Vec<T> objects as LPARAM to the WinAPI callbacks and it worked fine. For instance "unpacking" an lparam value to a Vec<RECT> looked like this in my case:
unsafe extern "system" fn enumerate_callback(hwnd: HWND, lparam: LPARAM) -> BOOL {
let rects = lparam as *mut Vec<RECT>;
}
Instead of passing a vector, I now have to pass a closure. I can not use a function pointer as my closure has to capture some variables, which would not be accessible if I used a function. In C++, I would use std::function<> for my particular task, I think that in Rust the corresponding abstraction is a closure.
My code for unpacking looks like this:
unsafe extern "system" fn enumerate_callback(hwnd: HWND, lparam: LPARAM) -> BOOL {
let cb: &mut FnMut(HWND) -> bool = &mut *(lparam as *mut c_void as *mut FnMut(HWND) -> bool);
// ...
}
SSCCE:
use std::os::raw::c_void;
fn enum_wnd_proc(some_value: i32, lparam: i32) {
let closure: &mut FnMut(i32) -> bool =
unsafe { (&mut *(lparam as *mut c_void as *mut FnMut(i32) -> bool)) };
println!("predicate() executed and returned: {}", closure(some_value));
}
fn main() {
let sum = 0;
let mut closure = |some_value: i32| -> bool {
sum += some_value;
sum >= 100
};
let lparam = (&mut closure as *mut c_void as *mut FnMut(i32) -> bool) as i32;
enum_wnd_proc(20, lparam);
}
(Playground)
I get these errors:
error[E0277]: expected a `std::ops::FnMut<(i32,)>` closure, found `std::ffi::c_void`
--> src/main.rs:5:26
|
5 | unsafe { (&mut *(lparam as *mut c_void as *mut FnMut(i32) -> bool)) };
| ^^^^^^^^^^^^^^^^^^^^^ expected an `FnMut<(i32,)>` closure, found `std::ffi::c_void`
|
= help: the trait `std::ops::FnMut<(i32,)>` is not implemented for `std::ffi::c_void`
= note: required for the cast to the object type `dyn std::ops::FnMut(i32) -> bool`
error[E0606]: casting `&mut [closure#src/main.rs:12:23: 15:6 sum:_]` as `*mut std::ffi::c_void` is invalid
--> src/main.rs:17:19
|
17 | let lparam = (&mut closure as *mut c_void as *mut FnMut(i32) -> bool) as i32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0606]: casting `*mut dyn std::ops::FnMut(i32) -> bool` as `i32` is invalid
--> src/main.rs:17:18
|
17 | let lparam = (&mut closure as *mut c_void as *mut FnMut(i32) -> bool) as i32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: cast through a thin pointer first
error[E0277]: expected a `std::ops::FnMut<(i32,)>` closure, found `std::ffi::c_void`
--> src/main.rs:17:19
|
17 | let lparam = (&mut closure as *mut c_void as *mut FnMut(i32) -> bool) as i32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `FnMut<(i32,)>` closure, found `std::ffi::c_void`
|
= help: the trait `std::ops::FnMut<(i32,)>` is not implemented for `std::ffi::c_void`
= note: required for the cast to the object type `dyn std::ops::FnMut(i32) -> bool`
I would like to know:
Is there a way to pass a function/closure to a different function and perform those "C-like" casts?
What is the proper way to cast a closure to a i64 value for passing it to that callback?
I'm using the stable version of Rust.
First, some logical errors with the code:
It is not correct to cast pointers to i32 on many platforms (like 64-bit). Pointers may use all of those bits. Truncating a pointer and then calling a function at the truncated address will lead to Really Bad Things. Generally you want to use a machine-sized integer (usize or isize).
The sum value needs to be mutable.
The meat of the problem is that closures are concrete types that take up a size unknown to the programmer, but known to the compiler. The C function is limited to taking a machine-sized integer.
Because closures implement one of the Fn* traits, we can take a reference to the closure's implementation of that trait to generate a trait object. Taking a reference a trait leads to a fat pointer that contains two pointer-sized values. In this case, it contains a pointer to the data that is closed-over and a pointer to a vtable, the concrete methods that implement the trait.
In general, any reference to or Box of a dynamically-sized type type is going to generate a fat pointer.
On a 64-bit machine, a fat pointer would be 128 bits in total, and casting that to a machine-sized pointer would again truncate the data, causing Really Bad Things to happen.
The solution, like everything else in computer science, is to add more layers of abstraction:
use std::os::raw::c_void;
fn enum_wnd_proc(some_value: i32, lparam: usize) {
let trait_obj_ref: &mut &mut FnMut(i32) -> bool = unsafe {
let closure_pointer_pointer = lparam as *mut c_void;
&mut *(closure_pointer_pointer as *mut _)
};
println!(
"predicate() executed and returned: {}",
trait_obj_ref(some_value)
);
}
fn main() {
let mut sum = 0;
let mut closure = |some_value: i32| -> bool {
println!("I'm summing {} + {}", sum, some_value);
sum += some_value;
sum >= 100
};
let mut trait_obj: &mut FnMut(i32) -> bool = &mut closure;
let trait_obj_ref = &mut trait_obj;
let closure_pointer_pointer = trait_obj_ref as *mut _ as *mut c_void;
let lparam = closure_pointer_pointer as usize;
enum_wnd_proc(20, lparam);
}
We take a second reference to the fat pointer, which creates a thin pointer. This pointer is only one machine-integer in size.
Maybe a diagram will help (or hurt)?
Reference -> Trait object -> Concrete closure
8 bytes 16 bytes ?? bytes
Because we are using raw pointers, it is now the programmers responsibility to make sure that the closure outlives where it is used! If enum_wnd_proc stores the pointer somewhere, you must be very careful to not use it after the closure is dropped.
As a side note, using mem::transmute when casting the trait object:
use std::mem;
let closure_pointer_pointer: *mut c_void = unsafe { mem::transmute(trait_obj) };
Produces a better error message:
error[E0512]: transmute called with types of different sizes
--> src/main.rs:26:57
|
26 | let closure_pointer_pointer: *mut c_void = unsafe { mem::transmute(trait_obj) };
| ^^^^^^^^^^^^^^
|
= note: source type: &mut dyn std::ops::FnMut(i32) -> bool (128 bits)
= note: target type: *mut std::ffi::c_void (64 bits)
Error E0512.
See also
Pass a Rust trait to C
Rust FFI passing trait object as context to call callbacks on
How do I create a Rust callback function to pass to a FFI function?
How do I convert a Rust closure to a C-style callback?

Rust FFI. Casting to void pointer

I've a function which has prototype as below
//opaque struct
struct mosquitto;
struct mosquitto *mosquitto_new(const char *id, bool clean_session, void *obj);
In my c code, I'm calling it as below.
struct mosquitto *m = mosquitto_new(buf, true, NULL);
Now I want to call the above API in my rust code. rust-bindgen generated the following bindings
pub enum Struct_mosquitto { }
pub fn mosquitto_new(id: *const ::libc::c_char, clean_session: u8, obj: *mut ::libc::c_void) -> *mut Struct_mosquitto;
When I'm trying to call the above API, I'm getting a mismatch at 3rd argument.
let s = CString::new("ravi").unwrap();
let mqtt = mosquitto::mosquitto_new(s.as_ptr(), 1, ptr::null());
How do I pass NULL to *mut c_void?
BONUS QUESTION: How to pass a rust struct to *mut c_void ?
The ptr::null() function returns a *const T, what you want is the ptr::null_mut() function, since the argument to your function is of type *mut ::libc::c_void.
For passing an actual value, have a look at the answer to Working with c_void in an FFI

Resources