use crate::{bindings::*, *};
use std::{collections::HashMap, intrinsics::type_id};
#[cfg(feature = "global_function")]
use crate::codegen::global_function::GlobalFunction;
#[cfg(feature = "global_function")]
#[static_init::dynamic]
static mut GLOBAL_FUNCTION_HANDLERS: HashMap<&'static PBStr, fn(CallInfoRef<'_>) -> Result<()>> =
HashMap::new();
#[cfg(feature = "global_function")]
pub fn register_global_function<T: GlobalFunction>() {
let mut map = GLOBAL_FUNCTION_HANDLERS.write();
map.insert(T::NAME, T::invoke);
}
#[cfg(feature = "nonvisualobject")]
#[static_init::dynamic]
static mut NVO_HANDLERS: HashMap<
&'static PBStr,
fn(session: Session, obj: ContextObject) -> Result<pbuserobject>
> = HashMap::new();
#[cfg(feature = "nonvisualobject")]
pub fn register_nonvisualobject<T: NonVisualObject>() {
fn new<T: NonVisualObject>(session: Session, ctx: ContextObject) -> Result<bindings::pbuserobject> {
let obj = Box::new(T::new(session, ctx)?);
unsafe {
let om = NVOM::<T> {
ctx: NonNull::new_unchecked(Box::into_raw(obj)),
type_id: type_id::<T>(),
destory: handler::destroy,
invoke: handler::invoke
};
Ok(ffi::NewNonVisualObject(&om as *const NVOM<T> as _))
}
}
let mut map = NVO_HANDLERS.write();
map.insert(T::CLASS_NAME, new::<T>);
}
#[cfg(feature = "visualobject")]
#[static_init::dynamic]
static mut VO_HANDLERS: HashMap<
&'static PBStr,
fn(session: Session, obj: ContextObject) -> Result<bindings::pbuserobject>
> = HashMap::new();
#[cfg(feature = "visualobject")]
pub fn register_visualobject<T: VisualObject>() {
fn new<T: VisualObject>(session: Session, ctx: ContextObject) -> Result<bindings::pbuserobject> {
let obj = Box::new(T::new(session, ctx)?);
unsafe {
let om = VOM::<T> {
ctx: NonNull::new_unchecked(Box::into_raw(obj)),
type_id: type_id::<T>(),
cls_name: T::WINDOW_CLASS_NAME.as_ptr(),
destory: handler::destroy,
invoke: handler::invoke,
create_control: handler::create_control,
get_event_id: handler::get_event_id
};
Ok(ffi::NewVisualObject(&om as *const VOM<T> as _))
}
}
let mut map = VO_HANDLERS.write();
map.insert(T::CLASS_NAME, new::<T>);
}
#[cfg(any(feature = "nonvisualobject", feature = "visualobject"))]
#[doc(hidden)]
mod handler {
use super::*;
pub unsafe extern "C" fn destroy<T: UserObject>(ctx: NonNull<T>) { Box::from_raw(ctx.as_ptr()); }
pub unsafe extern "C" fn invoke<T: UserObject>(
mut ctx: NonNull<T>,
session: Session,
_obj: pbobject,
mid: MethodId,
ci: pbcallinfo
) -> PBXRESULT {
let ci = CallInfoRef::from_ptr(ci, session);
ctx.as_mut().invoke(mid, &ci).into()
}
#[cfg(feature = "visualobject")]
pub unsafe extern "C" fn create_control<T: VisualObject>(
mut ctx: NonNull<T>,
dwExStyle: u32,
window_name: LPCTSTR,
dwStyle: u32,
x: i32,
y: i32,
width: i32,
height: i32,
parent: HWND,
instance: HINSTANCE
) -> HWND {
let window_name = PBStr::from_ptr_str(window_name);
ctx.as_mut().create_control(dwExStyle, window_name, dwStyle, x, y, width, height, parent, instance)
}
#[cfg(feature = "visualobject")]
pub unsafe extern "C" fn get_event_id<T: VisualObject>(
ctx: NonNull<T>,
hwnd: HWND,
msg: u16,
wparam: u32,
lparam: u32
) -> i32 {
const PB_NULL: i32 = -1;
ctx.as_ref().get_event_id(hwnd, msg, wparam, lparam).unwrap_or(PB_NULL)
}
}
#[doc(hidden)]
mod export {
use super::*;
#[cfg(feature = "global_function")]
#[no_mangle]
unsafe extern "stdcall" fn PBX_InvokeGlobalFunction(
session: Session,
functionName: LPCTSTR,
ci: pbcallinfo
) -> PBXRESULT {
let functionName = PBStr::from_ptr_str(functionName);
let map = GLOBAL_FUNCTION_HANDLERS.read();
if let Some(handler) = map.get(functionName) {
let ci = CallInfoRef::from_ptr(ci, session);
handler(ci).into()
} else {
PBXRESULT::E_NO_REGISTER_FUNCTION
}
}
#[cfg(feature = "nonvisualobject")]
#[no_mangle]
unsafe extern "stdcall" fn PBX_CreateNonVisualObject(
session: Session,
pbobj: pbobject,
className: LPCTSTR,
mut obj: NonNull<pbuserobject>
) -> PBXRESULT {
let className = PBStr::from_ptr_str(className);
let map = NVO_HANDLERS.read();
if let Some(handler) = map.get(className) {
let pbobj = ContextObject::from_ptr(pbobj, &session);
match handler(session, pbobj) {
Ok(ptr) => {
*obj.as_mut() = ptr;
PBXRESULT::OK
},
Err(e) => e
}
} else {
PBXRESULT::E_NO_SUCH_CLASS
}
}
#[cfg(feature = "visualobject")]
#[no_mangle]
unsafe extern "stdcall" fn PBX_CreateVisualObject(
session: Session,
pbobj: pbobject,
className: LPCTSTR,
mut obj: NonNull<pbuserobject>
) -> PBXRESULT {
let className = PBStr::from_ptr_str(className);
let map = VO_HANDLERS.read();
if let Some(handler) = map.get(className) {
let pbobj = ContextObject::from_ptr(pbobj, &session);
match handler(session, pbobj) {
Ok(ptr) => {
*obj.as_mut() = ptr;
PBXRESULT::OK
},
Err(e) => e
}
} else {
PBXRESULT::E_NO_SUCH_CLASS
}
}
}