如何安全地包装回调以传递给 Windows FFI?

How do I safely wrap a callback to pass to Windows FFI?

我正在尝试在 winapi 之上编写一个包装器。我想包装接受回调函数指针的函数。

举个例子,考虑这个:

// 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 function exposed by winapi
unsafe extern "system" fn SetExceptionHandler(handler: UnsafeCallback);

// The function I want to expose in my library
fn SetExceptionHandler(handler: SafeCallback);

我想创建一个包装函数,如下所示:

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(_) => _
    };
}

我能想到创建这个包装函数的两种可能性:

  1. 在运行时创建包装函数

    在保险箱内创建一个封闭或类似结构 SetExceptionHandler 方法。

    我不知道如何让闭包跨越 FFI 边界。

  2. 公开转换宏并在编译时生成函数

    编辑 SetExceptionHandler 函数以接受 UnsafeCallback 类型。

    然后我可以创建一个在编译时生成包装函数的宏,并将这个宏公开给用户。

    我将不得不再次暴露不安全的外部参数,所以它不是 我更愿意怎么做。

    我不知道如何构建这样一个宏,或者这是否可能。


我的第一个想法是否可行?如果是这样,如何做到这一点? 如果不是,像第二个思路那样写一个宏是否可行可行?如果是这样,如何做到这一点?

基于

我的印象是我的第一个想法可能是不可能的,除了 trampolining

在安全的 Rust 和这种情况下是否可以进行蹦床?

经过大量搜索,我找到了一篇博客 post,它解释了一个很好的解决回调包装问题的方法。 Article here