diff --git a/mac_test.js b/mac_test.js new file mode 100644 index 0000000..85dcfa2 --- /dev/null +++ b/mac_test.js @@ -0,0 +1,37 @@ +const { load, open, DataType } = require("./index"); + +// 定义 CGRect 结构体 +const CGRect = { + origin: { + x: DataType.Double, + y: DataType.Double, + ffiTypeTag: DataType.StackStruct, + }, + size: { + width: DataType.Double, + height: DataType.Double, + ffiTypeTag: DataType.StackStruct, + }, + ffiTypeTag: DataType.StackStruct, +}; + +// 获取主屏幕尺寸的函数 +const getMainDisplaySize = async () => { + open({ + library: "ApplicationServices", + path: "/System/Library/Frameworks/ApplicationServices.framework/ApplicationServices", + }); + + const bounds = await load({ + library: "ApplicationServices", + funcName: "CGDisplayBounds", + paramsType: [DataType.I32], // 不支持 U32 ,使用 I32 报错 + paramsValue: [1], + retType: CGRect, + }); + return bounds; +}; + +if (process.platform === "darwin") { + getMainDisplaySize().then(console.log); +} diff --git a/src/datatype/create_struct.rs b/src/datatype/create_struct.rs index cad698c..a8f27e3 100644 --- a/src/datatype/create_struct.rs +++ b/src/datatype/create_struct.rs @@ -1,5 +1,6 @@ use super::string::{string_to_c_string, string_to_c_w_string}; use crate::define::*; +use crate::utils::dataprocess::is_stack_struct; use crate::utils::{ calculate_struct_size, get_array_desc, get_array_value, get_ffi_tag, get_js_external_wrap_data, get_size_align, @@ -124,10 +125,10 @@ pub unsafe fn generate_c_struct( offset += size + padding; size } - RsArgsValue::Object(mut val) => { - if let FFITag::Array = get_ffi_tag(&val) { - let array_desc = get_array_desc(&val); - let array_value = get_array_value(&mut val).unwrap(); + RsArgsValue::Object(mut obj_value) => { + if let FFITag::Array = get_ffi_tag(&obj_value) { + let array_desc = get_array_desc(&obj_value); + let array_value = get_array_value(&mut obj_value).unwrap(); let FFIARRARYDESC { array_type, array_len, @@ -261,8 +262,7 @@ pub unsafe fn generate_c_struct( } else { let is_stack_struct = if let Some(RsArgsValue::Object(field_type)) = struct_type.get(&field) { - field_type.get(FFI_TAG_FIELD) - == Some(&RsArgsValue::I32(ReserveDataType::StackStruct.to_i32())) + is_stack_struct(field_type) } else { false }; @@ -273,7 +273,7 @@ pub unsafe fn generate_c_struct( let (size, align) = calculate_struct_size(val_type); let padding = (align - (offset % align)) % align; field_ptr = field_ptr.offset(padding as isize); - generate_c_struct(env, val_type, val, Some(field_ptr))?; + generate_c_struct(env, val_type, obj_value, Some(field_ptr))?; offset += size + padding; size } else { @@ -284,7 +284,7 @@ pub unsafe fn generate_c_struct( let padding = (align - (offset % align)) % align; field_ptr = field_ptr.offset(padding as isize); if let RsArgsValue::Object(val_type) = struct_type.get(&field).unwrap() { - let obj_ptr = generate_c_struct(env, val_type, val, None)?; + let obj_ptr = generate_c_struct(env, val_type, obj_value, None)?; (field_ptr as *mut *const c_void).write(obj_ptr); } offset += size + padding; diff --git a/src/datatype/pointer.rs b/src/datatype/pointer.rs index 116a862..52a1e18 100644 --- a/src/datatype/pointer.rs +++ b/src/datatype/pointer.rs @@ -1,5 +1,6 @@ use crate::utils::{ calculate_struct_size, get_array_desc, get_ffi_tag, get_func_desc, get_size_align, + is_stack_struct, }; use indexmap::IndexMap; use libc::{c_double, c_float, c_int, c_void, free}; @@ -257,9 +258,7 @@ unsafe fn free_struct_memory( } _ => { // struct - if obj.get(FFI_TAG_FIELD) - == Some(&RsArgsValue::I32(ReserveDataType::StackStruct.to_i32())) - { + if is_stack_struct(obj) { let (size, align) = calculate_struct_size(&obj); let padding = (align - (offset % align)) % align; field_ptr = field_ptr.offset(padding as isize); diff --git a/src/datatype/restore_struct.rs b/src/datatype/restore_struct.rs index 9d62c27..1e448ed 100644 --- a/src/datatype/restore_struct.rs +++ b/src/datatype/restore_struct.rs @@ -249,9 +249,7 @@ pub unsafe fn create_rs_struct_from_pointer( }; } else { // raw object - if sub_obj_type.get(FFI_TAG_FIELD) - == Some(&RsArgsValue::I32(ReserveDataType::StackStruct.to_i32())) - { + if is_stack_struct(&sub_obj_type) { let (size, align) = calculate_struct_size(sub_obj_type); let padding = (align - (offset % align)) % align; field_ptr = field_ptr.offset(padding as isize); diff --git a/src/define.rs b/src/define.rs index b5e04ce..3fa0a34 100644 --- a/src/define.rs +++ b/src/define.rs @@ -426,6 +426,24 @@ pub struct OpenParams { pub path: String, } +pub struct FFITypeCleanup { + pub struct_type_box: Option<*mut ffi_type>, + pub elements_box: Option<*mut Vec<*mut ffi_type>>, +} + +impl Drop for FFITypeCleanup { + fn drop(&mut self) { + unsafe { + if let Some(struct_type_box) = self.struct_type_box.take() { + let _ = Box::from_raw(struct_type_box); + } + if let Some(elements_box) = self.elements_box.take() { + let _ = Box::from_raw(elements_box); + } + } + } +} + pub const ARRAY_LENGTH_TAG: &str = "length"; pub const ARRAY_TYPE_TAG: &str = "type"; pub const ARRAY_DYNAMIC_TAG: &str = "dynamicArray"; diff --git a/src/lib.rs b/src/lib.rs index 9234748..24786e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,8 +9,8 @@ use define::*; use dlopen::symbor::{Library, Symbol}; use libffi_sys::{ ffi_abi_FFI_DEFAULT_ABI, ffi_call, ffi_cif, ffi_prep_cif, ffi_type, ffi_type_double, - ffi_type_float, ffi_type_pointer, ffi_type_sint32, ffi_type_sint64, ffi_type_uint64, - ffi_type_uint8, ffi_type_void, + ffi_type_enum_STRUCT, ffi_type_float, ffi_type_pointer, ffi_type_sint32, ffi_type_sint64, + ffi_type_uint64, ffi_type_uint8, ffi_type_void, }; use napi::{Env, JsExternal, JsUnknown, Result}; use std::collections::HashMap; @@ -18,7 +18,7 @@ use std::ffi::c_void; use std::rc::Rc; use utils::dataprocess::{ get_arg_types_values, get_js_external_wrap_data, get_js_unknown_from_pointer, get_value_pointer, - type_define_to_rs_args, + is_stack_struct, type_define_to_rs_args, }; static mut LIBRARY_MAP: Option< @@ -52,15 +52,12 @@ unsafe fn create_pointer(env: Env, params: CreatePointerParams) -> Result Result { - let ptr = get_js_external_wrap_data(&env, js_external)?; - Ok(ptr.is_null()) + let ptr = get_js_external_wrap_data(&env, js_external)?; + Ok(ptr.is_null()) } - #[napi] unsafe fn restore_pointer(env: Env, params: StorePointerParams) -> Result> { let StorePointerParams { @@ -226,25 +223,59 @@ unsafe fn load(env: Env, params: FFIParams) -> napi::Result { let (mut arg_types, arg_values) = get_arg_types_values(Rc::clone(¶ms_type_rs), params_value)?; let mut arg_values_c_void = get_value_pointer(&env, Rc::clone(¶ms_type_rs), arg_values)?; let ret_type_rs = type_define_to_rs_args(&env, ret_type)?; - let r_type: *mut ffi_type = match ret_type_rs { - RsArgsValue::I32(number) => { - let ret_data_type = number.to_basic_data_type(); - match ret_data_type { - BasicDataType::U8 => &mut ffi_type_uint8 as *mut ffi_type, - BasicDataType::I32 => &mut ffi_type_sint32 as *mut ffi_type, - BasicDataType::I64 | BasicDataType::BigInt => &mut ffi_type_sint64 as *mut ffi_type, - BasicDataType::U64 => &mut ffi_type_uint64 as *mut ffi_type, - BasicDataType::String | BasicDataType::WString => &mut ffi_type_pointer as *mut ffi_type, - BasicDataType::Void => &mut ffi_type_void as *mut ffi_type, - BasicDataType::Float => &mut ffi_type_float as *mut ffi_type, - BasicDataType::Double => &mut ffi_type_double as *mut ffi_type, - BasicDataType::Boolean => &mut ffi_type_uint8 as *mut ffi_type, - BasicDataType::External => &mut ffi_type_pointer as *mut ffi_type, + let mut ffi_type_cleanup = FFITypeCleanup { + struct_type_box: None, + elements_box: None, + }; + unsafe fn get_ffi_type( + ret_type_rs: &RsArgsValue, + ffi_type_cleanup: &mut FFITypeCleanup, + ) -> *mut ffi_type { + match ret_type_rs { + RsArgsValue::I32(number) => { + let ret_data_type = number.to_basic_data_type(); + match ret_data_type { + BasicDataType::U8 => &mut ffi_type_uint8 as *mut ffi_type, + BasicDataType::I32 => &mut ffi_type_sint32 as *mut ffi_type, + BasicDataType::I64 | BasicDataType::BigInt => &mut ffi_type_sint64 as *mut ffi_type, + BasicDataType::U64 => &mut ffi_type_uint64 as *mut ffi_type, + BasicDataType::String | BasicDataType::WString => &mut ffi_type_pointer as *mut ffi_type, + BasicDataType::Void => &mut ffi_type_void as *mut ffi_type, + BasicDataType::Float => &mut ffi_type_float as *mut ffi_type, + BasicDataType::Double => &mut ffi_type_double as *mut ffi_type, + BasicDataType::Boolean => &mut ffi_type_uint8 as *mut ffi_type, + BasicDataType::External => &mut ffi_type_pointer as *mut ffi_type, + } + } + RsArgsValue::Object(struct_type) => { + if is_stack_struct(struct_type) { + let mut elements: Vec<*mut ffi_type> = struct_type + .iter() + .filter(|(field_name, _)| field_name != &FFI_TAG_FIELD) + .map(|(_, field_type)| get_ffi_type(field_type, ffi_type_cleanup)) + .collect(); + elements.push(std::ptr::null_mut()); + let struct_type_box = ffi_type { + size: 0, + alignment: 0, + type_: ffi_type_enum_STRUCT as u16, + elements: elements.as_mut_ptr(), + }; + let elements_ptr = Box::into_raw(Box::new(elements)); + let struct_type_ptr = Box::into_raw(Box::new(struct_type_box)); + ffi_type_cleanup.elements_box = Some(elements_ptr); + ffi_type_cleanup.struct_type_box = Some(struct_type_ptr); + struct_type_ptr as *mut ffi_type + } else { + &mut ffi_type_pointer as *mut ffi_type + } } + _ => &mut ffi_type_void as *mut ffi_type, } - RsArgsValue::Object(_) => &mut ffi_type_pointer as *mut ffi_type, - _ => &mut ffi_type_void as *mut ffi_type, - }; + } + + let r_type = get_ffi_type(&ret_type_rs, &mut ffi_type_cleanup); + let mut cif = ffi_cif { abi: ffi_abi_FFI_DEFAULT_ABI, nargs: params_type_len as u32, @@ -265,6 +296,7 @@ unsafe fn load(env: Env, params: FFIParams) -> napi::Result { #[cfg(all(target_arch = "arm"))] vfp_args: [0; 16], }; + ffi_prep_cif( &mut cif, ffi_abi_FFI_DEFAULT_ABI, diff --git a/src/utils/dataprocess.rs b/src/utils/dataprocess.rs index 623b61d..a6bf514 100644 --- a/src/utils/dataprocess.rs +++ b/src/utils/dataprocess.rs @@ -37,6 +37,13 @@ pub unsafe fn get_js_external_wrap_data(env: &Env, js_external: JsExternal) -> R Ok(*p) } +pub fn is_stack_struct(obj: &IndexMap) -> bool { + if let Some(tag) = obj.get(FFI_TAG_FIELD) { + tag == &RsArgsValue::I32(ReserveDataType::StackStruct.to_i32()) + } else { + false + } +} pub fn get_ffi_tag(obj: &IndexMap) -> FFITag { if obj.get(FFI_TAG_FIELD).is_none() { return FFITag::Unknown; @@ -85,9 +92,6 @@ pub fn get_func_desc(obj: &IndexMap) -> FFIFUNCDESC { FFIFUNCDESC { need_free } } -pub fn js_number_to_i32(js_number: JsNumber) -> Result { - js_number.try_into() -} pub unsafe fn get_arg_types_values( params_type: Rc>, params_value: Vec, @@ -721,9 +725,9 @@ pub unsafe fn type_object_to_rs_struct( pub unsafe fn type_define_to_rs_args(env: &Env, type_define: JsUnknown) -> Result { let params_type_value_type = type_define.get_type()?; let ret_value = match params_type_value_type { - ValueType::Number => RsArgsValue::I32(js_number_to_i32( - create_js_value_unchecked::(type_define)?, - )?), + ValueType::Number => { + RsArgsValue::I32(create_js_value_unchecked::(type_define)?.try_into()?) + } ValueType::Object => RsArgsValue::Object(type_object_to_rs_struct( env, &create_js_value_unchecked::(type_define)?, @@ -757,9 +761,7 @@ pub unsafe fn get_js_unknown_from_pointer( rs_value_to_js_unknown(&env, RsArgsValue::String(ptr_str)) } BasicDataType::WString => { - let ptr_str = WideCString::from_ptr_str(*(ptr as *mut *const WideChar)) - .to_string_lossy() - .to_string(); + let ptr_str = WideCString::from_ptr_str(*(ptr as *mut *const WideChar)).to_string_lossy(); rs_value_to_js_unknown(&env, RsArgsValue::WString(ptr_str)) } BasicDataType::U8 => rs_value_to_js_unknown(env, RsArgsValue::U8(*(ptr as *mut u8))), @@ -783,9 +785,9 @@ pub unsafe fn get_js_unknown_from_pointer( } } } - RsArgsValue::Object(obj) => { - if let FFITag::Array = get_ffi_tag(&obj) { - let array_desc = get_array_desc(&obj); + RsArgsValue::Object(sub_obj_type) => { + if let FFITag::Array = get_ffi_tag(&sub_obj_type) { + let array_desc = get_array_desc(&sub_obj_type); // array let FFIARRARYDESC { array_type, @@ -816,7 +818,17 @@ pub unsafe fn get_js_unknown_from_pointer( } } else { // raw object - let rs_struct = create_rs_struct_from_pointer(env, *(ptr as *mut *mut c_void), &obj, false); + let is_stack_struct = is_stack_struct(&sub_obj_type); + let rs_struct = create_rs_struct_from_pointer( + env, + if is_stack_struct { + ptr + } else { + *(ptr as *mut *mut c_void) + }, + &sub_obj_type, + false, + ); rs_value_to_js_unknown(env, RsArgsValue::Object(rs_struct)) } } diff --git a/src/utils/object_utils.rs b/src/utils/object_utils.rs index d287b84..dcf87b5 100644 --- a/src/utils/object_utils.rs +++ b/src/utils/object_utils.rs @@ -1,4 +1,4 @@ -use super::dataprocess::{get_array_desc, get_ffi_tag}; +use super::dataprocess::{get_array_desc, get_ffi_tag, is_stack_struct}; use crate::define::*; use crate::{RefDataType, RsArgsValue, FFIARRARYDESC}; use indexmap::IndexMap; @@ -81,9 +81,7 @@ pub fn calculate_struct_size(struct_type: &IndexMap) -> (us return calculate_pointer(size, align, offset); } } else { - if obj.get(FFI_TAG_FIELD) - == Some(&RsArgsValue::I32(ReserveDataType::StackStruct.to_i32())) - { + if is_stack_struct(obj) { let (type_size, type_align) = calculate_struct_size(obj); let align = align.max(type_align); let padding = (type_align - (offset % type_align)) % type_align; diff --git a/test.ts b/test.ts index b717d8b..796ddde 100644 --- a/test.ts +++ b/test.ts @@ -583,4 +583,4 @@ const unitTest = () => { unitTest(); -exports.unitTest = unitTest; +exports.unitTest = unitTest; \ No newline at end of file