CopyFileEx
函数,但我无法获得 LPPROGRESS_ROUTINE
的工作示例。我是一名学习 Rust 的 Java 程序员,缺乏 OOP 范式对我来说是一个挑战。在 Java 中,我会使用一个实现接口的类作为我的回调。但是,lpprogressroutine
参数看起来像是指向函数的指针,而不是多态对象。但这应该没问题;我可以只声明一个函数并创建一个指向它的指针。
我希望回调函数调用带有附加参数的不同函数,所以我创建了一个包装器结构来包含这些附加参数和回调函数:
use jni::objects::{JObject, JString, JValueGen};
use jni::strings::JavaStr;
use jni::sys::jint;
use jni::JNIEnv;
use windows::core::*;
use windows::Win32::Foundation::HANDLE;
use windows::Win32::Storage::FileSystem::{
CopyFileExA, LPPROGRESS_ROUTINE, LPPROGRESS_ROUTINE_CALLBACK_REASON,
};
struct Callback<'a> {
env: JNIEnv<'a>,
ext_callback: JObject<'a>,
}
impl<'a> Callback<'a> {
fn new(env: JNIEnv<'a>, ext_callback: JObject<'a>) -> Self {
Callback {
env: env,
ext_callback: ext_callback,
}
}
unsafe extern "system" fn invoke(
&mut self,
totalfilesize: i64,
totalbytestransferred: i64,
streamsize: i64,
streambytestransferred: i64,
_dwstreamnumber: u32,
_dwcallbackreason: LPPROGRESS_ROUTINE_CALLBACK_REASON,
_hsourcefile: HANDLE,
_hdestinationfile: HANDLE,
_lpdata: *const ::core::ffi::c_void,
) -> u32 {
let arr = [
JValueGen::Long(totalfilesize),
JValueGen::Long(totalbytestransferred),
JValueGen::Long(streamsize),
JValueGen::Long(streambytestransferred),
];
self.env
.call_method(&self.callback, "onProgressEvent", "(IIII)V", &arr)
.expect("Java callback failed");
return 0;
}
}
现在,为了访问我在结构上定义的
env
和 ext_callback
字段,我必须将 &mut self
参数添加到我的调用函数中。我认为这已经破坏了函数签名,因此它不会作为 LPPROGRESS_ROUTINE 工作,但也许不会。
继续努力,我创建了一个方法,该方法将构造我的
Callback
实现并使用指向我的方法的指针调用 CopyFileExA 函数。这是我遇到麻烦的地方。我不知道如何创建指向回调方法的指针,因为它不是静态的:
pub extern "system" fn Java_com_nhbb_util_natives_WindowsCopy_copy<'local>(
mut env: JNIEnv<'local>,
_object: JObject<'local>,
source: JString<'local>,
dest: JString<'local>,
flags: jint,
ext_callback: JObject<'local>,
) {
let source_jstr: JavaStr = env.get_string(&source).expect("Invalid source string");
let dest_jstr: JavaStr = env.get_string(&dest).expect("Invalid dest string");
let source_arr = source_jstr.get_raw();
let dest_arr = dest_jstr.get_raw();
let source = source_arr as *const u8;
let dest = dest_arr as *const u8;
let flags: u32 = flags.try_into().unwrap();
let callback = Callback::new(env, ext_callback);
unsafe {
CopyFileExA(
PCSTR(source),
PCSTR(dest),
LPPROGRESS_ROUTINE::Some(callback::invoke),
// ^^^^^^^^ use of undeclared crate or module `callback`
None,
None,
flags,
);
}
}
我想我只是因为缺乏使用这种新语言的经验而苦苦挣扎。我是否使用
struct
采取了正确的方法?有更好的方法吗?