1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
use crate::rc::{Ref, RefCountable};
use binaryninjacore_sys::{
BNExecuteMainThreadAction, BNExecuteOnMainThread, BNExecuteOnMainThreadAndWait,
BNFreeMainThreadAction, BNIsMainThreadActionDone, BNMainThreadAction, BNMainThreadCallbacks,
BNNewMainThreadActionReference, BNRegisterMainThread, BNWaitForMainThreadAction,
};
use std::ffi::c_void;
pub struct MainThreadActionExecutor {
func: Box<dyn Fn()>,
}
impl MainThreadActionExecutor {
unsafe extern "C" fn cb_execute(ctx: *mut c_void) {
let f: Box<Self> = Box::from_raw(ctx as *mut Self);
f.execute();
}
pub fn execute(&self) {
(self.func)();
}
}
/// Execute the passed function on the main thread. Returns `None` if already running on the main thread.
///
/// When not running in headless, this will block the UI.
pub fn execute_on_main_thread<F: Fn() + 'static>(f: F) -> Option<Ref<MainThreadAction>> {
let boxed_executor = Box::new(MainThreadActionExecutor { func: Box::new(f) });
let raw_executor = Box::into_raw(boxed_executor);
let raw_action = unsafe {
BNExecuteOnMainThread(
raw_executor as *mut c_void,
Some(MainThreadActionExecutor::cb_execute),
)
};
match raw_action.is_null() {
false => Some(MainThreadAction::ref_from_raw(raw_action)),
true => None,
}
}
/// Execute the passed function on the main thread and wait until the function is finished.
///
/// When not running in headless, this will block the UI.
pub fn execute_on_main_thread_and_wait<F: Fn() + 'static>(f: F) {
let boxed_executor = Box::new(MainThreadActionExecutor { func: Box::new(f) });
let raw_executor = Box::into_raw(boxed_executor);
unsafe {
BNExecuteOnMainThreadAndWait(
raw_executor as *mut c_void,
Some(MainThreadActionExecutor::cb_execute),
)
};
}
/// The trait required for receiving main thread actions
pub trait MainThreadHandler: Sized {
fn add_action(&self, _view: Ref<MainThreadAction>);
unsafe extern "C" fn cb_add_action(ctxt: *mut c_void, action: *mut BNMainThreadAction) {
ffi_wrap!("MainThread::add_action", {
let main_thread = &*(ctxt as *mut Self);
let action = MainThreadAction::ref_from_raw(action);
main_thread.add_action(action);
})
}
/// Register the main thread handler. Leaking [`Self`] in the process.
///
/// NOTE: This MUST be called from **within** the main thread.
fn register(self) {
// NOTE: We leak self here.
let raw = Box::into_raw(Box::new(self));
let mut callbacks = BNMainThreadCallbacks {
context: raw as *mut c_void,
addAction: Some(Self::cb_add_action),
};
unsafe { BNRegisterMainThread(&mut callbacks) };
}
}
pub struct MainThreadAction {
pub handle: *mut BNMainThreadAction,
}
impl MainThreadAction {
pub fn from_raw(handle: *mut BNMainThreadAction) -> Self {
assert!(!handle.is_null());
Self { handle }
}
pub fn ref_from_raw(handle: *mut BNMainThreadAction) -> Ref<Self> {
unsafe { Ref::new(Self::from_raw(handle)) }
}
pub fn execute(&self) {
unsafe { BNExecuteMainThreadAction(self.handle) }
}
pub fn is_done(&self) -> bool {
unsafe { BNIsMainThreadActionDone(self.handle) }
}
pub fn wait(&self) {
unsafe { BNWaitForMainThreadAction(self.handle) }
}
}
impl ToOwned for MainThreadAction {
type Owned = Ref<Self>;
fn to_owned(&self) -> Self::Owned {
unsafe { RefCountable::inc_ref(self) }
}
}
unsafe impl RefCountable for MainThreadAction {
unsafe fn inc_ref(action: &Self) -> Ref<Self> {
Ref::new(Self {
handle: BNNewMainThreadActionReference(action.handle),
})
}
unsafe fn dec_ref(action: &Self) {
BNFreeMainThreadAction(action.handle);
}
}
unsafe impl Send for MainThreadAction {}
|