如何安全地包装回调以传递给 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(_) => _
};
}
我能想到创建这个包装函数的两种可能性:
在运行时创建包装函数
在保险箱内创建一个封闭或类似结构
SetExceptionHandler
方法。
我不知道如何让闭包跨越 FFI 边界。
公开转换宏并在编译时生成函数
编辑 SetExceptionHandler
函数以接受 UnsafeCallback
类型。
然后我可以创建一个在编译时生成包装函数的宏,并将这个宏公开给用户。
我将不得不再次暴露不安全的外部参数,所以它不是
我更愿意怎么做。
我不知道如何构建这样一个宏,或者这是否可能。
我的第一个想法是否可行?如果是这样,如何做到这一点?
如果不是,像第二个思路那样写一个宏是否可行可行?如果是这样,如何做到这一点?
基于
我的印象是我的第一个想法可能是不可能的,除了 trampolining。
在安全的 Rust 和这种情况下是否可以进行蹦床?
经过大量搜索,我找到了一篇博客 post,它解释了一个很好的解决回调包装问题的方法。 Article here
我正在尝试在 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(_) => _
};
}
我能想到创建这个包装函数的两种可能性:
在运行时创建包装函数
在保险箱内创建一个封闭或类似结构
SetExceptionHandler
方法。我不知道如何让闭包跨越 FFI 边界。
公开转换宏并在编译时生成函数
编辑
SetExceptionHandler
函数以接受UnsafeCallback
类型。然后我可以创建一个在编译时生成包装函数的宏,并将这个宏公开给用户。
我将不得不再次暴露不安全的外部参数,所以它不是 我更愿意怎么做。
我不知道如何构建这样一个宏,或者这是否可能。
我的第一个想法是否可行?如果是这样,如何做到这一点? 如果不是,像第二个思路那样写一个宏是否可行可行?如果是这样,如何做到这一点?
基于
我的印象是我的第一个想法可能是不可能的,除了 trampolining。
在安全的 Rust 和这种情况下是否可以进行蹦床?
经过大量搜索,我找到了一篇博客 post,它解释了一个很好的解决回调包装问题的方法。 Article here