I am trying to write a wrapper on top of winapi. I want to wrap functions that accept pointers for callback functions.
As an example, consider this:
// The unsafe callback type the FFI function accepts
type UnsafeCallback = unsafe extern "system" fn(exception_info: *mut ExceptionInfo) -> u32;
// The safe callback type my function should accept
type SafeCallback = fn(exception_info: &ConvertedExceptionInfo) -> u32;
The functions that will be used:
// The function exposed by winapi
unsafe extern "system" fn SetExceptionHandler(handler: UnsafeCallback);
// The function I want to expose in my library
fn SetExceptionHandler(handler: SafeCallback);
I want to create a wrapping function that looks like this:
unsafe extern "system" fn(exception_info: *mut ExceptionInfo) -> u32 {
let result = panic::catch_unwind(|| {
// Convert ExceptionInfo into ConvertedExceptionInfo. I know this is undefined behavior, but its only here
// to demonstrate program flow
let converted_exception_info: ConvertedExceptionInfo = (*exception_info).into();
// Call the corresponding safe function (as to how we get the function pointer here, that's
// the whole question)
return safe_callback(&converted_exception_info);
});
return match result {
Ok(val) => val,
Err(_) => _
};
}
I can think of two possibilities to create this wrapping function:
Creating a wrapping function at runtime
Create a closure or similar construct inside the safe
SetExceptionHandler
method.I have no idea how to get the closure across the FFI boundary.
Exposing a conversion macro and generating the function at compile time
Edit the
SetExceptionHandler
function to accept theUnsafeCallback
type.Then I could create a macro that generates the wrapping function at compile time and expose this macro to the user.
I would have to expose unsafe extern parameters again, so it is not how I would prefer to do it.
I have no idea how to structure such a macro or if this is even possible.
Is my first idea possible and feasible? If so, how could this be done? If not, is writing a macro like the second idea possible and feasible? If so, how could this be done?
Based 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?
- How do I pass a closure through raw pointers as an argument to a C function?
I get the impression that my first idea is probably not possible with the exception of something called trampolining.
Is trampolining possible in safe Rust and in this situation?