From 732613d845daba707c759d9c23a7de4710347a4e Mon Sep 17 00:00:00 2001 From: Kozlov Maxim Date: Wed, 2 Aug 2023 14:40:11 +0600 Subject: [PATCH] fork init --- src/add_in/mod.rs | 37 ++ src/addin2.rs | 121 ------ src/ffi.rs | 729 ---------------------------------- src/ffi/connection.rs | 47 +++ src/ffi/init_base.rs | 56 +++ src/ffi/lang_extender.rs | 279 +++++++++++++ src/ffi/memory_manager.rs | 42 ++ src/ffi/mod.rs | 135 +++++++ src/ffi/types.rs | 210 ++++++++++ src/ffi/utils.rs | 14 + src/lib.rs | 16 +- src/{addin1.rs => myaddin.rs} | 34 +- 12 files changed, 852 insertions(+), 868 deletions(-) create mode 100644 src/add_in/mod.rs delete mode 100644 src/addin2.rs delete mode 100644 src/ffi.rs create mode 100644 src/ffi/connection.rs create mode 100644 src/ffi/init_base.rs create mode 100644 src/ffi/lang_extender.rs create mode 100644 src/ffi/memory_manager.rs create mode 100644 src/ffi/mod.rs create mode 100644 src/ffi/types.rs create mode 100644 src/ffi/utils.rs rename src/{addin1.rs => myaddin.rs} (87%) diff --git a/src/add_in/mod.rs b/src/add_in/mod.rs new file mode 100644 index 0000000..39b09cf --- /dev/null +++ b/src/add_in/mod.rs @@ -0,0 +1,37 @@ +use crate::ffi::{ + connection::Connection, + types::{ParamValue, ReturnValue}, +}; + +pub trait AddIn { + fn init(&mut self, interface: &'static Connection) -> bool; + + /// default 2000, don't use version 1000, because static objects are created + fn get_info(&mut self) -> u16 { + 2000 + } + fn done(&mut self); + fn register_extension_as(&mut self) -> &'static [u16]; + fn get_n_props(&mut self) -> usize; + fn find_prop(&mut self, name: &[u16]) -> Option; + fn get_prop_name(&mut self, num: usize, alias: usize) -> Option<&'static [u16]>; + fn get_prop_val(&mut self, num: usize, val: ReturnValue) -> bool; + fn set_prop_val(&mut self, num: usize, val: &ParamValue) -> bool; + fn is_prop_readable(&mut self, num: usize) -> bool; + fn is_prop_writable(&mut self, num: usize) -> bool; + fn get_n_methods(&mut self) -> usize; + fn find_method(&mut self, name: &[u16]) -> Option; + fn get_method_name(&mut self, num: usize, alias: usize) -> Option<&'static [u16]>; + fn get_n_params(&mut self, num: usize) -> usize; + fn get_param_def_value( + &mut self, + method_num: usize, + param_num: usize, + value: ReturnValue, + ) -> bool; + fn has_ret_val(&mut self, method_num: usize) -> bool; + fn call_as_proc(&mut self, method_num: usize, params: &[ParamValue]) -> bool; + fn call_as_func(&mut self, method_num: usize, params: &[ParamValue], val: ReturnValue) -> bool; + fn set_locale(&mut self, loc: &[u16]); + fn set_user_interface_language_code(&mut self, lang: &[u16]); +} diff --git a/src/addin2.rs b/src/addin2.rs deleted file mode 100644 index d8a81cc..0000000 --- a/src/addin2.rs +++ /dev/null @@ -1,121 +0,0 @@ -use crate::ffi::{Addin, Connection, ParamValue, ReturnValue}; -use utf16_lit::utf16_null; - -pub struct Addin2 { - test1: i32, -} - -impl Addin2 { - pub fn new() -> Addin2 { - Addin2 { test1: 12345 } - } -} - -impl Drop for Addin2 { - fn drop(&mut self) { - - } -} - -impl Addin for Addin2 { - fn init(&mut self, _interface: &'static Connection) -> bool { - - true - } - - fn done(&mut self) { - - } - - fn register_extension_as(&mut self) -> &'static [u16] { - &utf16_null!("Class2") - } - - fn get_n_props(&mut self) -> usize { - 1 - } - - fn find_prop(&mut self, name: &[u16]) -> Option { - const TEST1: &[u16] = &utf16_null!("Test1"); - match name { - TEST1 => Some(0), - _ => None, - } - } - - fn get_prop_name(&mut self, num: usize, _alias: usize) -> Option<&'static [u16]> { - if num == 0 { - Some(&utf16_null!("Test1")) - } else { - None - } - } - - fn get_prop_val(&mut self, num: usize, val: ReturnValue) -> bool { - match num { - 0 => { - val.set_i32(self.test1); - true - } - _ => false, - } - } - - fn set_prop_val(&mut self, _num: usize, _val: &ParamValue) -> bool { - false - } - - fn is_prop_readable(&mut self, _num: usize) -> bool { - true - } - - fn is_prop_writable(&mut self, _num: usize) -> bool { - false - } - - fn get_n_methods(&mut self) -> usize { - 0 - } - - fn find_method(&mut self, _name: &[u16]) -> Option { - None - } - - fn get_method_name(&mut self, _num: usize, _alias: usize) -> Option<&'static [u16]> { - None - } - - fn get_n_params(&mut self, _num: usize) -> usize { - 0 - } - - fn get_param_def_value( - &mut self, - _method_num: usize, - _param_num: usize, - _value: ReturnValue, - ) -> bool { - true - } - - fn has_ret_val(&mut self, _method_num: usize) -> bool { - false - } - - fn call_as_proc(&mut self, _method_num: usize, _params: &[ParamValue]) -> bool { - false - } - - fn call_as_func( - &mut self, - _method_num: usize, - _params: &[ParamValue], - _val: ReturnValue, - ) -> bool { - false - } - - fn set_locale(&mut self, _loc: &[u16]) {} - - fn set_user_interface_language_code(&mut self, _lang: &[u16]) {} -} diff --git a/src/ffi.rs b/src/ffi.rs deleted file mode 100644 index 08ea923..0000000 --- a/src/ffi.rs +++ /dev/null @@ -1,729 +0,0 @@ -use std::{ - ffi::{c_int, c_long, c_ulong, c_void}, - ptr::{self, NonNull}, - slice::{from_raw_parts, from_raw_parts_mut}, -}; - -#[repr(C)] -#[derive(Debug)] -pub enum AttachType { - CanAttachNotIsolated = 1, - CanAttachIsolated, - CanAttachAny, -} - -#[repr(C)] -#[derive(Clone, Copy, Default)] -pub struct Tm { - pub sec: c_int, // seconds after the minute - [0, 60] including leap second - pub min: c_int, // minutes after the hour - [0, 59] - pub hour: c_int, // hours since midnight - [0, 23] - pub mday: c_int, // day of the month - [1, 31] - pub mon: c_int, // months since January - [0, 11] - pub year: c_int, // years since 1900 - pub wday: c_int, // days since Sunday - [0, 6] - pub yday: c_int, // days since January 1 - [0, 365] - pub isdst: c_int, // daylight savings time flag - - #[cfg(target_family = "unix")] - pub gmtoff: std::ffi::c_long, // seconds east of UTC - #[cfg(target_family = "unix")] - pub zone: std::ffi::c_char, // timezone abbreviation -} - -pub struct ReturnValue<'a> { - mem: &'a MemoryManager, - variant: &'a mut TVariant, - result: &'a mut bool, -} - -#[allow(dead_code)] -impl<'a> ReturnValue<'a> { - pub fn set_empty(self) { - self.variant.vt = VariantType::EMPTY; - } - pub fn set_i32(self, val: i32) { - self.variant.vt = VariantType::I4; - self.variant.value.i32 = val; - } - - pub fn set_bool(self, val: bool) { - self.variant.vt = VariantType::BOOL; - self.variant.value.bool = val; - } - - pub fn set_f64(self, val: f64) { - self.variant.vt = VariantType::R8; - self.variant.value.f64 = val; - } - - pub fn set_date(self, val: Tm) { - self.variant.vt = VariantType::TM; - self.variant.value.tm = val; - } - - pub fn set_str(self, val: &[u16]) { - let Some(ptr) = self.mem.alloc_str(val.len()) else { - *self.result = false; - return; - }; - - unsafe { ptr::copy_nonoverlapping(val.as_ptr(), ptr.as_ptr(), val.len()) }; - - self.variant.vt = VariantType::PWSTR; - self.variant.value.data_str.ptr = ptr.as_ptr(); - self.variant.value.data_str.len = val.len() as u32; - } - - pub fn set_blob(self, val: &[u8]) { - let Some(ptr) = self.mem.alloc_blob(val.len()) else { - *self.result = false; - return; - }; - - unsafe { ptr::copy_nonoverlapping(val.as_ptr(), ptr.as_ptr(), val.len()) }; - - self.variant.vt = VariantType::BLOB; - self.variant.value.data_blob.ptr = ptr.as_ptr(); - self.variant.value.data_blob.len = val.len() as u32; - } - - pub fn alloc_str(self, len: usize) -> Option<&'a mut [u16]> { - let Some(ptr) = self.mem.alloc_str(len) else { - *self.result = false; - return None; - }; - - unsafe { ptr::write_bytes(ptr.as_ptr(), 0, len) }; - - self.variant.vt = VariantType::PWSTR; - self.variant.value.data_str.ptr = ptr.as_ptr(); - self.variant.value.data_str.len = len as u32; - - Some(unsafe { from_raw_parts_mut(ptr.as_ptr(), len) }) - } - - pub fn alloc_blob(self, len: usize) -> Option<&'a mut [u8]> { - let Some(ptr) = self.mem.alloc_blob(len) else { - *self.result = false; - return None; - }; - - unsafe { ptr::write_bytes(ptr.as_ptr(), 0, len) }; - - self.variant.vt = VariantType::BLOB; - self.variant.value.data_blob.ptr = ptr.as_ptr(); - self.variant.value.data_blob.len = len as u32; - - Some(unsafe { from_raw_parts_mut(ptr.as_ptr(), len) }) - } -} - -pub enum ParamValue<'a> { - Empty, - Bool(bool), - I32(i32), - F64(f64), - Date(Tm), - Str(&'a [u16]), - Blob(&'a [u8]), -} - -impl<'a> From<&'a TVariant> for ParamValue<'a> { - fn from(param: &'a TVariant) -> ParamValue { - unsafe { - match param.vt { - VariantType::EMPTY => Self::Empty, - VariantType::BOOL => Self::Bool(param.value.bool), - VariantType::I4 => Self::I32(param.value.i32), - VariantType::R8 => Self::F64(param.value.f64), - VariantType::TM => Self::Date(param.value.tm), - VariantType::PWSTR => Self::Str(from_raw_parts( - param.value.data_str.ptr, - param.value.data_str.len as usize, - )), - VariantType::BLOB => Self::Blob(from_raw_parts( - param.value.data_blob.ptr, - param.value.data_blob.len as usize, - )), - _ => Self::Empty, - } - } - } -} - -#[repr(u16)] -#[allow(dead_code)] -enum VariantType { - EMPTY = 0, - NULL, - I2, //int16_t - I4, //int32_t - R4, //float - R8, //double - DATE, //DATE (double) - TM, //struct tm - PSTR, //struct str string - INTERFACE, //struct iface - ERROR, //int32_t errCode - BOOL, //bool - VARIANT, //struct _tVariant * - I1, //int8_t - UI1, //uint8_t - UI2, //uint16_t - UI4, //uint32_t - I8, //int64_t - UI8, //uint64_t - INT, //int Depends on architecture - UINT, //unsigned int Depends on architecture - HRESULT, //long hRes - PWSTR, //struct wstr - BLOB, //means in struct str binary data contain - CLSID, //UUID - - UNDEFINED = 0xFFFF, -} - -#[repr(C)] -#[derive(Clone, Copy)] -struct DataStr { - pub ptr: *mut u16, - pub len: u32, -} - -#[repr(C)] -#[derive(Clone, Copy)] -struct DataBlob { - pub ptr: *mut u8, - pub len: u32, -} - -#[repr(C)] -union VariantValue { - pub bool: bool, - pub i32: i32, - pub f64: f64, - pub tm: Tm, - pub data_str: DataStr, - pub data_blob: DataBlob, -} - -#[repr(C)] -struct TVariant { - value: VariantValue, - elements: u32, //Dimension for an one-dimensional array in pvarVal - vt: VariantType, -} - -pub trait Addin { - fn init(&mut self, interface: &'static Connection) -> bool; - - /// default 2000, don't use version 1000, because static objects are created - fn get_info(&mut self) -> u16 { - 2000 - } - fn done(&mut self); - fn register_extension_as(&mut self) -> &'static [u16]; - fn get_n_props(&mut self) -> usize; - fn find_prop(&mut self, name: &[u16]) -> Option; - fn get_prop_name(&mut self, num: usize, alias: usize) -> Option<&'static [u16]>; - fn get_prop_val(&mut self, num: usize, val: ReturnValue) -> bool; - fn set_prop_val(&mut self, num: usize, val: &ParamValue) -> bool; - fn is_prop_readable(&mut self, num: usize) -> bool; - fn is_prop_writable(&mut self, num: usize) -> bool; - fn get_n_methods(&mut self) -> usize; - fn find_method(&mut self, name: &[u16]) -> Option; - fn get_method_name(&mut self, num: usize, alias: usize) -> Option<&'static [u16]>; - fn get_n_params(&mut self, num: usize) -> usize; - fn get_param_def_value( - &mut self, - method_num: usize, - param_num: usize, - value: ReturnValue, - ) -> bool; - fn has_ret_val(&mut self, method_num: usize) -> bool; - fn call_as_proc(&mut self, method_num: usize, params: &[ParamValue]) -> bool; - fn call_as_func(&mut self, method_num: usize, params: &[ParamValue], val: ReturnValue) -> bool; - fn set_locale(&mut self, loc: &[u16]); - fn set_user_interface_language_code(&mut self, lang: &[u16]); -} - -#[repr(C)] -struct This { - ptr: *mut Component, -} - -impl<'a, const OFFSET: usize, T: Addin> This { - unsafe fn get_component(&mut self) -> &'a mut Component { - let new_ptr = (self as *mut This as *mut c_void) - .sub(OFFSET * std::mem::size_of::()); - &mut *(new_ptr as *mut Component) - } -} - -#[repr(C)] -struct InitDoneBaseVTable { - dtor: usize, - #[cfg(target_family = "unix")] - dtor2: usize, - init: unsafe extern "system" fn(&mut This<0, T>, &'static Connection) -> bool, - set_mem_manager: unsafe extern "system" fn(&mut This<0, T>, &'static MemoryManager) -> bool, - get_info: unsafe extern "system" fn(&mut This<0, T>) -> c_long, - done: unsafe extern "system" fn(&mut This<0, T>), -} - -unsafe extern "system" fn init( - this: &mut This<0, T>, - interface: &'static Connection, -) -> bool { - let component = this.get_component(); - component.addin.init(interface) -} - -unsafe extern "system" fn set_mem_manager( - this: &mut This<0, T>, - mem: &'static MemoryManager, -) -> bool { - let component = this.get_component(); - component.memory = Some(mem); - true -} - -unsafe extern "system" fn get_info(this: &mut This<0, T>) -> c_long { - let component = this.get_component(); - component.addin.get_info() as c_long -} - -unsafe extern "system" fn done(this: &mut This<0, T>) { - let component = this.get_component(); - component.addin.done() -} - -#[repr(C)] -struct LanguageExtenderBaseVTable { - dtor: usize, - #[cfg(target_family = "unix")] - dtor2: usize, - register_extension_as: unsafe extern "system" fn(&mut This<1, T>, *mut *mut u16) -> bool, - get_n_props: unsafe extern "system" fn(&mut This<1, T>) -> c_long, - find_prop: unsafe extern "system" fn(&mut This<1, T>, *const u16) -> c_long, - get_prop_name: unsafe extern "system" fn(&mut This<1, T>, c_long, c_long) -> *const u16, - get_prop_val: unsafe extern "system" fn(&mut This<1, T>, c_long, &mut TVariant) -> bool, - set_prop_val: unsafe extern "system" fn(&mut This<1, T>, c_long, &TVariant) -> bool, - is_prop_readable: unsafe extern "system" fn(&mut This<1, T>, c_long) -> bool, - is_prop_writable: unsafe extern "system" fn(&mut This<1, T>, c_long) -> bool, - get_n_methods: unsafe extern "system" fn(&mut This<1, T>) -> c_long, - find_method: unsafe extern "system" fn(&mut This<1, T>, *const u16) -> c_long, - get_method_name: unsafe extern "system" fn(&mut This<1, T>, c_long, c_long) -> *const u16, - get_n_params: unsafe extern "system" fn(&mut This<1, T>, c_long) -> c_long, - get_param_def_value: - unsafe extern "system" fn(&mut This<1, T>, c_long, c_long, &mut TVariant) -> bool, - has_ret_val: unsafe extern "system" fn(&mut This<1, T>, c_long) -> bool, - call_as_proc: - unsafe extern "system" fn(&mut This<1, T>, c_long, *const TVariant, c_long) -> bool, - call_as_func: unsafe extern "system" fn( - &mut This<1, T>, - c_long, - &mut TVariant, - *const TVariant, - c_long, - ) -> bool, -} - -unsafe extern "system" fn register_extension_as( - this: &mut This<1, T>, - name: *mut *mut u16, -) -> bool { - let component = this.get_component(); - let Some(allocator) = component.memory else { - return false; - }; - - let extension_name = component.addin.register_extension_as(); - - let Some(ptr) = allocator.alloc_str(extension_name.len()) else { - return false; - }; - ptr::copy_nonoverlapping(extension_name.as_ptr(), ptr.as_ptr(), extension_name.len()); - *name = ptr.as_ptr(); - - true -} - -unsafe extern "system" fn get_n_props(this: &mut This<1, T>) -> c_long { - let component = this.get_component(); - component.addin.get_n_props() as c_long -} - -unsafe extern "system" fn find_prop(this: &mut This<1, T>, name: *const u16) -> c_long { - let component = this.get_component(); - let name = get_str(name); - match component.addin.find_prop(name) { - Some(i) => i as c_long, - None => -1, - } -} - -unsafe extern "system" fn get_prop_name( - this: &mut This<1, T>, - num: c_long, - alias: c_long, -) -> *const u16 { - let component = this.get_component(); - let Some(allocator) = component.memory else { - return ptr::null(); - }; - let Some(prop_name) = component.addin.get_prop_name(num as usize, alias as usize) else { - return ptr::null(); - }; - let Some(ptr) = allocator.alloc_str(prop_name.len()) else { - return ptr::null(); - }; - ptr::copy_nonoverlapping(prop_name.as_ptr(), ptr.as_ptr(), prop_name.len()); - - ptr.as_ptr() -} - -unsafe extern "system" fn get_prop_val( - component: &mut This<1, T>, - num: c_long, - val: &mut TVariant, -) -> bool { - let component = component.get_component(); - let Some(mem) = component.memory else { - return false; - }; - - let mut result = true; - let return_value = ReturnValue { - mem, - variant: val, - result: &mut result, - }; - component.addin.get_prop_val(num as usize, return_value) && result -} - -unsafe extern "system" fn set_prop_val( - this: &mut This<1, T>, - num: c_long, - val: &TVariant, -) -> bool { - let component = this.get_component(); - let param = ParamValue::from(val); - component.addin.set_prop_val(num as usize, ¶m) -} - -unsafe extern "system" fn is_prop_readable(this: &mut This<1, T>, num: c_long) -> bool { - let component = this.get_component(); - component.addin.is_prop_readable(num as usize) -} - -unsafe extern "system" fn is_prop_writable(this: &mut This<1, T>, num: c_long) -> bool { - let component = this.get_component(); - component.addin.is_prop_writable(num as usize) -} - -unsafe extern "system" fn get_n_methods(this: &mut This<1, T>) -> c_long { - let component = this.get_component(); - component.addin.get_n_methods() as c_long -} - -unsafe extern "system" fn find_method(this: &mut This<1, T>, name: *const u16) -> c_long { - let component = this.get_component(); - let name = get_str(name); - match component.addin.find_method(name) { - Some(i) => i as c_long, - None => -1, - } -} - -unsafe extern "system" fn get_method_name( - this: &mut This<1, T>, - num: c_long, - alias: c_long, -) -> *const u16 { - let component = this.get_component(); - let Some(allocator) = component.memory else { - return ptr::null(); - }; - let Some(method_name) = component.addin.get_method_name(num as usize, alias as usize) else { - return ptr::null(); - }; - let Some(ptr) = allocator.alloc_str(method_name.len()) else { - return ptr::null(); - }; - - ptr::copy_nonoverlapping(method_name.as_ptr(), ptr.as_ptr(), method_name.len()); - - ptr.as_ptr() -} - -unsafe extern "system" fn get_n_params(this: &mut This<1, T>, num: c_long) -> c_long { - let component = this.get_component(); - component.addin.get_n_params(num as usize) as c_long -} - -unsafe extern "system" fn get_param_def_value( - this: &mut This<1, T>, - method_num: c_long, - param_num: c_long, - val: &mut TVariant, -) -> bool { - let component = this.get_component(); - let Some(mem) = component.memory else { - return false; - }; - - let mut result = true; - let return_value = ReturnValue { - mem, - variant: val, - result: &mut result, - }; - - component - .addin - .get_param_def_value(method_num as usize, param_num as usize, return_value) - && result -} - -unsafe extern "system" fn has_ret_val(this: &mut This<1, T>, method_num: c_long) -> bool { - let component = this.get_component(); - component.addin.has_ret_val(method_num as usize) -} - -unsafe extern "system" fn call_as_proc( - this: &mut This<1, T>, - method_num: c_long, - params: *const TVariant, - size_array: c_long, -) -> bool { - let component = this.get_component(); - let param_values = from_raw_parts(params, size_array as usize) - .iter() - .map(|x| ParamValue::from(x)) - .collect::>(); - - component - .addin - .call_as_proc(method_num as usize, param_values.as_slice()) -} - -unsafe extern "system" fn call_as_func( - this: &mut This<1, T>, - method_num: c_long, - ret_value: &mut TVariant, - params: *const TVariant, - size_array: c_long, -) -> bool { - let component = this.get_component(); - let Some(mem) = component.memory else { - return false; - }; - - let mut result = true; - let return_value = ReturnValue { - mem, - variant: ret_value, - result: &mut result, - }; - - let param_values = from_raw_parts(params, size_array as usize) - .iter() - .map(|x| ParamValue::from(x)) - .collect::>(); - - component - .addin - .call_as_func(method_num as usize, param_values.as_slice(), return_value) - && result -} - -#[repr(C)] -struct LocaleBaseVTable { - dtor: usize, - #[cfg(target_family = "unix")] - dtor2: usize, - set_locale: unsafe extern "system" fn(&mut This<2, T>, *const u16), -} - -unsafe extern "system" fn set_locale(this: &mut This<2, T>, loc: *const u16) { - let component = this.get_component(); - let loc = get_str(loc); - component.addin.set_locale(loc) -} - -#[repr(C)] -struct UserLanguageBaseVTable { - dtor: usize, - #[cfg(target_family = "unix")] - dtor2: usize, - set_user_interface_language_code: unsafe extern "system" fn(&mut This<3, T>, *const u16), -} - -unsafe extern "system" fn set_user_interface_language_code( - this: &mut This<3, T>, - lang: *const u16, -) { - let component = this.get_component(); - let lang = get_str(lang); - component.addin.set_user_interface_language_code(lang) -} - -#[repr(C)] -struct Component { - vptr1: Box>, - vptr2: Box>, - vptr3: Box>, - vptr4: Box>, - destroy: unsafe extern "system" fn(*mut *mut Component), - memory: Option<&'static MemoryManager>, - addin: T, -} - -unsafe extern "system" fn destroy(component: *mut *mut Component) { - let comp = Box::from_raw(*component); - drop(comp); -} - -pub unsafe fn create_component(component: *mut *mut c_void, addin: T) -> c_long { - let vptr1 = Box::new(InitDoneBaseVTable { - dtor: 0, - #[cfg(target_family = "unix")] - dtor2: 0, - init, - set_mem_manager, - get_info, - done, - }); - - let vptr2 = Box::new(LanguageExtenderBaseVTable { - dtor: 0, - #[cfg(target_family = "unix")] - dtor2: 0, - register_extension_as, - get_n_props, - find_prop, - get_prop_name, - get_prop_val, - set_prop_val, - is_prop_readable, - is_prop_writable, - get_n_methods, - find_method, - get_method_name, - get_n_params, - get_param_def_value, - has_ret_val, - call_as_proc, - call_as_func, - }); - - let vptr3 = Box::new(LocaleBaseVTable { - dtor: 0, - #[cfg(target_family = "unix")] - dtor2: 0, - set_locale, - }); - - let vptr4 = Box::new(UserLanguageBaseVTable { - dtor: 0, - #[cfg(target_family = "unix")] - dtor2: 0, - set_user_interface_language_code, - }); - - let c = Box::new(Component { - vptr1, - vptr2, - vptr3, - vptr4, - destroy: destroy::, - memory: None, - addin, - }); - - *component = Box::into_raw(c) as *mut c_void; - 1 -} - -pub unsafe fn destroy_component(component: *mut *mut c_void) -> c_long { - #[repr(C)] - struct ComponentWrapper { - vptr1: usize, - vptr2: usize, - vptr3: usize, - vptr4: usize, - destroy: unsafe extern "system" fn(*mut *mut c_void), - } - - let wrapper = *component as *mut ComponentWrapper; - let wrapper = &mut *wrapper; - (wrapper.destroy)(component); - *component = ptr::null_mut(); - - 0 -} - -#[repr(C)] -struct MemoryManagerVTable { - dtor: usize, - #[cfg(target_family = "unix")] - dtor2: usize, - alloc_memory: unsafe extern "system" fn(&MemoryManager, *mut *mut c_void, c_ulong) -> bool, - free_memory: unsafe extern "system" fn(&MemoryManager, *mut *mut c_void), -} - -#[repr(C)] -struct MemoryManager { - vptr: &'static MemoryManagerVTable, -} - -impl MemoryManager { - pub fn alloc_blob(&self, size: usize) -> Option> { - let mut ptr = ptr::null_mut::(); - unsafe { - if (self.vptr.alloc_memory)(self, &mut ptr, size as c_ulong) { - NonNull::new(ptr as *mut u8) - } else { - None - } - } - } - - pub fn alloc_str(&self, size: usize) -> Option> { - let mut ptr = ptr::null_mut::(); - unsafe { - if (self.vptr.alloc_memory)(self, &mut ptr, size as c_ulong * 2) { - NonNull::new(ptr as *mut u16) - } else { - None - } - } - } -} - -#[repr(C)] -struct ConnectionVTable { - dtor: usize, - #[cfg(target_family = "unix")] - dtor2: usize, -} - -#[repr(C)] -pub struct Connection { - vptr1: &'static ConnectionVTable, -} - -unsafe fn get_str<'a>(s: *const u16) -> &'a [u16] { - unsafe fn strlen(s: *const u16) -> usize { - let mut i = 0; - while *s.add(i) != 0 { - i += 1; - } - i + 1 - } - - let len = strlen(s); - from_raw_parts(s, len) -} diff --git a/src/ffi/connection.rs b/src/ffi/connection.rs new file mode 100644 index 0000000..f606bae --- /dev/null +++ b/src/ffi/connection.rs @@ -0,0 +1,47 @@ +use std::ffi::{c_long, c_ushort}; +use utf16_lit::utf16_null; + +use super::types::TVariant; + +#[repr(C)] +struct ConnectionVTable { + dtor: usize, + #[cfg(target_family = "unix")] + dtor2: usize, + add_error: + unsafe extern "system" fn(&Connection, c_ushort, *const u16, *const u16, c_long) -> bool, + read: unsafe extern "system" fn( + &Connection, + *mut u16, + &mut TVariant, + c_long, + *mut *mut u16, + ) -> bool, + write: unsafe extern "system" fn(&Connection, *mut u16, &mut TVariant) -> bool, + register_profile_as: unsafe extern "system" fn(&Connection, *mut u16) -> bool, + set_event_buffer_depth: unsafe extern "system" fn(&Connection, c_long) -> bool, + get_event_buffer_depth: unsafe extern "system" fn(&Connection) -> c_long, + external_event: unsafe extern "system" fn(&Connection, *mut u16, *mut u16, *mut u16) -> bool, + clean_event_buffer: unsafe extern "system" fn(&Connection), + set_status_line: unsafe extern "system" fn(&Connection, *mut u16) -> bool, + reset_status_line: unsafe extern "system" fn(&Connection), +} + +#[repr(C)] +pub struct Connection { + vptr1: &'static ConnectionVTable, +} + +impl Connection { + pub fn external_event(&self, caller: &str, name: &str, data: &str) -> bool { + unsafe { + let caller_ptr = utf16_null!("caller").as_mut_ptr(); + let name_ptr = utf16_null!("name").as_mut_ptr(); + let data_ptr = utf16_null!("data").as_mut_ptr(); + (self.vptr1.external_event)(self, caller_ptr, name_ptr, data_ptr) + } + } + pub fn get_event_buffer_depth(&self) -> c_long { + unsafe { (self.vptr1.get_event_buffer_depth)(self) } + } +} diff --git a/src/ffi/init_base.rs b/src/ffi/init_base.rs new file mode 100644 index 0000000..6ad72ef --- /dev/null +++ b/src/ffi/init_base.rs @@ -0,0 +1,56 @@ +use std::ffi::c_long; + +use super::{connection::Connection, memory_manager::MemoryManager, This}; +use crate::add_in::AddIn; + +#[repr(C)] +pub struct InitDoneBaseVTable { + dtor: usize, + #[cfg(target_family = "unix")] + dtor2: usize, + init: unsafe extern "system" fn(&mut This<0, T>, &'static Connection) -> bool, + set_mem_manager: unsafe extern "system" fn(&mut This<0, T>, &'static MemoryManager) -> bool, + get_info: unsafe extern "system" fn(&mut This<0, T>) -> c_long, + done: unsafe extern "system" fn(&mut This<0, T>), +} + +unsafe extern "system" fn init( + this: &mut This<0, T>, + interface: &'static Connection, +) -> bool { + let component = this.get_component(); + component.addin.init(interface) +} + +unsafe extern "system" fn set_mem_manager( + this: &mut This<0, T>, + mem: &'static MemoryManager, +) -> bool { + let component = this.get_component(); + component.memory = Some(mem); + true +} + +unsafe extern "system" fn get_info(this: &mut This<0, T>) -> c_long { + let component = this.get_component(); + component.addin.get_info() as c_long +} + +unsafe extern "system" fn done(this: &mut This<0, T>) { + let component = this.get_component(); + component.addin.done() +} + +impl InitDoneBaseVTable { + pub fn new() -> Self { + Self { + dtor: 0, + #[cfg(target_family = "unix")] + dtor2: 0, + init, + set_mem_manager, + get_info, + done, + } + } +} diff --git a/src/ffi/lang_extender.rs b/src/ffi/lang_extender.rs new file mode 100644 index 0000000..4e61558 --- /dev/null +++ b/src/ffi/lang_extender.rs @@ -0,0 +1,279 @@ +use std::{ + ffi::c_long, + ptr::{self}, + slice::from_raw_parts, +}; + +use crate::add_in::AddIn; + +use super::{ + get_str, + types::{ParamValue, ReturnValue, TVariant}, + This, +}; + +#[repr(C)] +pub struct LanguageExtenderBaseVTable { + dtor: usize, + #[cfg(target_family = "unix")] + dtor2: usize, + register_extension_as: unsafe extern "system" fn(&mut This<1, T>, *mut *mut u16) -> bool, + get_n_props: unsafe extern "system" fn(&mut This<1, T>) -> c_long, + find_prop: unsafe extern "system" fn(&mut This<1, T>, *const u16) -> c_long, + get_prop_name: unsafe extern "system" fn(&mut This<1, T>, c_long, c_long) -> *const u16, + get_prop_val: unsafe extern "system" fn(&mut This<1, T>, c_long, &mut TVariant) -> bool, + set_prop_val: unsafe extern "system" fn(&mut This<1, T>, c_long, &TVariant) -> bool, + is_prop_readable: unsafe extern "system" fn(&mut This<1, T>, c_long) -> bool, + is_prop_writable: unsafe extern "system" fn(&mut This<1, T>, c_long) -> bool, + get_n_methods: unsafe extern "system" fn(&mut This<1, T>) -> c_long, + find_method: unsafe extern "system" fn(&mut This<1, T>, *const u16) -> c_long, + get_method_name: unsafe extern "system" fn(&mut This<1, T>, c_long, c_long) -> *const u16, + get_n_params: unsafe extern "system" fn(&mut This<1, T>, c_long) -> c_long, + get_param_def_value: + unsafe extern "system" fn(&mut This<1, T>, c_long, c_long, &mut TVariant) -> bool, + has_ret_val: unsafe extern "system" fn(&mut This<1, T>, c_long) -> bool, + call_as_proc: + unsafe extern "system" fn(&mut This<1, T>, c_long, *const TVariant, c_long) -> bool, + call_as_func: unsafe extern "system" fn( + &mut This<1, T>, + c_long, + &mut TVariant, + *const TVariant, + c_long, + ) -> bool, +} + +unsafe extern "system" fn register_extension_as( + this: &mut This<1, T>, + name: *mut *mut u16, +) -> bool { + let component = this.get_component(); + let Some(allocator) = component.memory else { + return false; + }; + + let extension_name = component.addin.register_extension_as(); + + let Some(ptr) = allocator.alloc_str(extension_name.len()) else { + return false; + }; + ptr::copy_nonoverlapping(extension_name.as_ptr(), ptr.as_ptr(), extension_name.len()); + *name = ptr.as_ptr(); + + true +} + +unsafe extern "system" fn get_n_props(this: &mut This<1, T>) -> c_long { + let component = this.get_component(); + component.addin.get_n_props() as c_long +} + +unsafe extern "system" fn find_prop(this: &mut This<1, T>, name: *const u16) -> c_long { + let component = this.get_component(); + let name = get_str(name); + match component.addin.find_prop(name) { + Some(i) => i as c_long, + None => -1, + } +} + +unsafe extern "system" fn get_prop_name( + this: &mut This<1, T>, + num: c_long, + alias: c_long, +) -> *const u16 { + let component = this.get_component(); + let Some(allocator) = component.memory else { + return ptr::null(); + }; + let Some(prop_name) = component.addin.get_prop_name(num as usize, alias as usize) else { + return ptr::null(); + }; + let Some(ptr) = allocator.alloc_str(prop_name.len()) else { + return ptr::null(); + }; + ptr::copy_nonoverlapping(prop_name.as_ptr(), ptr.as_ptr(), prop_name.len()); + + ptr.as_ptr() +} + +unsafe extern "system" fn get_prop_val( + component: &mut This<1, T>, + num: c_long, + val: &mut TVariant, +) -> bool { + let component = component.get_component(); + let Some(mem) = component.memory else { + return false; + }; + + let mut result = true; + let return_value = ReturnValue { + mem, + variant: val, + result: &mut result, + }; + component.addin.get_prop_val(num as usize, return_value) && result +} + +unsafe extern "system" fn set_prop_val( + this: &mut This<1, T>, + num: c_long, + val: &TVariant, +) -> bool { + let component = this.get_component(); + let param = ParamValue::from(val); + component.addin.set_prop_val(num as usize, ¶m) +} + +unsafe extern "system" fn is_prop_readable(this: &mut This<1, T>, num: c_long) -> bool { + let component = this.get_component(); + component.addin.is_prop_readable(num as usize) +} + +unsafe extern "system" fn is_prop_writable(this: &mut This<1, T>, num: c_long) -> bool { + let component = this.get_component(); + component.addin.is_prop_writable(num as usize) +} + +unsafe extern "system" fn get_n_methods(this: &mut This<1, T>) -> c_long { + let component = this.get_component(); + component.addin.get_n_methods() as c_long +} + +unsafe extern "system" fn find_method(this: &mut This<1, T>, name: *const u16) -> c_long { + let component = this.get_component(); + let name = get_str(name); + match component.addin.find_method(name) { + Some(i) => i as c_long, + None => -1, + } +} + +unsafe extern "system" fn get_method_name( + this: &mut This<1, T>, + num: c_long, + alias: c_long, +) -> *const u16 { + let component = this.get_component(); + let Some(allocator) = component.memory else { + return ptr::null(); + }; + let Some(method_name) = component.addin.get_method_name(num as usize, alias as usize) else { + return ptr::null(); + }; + let Some(ptr) = allocator.alloc_str(method_name.len()) else { + return ptr::null(); + }; + + ptr::copy_nonoverlapping(method_name.as_ptr(), ptr.as_ptr(), method_name.len()); + + ptr.as_ptr() +} + +unsafe extern "system" fn get_n_params(this: &mut This<1, T>, num: c_long) -> c_long { + let component = this.get_component(); + component.addin.get_n_params(num as usize) as c_long +} + +unsafe extern "system" fn get_param_def_value( + this: &mut This<1, T>, + method_num: c_long, + param_num: c_long, + val: &mut TVariant, +) -> bool { + let component = this.get_component(); + let Some(mem) = component.memory else { + return false; + }; + + let mut result = true; + let return_value = ReturnValue { + mem, + variant: val, + result: &mut result, + }; + + component + .addin + .get_param_def_value(method_num as usize, param_num as usize, return_value) + && result +} + +unsafe extern "system" fn has_ret_val(this: &mut This<1, T>, method_num: c_long) -> bool { + let component = this.get_component(); + component.addin.has_ret_val(method_num as usize) +} + +unsafe extern "system" fn call_as_proc( + this: &mut This<1, T>, + method_num: c_long, + params: *const TVariant, + size_array: c_long, +) -> bool { + let component = this.get_component(); + let param_values = from_raw_parts(params, size_array as usize) + .iter() + .map(|x| ParamValue::from(x)) + .collect::>(); + + component + .addin + .call_as_proc(method_num as usize, param_values.as_slice()) +} + +unsafe extern "system" fn call_as_func( + this: &mut This<1, T>, + method_num: c_long, + ret_value: &mut TVariant, + params: *const TVariant, + size_array: c_long, +) -> bool { + let component = this.get_component(); + let Some(mem) = component.memory else { + return false; + }; + + let mut result = true; + let return_value = ReturnValue { + mem, + variant: ret_value, + result: &mut result, + }; + + let param_values = from_raw_parts(params, size_array as usize) + .iter() + .map(|x| ParamValue::from(x)) + .collect::>(); + + component + .addin + .call_as_func(method_num as usize, param_values.as_slice(), return_value) + && result +} + +impl LanguageExtenderBaseVTable { + pub fn new() -> Self { + Self { + dtor: 0, + #[cfg(target_family = "unix")] + dtor2: 0, + register_extension_as, + get_n_props, + find_prop, + get_prop_name, + get_prop_val, + set_prop_val, + is_prop_readable, + is_prop_writable, + get_n_methods, + find_method, + get_method_name, + get_n_params, + get_param_def_value, + has_ret_val, + call_as_proc, + call_as_func, + } + } +} diff --git a/src/ffi/memory_manager.rs b/src/ffi/memory_manager.rs new file mode 100644 index 0000000..d74f768 --- /dev/null +++ b/src/ffi/memory_manager.rs @@ -0,0 +1,42 @@ +use std::{ + ffi::{c_ulong, c_void}, + ptr::{self, NonNull}, +}; + +#[repr(C)] +struct MemoryManagerVTable { + dtor: usize, + #[cfg(target_family = "unix")] + dtor2: usize, + alloc_memory: unsafe extern "system" fn(&MemoryManager, *mut *mut c_void, c_ulong) -> bool, + free_memory: unsafe extern "system" fn(&MemoryManager, *mut *mut c_void), +} + +#[repr(C)] +pub struct MemoryManager { + vptr: &'static MemoryManagerVTable, +} + +impl MemoryManager { + pub fn alloc_blob(&self, size: usize) -> Option> { + let mut ptr = ptr::null_mut::(); + unsafe { + if (self.vptr.alloc_memory)(self, &mut ptr, size as c_ulong) { + NonNull::new(ptr as *mut u8) + } else { + None + } + } + } + + pub fn alloc_str(&self, size: usize) -> Option> { + let mut ptr = ptr::null_mut::(); + unsafe { + if (self.vptr.alloc_memory)(self, &mut ptr, size as c_ulong * 2) { + NonNull::new(ptr as *mut u16) + } else { + None + } + } + } +} diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs new file mode 100644 index 0000000..9d55c6f --- /dev/null +++ b/src/ffi/mod.rs @@ -0,0 +1,135 @@ +use std::{ + ffi::{c_long, c_void}, + ptr, +}; + +use crate::add_in::AddIn; + +use self::{ + init_base::InitDoneBaseVTable, lang_extender::LanguageExtenderBaseVTable, + memory_manager::MemoryManager, utils::get_str, +}; + +pub mod connection; +pub mod init_base; +pub mod lang_extender; +pub mod memory_manager; +pub mod types; +pub mod utils; + +#[repr(C)] +#[derive(Debug)] +pub enum AttachType { + CanAttachNotIsolated = 1, + CanAttachIsolated, + CanAttachAny, +} + +#[repr(C)] +struct This { + ptr: *mut Component, +} + +impl<'a, const OFFSET: usize, T: AddIn> This { + unsafe fn get_component(&mut self) -> &'a mut Component { + let new_ptr = (self as *mut This as *mut c_void) + .sub(OFFSET * std::mem::size_of::()); + &mut *(new_ptr as *mut Component) + } +} + +#[repr(C)] +struct LocaleBaseVTable { + dtor: usize, + #[cfg(target_family = "unix")] + dtor2: usize, + set_locale: unsafe extern "system" fn(&mut This<2, T>, *const u16), +} + +unsafe extern "system" fn set_locale(this: &mut This<2, T>, loc: *const u16) { + let component = this.get_component(); + let loc = get_str(loc); + component.addin.set_locale(loc) +} + +#[repr(C)] +struct UserLanguageBaseVTable { + dtor: usize, + #[cfg(target_family = "unix")] + dtor2: usize, + set_user_interface_language_code: unsafe extern "system" fn(&mut This<3, T>, *const u16), +} + +unsafe extern "system" fn set_user_interface_language_code( + this: &mut This<3, T>, + lang: *const u16, +) { + let component = this.get_component(); + let lang = get_str(lang); + component.addin.set_user_interface_language_code(lang) +} + +#[repr(C)] +struct Component { + vptr1: Box>, + vptr2: Box>, + vptr3: Box>, + vptr4: Box>, + destroy: unsafe extern "system" fn(*mut *mut Component), + memory: Option<&'static MemoryManager>, + addin: T, +} + +unsafe extern "system" fn destroy(component: *mut *mut Component) { + let comp = Box::from_raw(*component); + drop(comp); +} + +pub unsafe fn create_component(component: *mut *mut c_void, addin: T) -> c_long { + let vptr1 = Box::new(InitDoneBaseVTable::new()); + let vptr2 = Box::new(LanguageExtenderBaseVTable::new()); + let vptr3 = Box::new(LocaleBaseVTable { + dtor: 0, + #[cfg(target_family = "unix")] + dtor2: 0, + set_locale, + }); + + let vptr4 = Box::new(UserLanguageBaseVTable { + dtor: 0, + #[cfg(target_family = "unix")] + dtor2: 0, + set_user_interface_language_code, + }); + + let c = Box::new(Component { + vptr1, + vptr2, + vptr3, + vptr4, + destroy: destroy::, + memory: None, + addin, + }); + + *component = Box::into_raw(c) as *mut c_void; + 1 +} + +pub unsafe fn destroy_component(component: *mut *mut c_void) -> c_long { + #[repr(C)] + struct ComponentWrapper { + vptr1: usize, + vptr2: usize, + vptr3: usize, + vptr4: usize, + destroy: unsafe extern "system" fn(*mut *mut c_void), + } + + let wrapper = *component as *mut ComponentWrapper; + let wrapper = &mut *wrapper; + (wrapper.destroy)(component); + *component = ptr::null_mut(); + + 0 +} diff --git a/src/ffi/types.rs b/src/ffi/types.rs new file mode 100644 index 0000000..1d358ec --- /dev/null +++ b/src/ffi/types.rs @@ -0,0 +1,210 @@ +use std::{ + ffi::c_int, + ptr, + slice::{from_raw_parts, from_raw_parts_mut}, +}; + +use super::memory_manager::MemoryManager; + +#[repr(C)] +#[derive(Clone, Copy, Default)] +pub struct Tm { + pub sec: c_int, // seconds after the minute - [0, 60] including leap second + pub min: c_int, // minutes after the hour - [0, 59] + pub hour: c_int, // hours since midnight - [0, 23] + pub mday: c_int, // day of the month - [1, 31] + pub mon: c_int, // months since January - [0, 11] + pub year: c_int, // years since 1900 + pub wday: c_int, // days since Sunday - [0, 6] + pub yday: c_int, // days since January 1 - [0, 365] + pub isdst: c_int, // daylight savings time flag + + #[cfg(target_family = "unix")] + pub gmtoff: std::ffi::c_long, // seconds east of UTC + #[cfg(target_family = "unix")] + pub zone: std::ffi::c_char, // timezone abbreviation +} + +pub struct ReturnValue<'a> { + pub mem: &'a MemoryManager, + pub variant: &'a mut TVariant, + pub result: &'a mut bool, +} + +#[allow(dead_code)] +impl<'a> ReturnValue<'a> { + pub fn set_empty(self) { + self.variant.vt = VariantType::EMPTY; + } + pub fn set_i32(self, val: i32) { + self.variant.vt = VariantType::I4; + self.variant.value.i32 = val; + } + + pub fn set_bool(self, val: bool) { + self.variant.vt = VariantType::BOOL; + self.variant.value.bool = val; + } + + pub fn set_f64(self, val: f64) { + self.variant.vt = VariantType::R8; + self.variant.value.f64 = val; + } + + pub fn set_date(self, val: Tm) { + self.variant.vt = VariantType::TM; + self.variant.value.tm = val; + } + + pub fn set_str(self, val: &[u16]) { + let Some(ptr) = self.mem.alloc_str(val.len()) else { + *self.result = false; + return; + }; + + unsafe { ptr::copy_nonoverlapping(val.as_ptr(), ptr.as_ptr(), val.len()) }; + + self.variant.vt = VariantType::PWSTR; + self.variant.value.data_str.ptr = ptr.as_ptr(); + self.variant.value.data_str.len = val.len() as u32; + } + + pub fn set_blob(self, val: &[u8]) { + let Some(ptr) = self.mem.alloc_blob(val.len()) else { + *self.result = false; + return; + }; + + unsafe { ptr::copy_nonoverlapping(val.as_ptr(), ptr.as_ptr(), val.len()) }; + + self.variant.vt = VariantType::BLOB; + self.variant.value.data_blob.ptr = ptr.as_ptr(); + self.variant.value.data_blob.len = val.len() as u32; + } + + pub fn alloc_str(self, len: usize) -> Option<&'a mut [u16]> { + let Some(ptr) = self.mem.alloc_str(len) else { + *self.result = false; + return None; + }; + + unsafe { ptr::write_bytes(ptr.as_ptr(), 0, len) }; + + self.variant.vt = VariantType::PWSTR; + self.variant.value.data_str.ptr = ptr.as_ptr(); + self.variant.value.data_str.len = len as u32; + + Some(unsafe { from_raw_parts_mut(ptr.as_ptr(), len) }) + } + + pub fn alloc_blob(self, len: usize) -> Option<&'a mut [u8]> { + let Some(ptr) = self.mem.alloc_blob(len) else { + *self.result = false; + return None; + }; + + unsafe { ptr::write_bytes(ptr.as_ptr(), 0, len) }; + + self.variant.vt = VariantType::BLOB; + self.variant.value.data_blob.ptr = ptr.as_ptr(); + self.variant.value.data_blob.len = len as u32; + + Some(unsafe { from_raw_parts_mut(ptr.as_ptr(), len) }) + } +} + +pub enum ParamValue<'a> { + Empty, + Bool(bool), + I32(i32), + F64(f64), + Date(Tm), + Str(&'a [u16]), + Blob(&'a [u8]), +} + +impl<'a> From<&'a TVariant> for ParamValue<'a> { + fn from(param: &'a TVariant) -> ParamValue { + unsafe { + match param.vt { + VariantType::EMPTY => Self::Empty, + VariantType::BOOL => Self::Bool(param.value.bool), + VariantType::I4 => Self::I32(param.value.i32), + VariantType::R8 => Self::F64(param.value.f64), + VariantType::TM => Self::Date(param.value.tm), + VariantType::PWSTR => Self::Str(from_raw_parts( + param.value.data_str.ptr, + param.value.data_str.len as usize, + )), + VariantType::BLOB => Self::Blob(from_raw_parts( + param.value.data_blob.ptr, + param.value.data_blob.len as usize, + )), + _ => Self::Empty, + } + } + } +} + +#[repr(u16)] +#[allow(dead_code)] +enum VariantType { + EMPTY = 0, + NULL, + I2, //int16_t + I4, //int32_t + R4, //float + R8, //double + DATE, //DATE (double) + TM, //struct tm + PSTR, //struct str string + INTERFACE, //struct iface + ERROR, //int32_t errCode + BOOL, //bool + VARIANT, //struct _tVariant * + I1, //int8_t + UI1, //uint8_t + UI2, //uint16_t + UI4, //uint32_t + I8, //int64_t + UI8, //uint64_t + INT, //int Depends on architecture + UINT, //unsigned int Depends on architecture + HRESULT, //long hRes + PWSTR, //struct wstr + BLOB, //means in struct str binary data contain + CLSID, //UUID + + UNDEFINED = 0xFFFF, +} + +#[repr(C)] +#[derive(Clone, Copy)] +struct DataStr { + pub ptr: *mut u16, + pub len: u32, +} + +#[repr(C)] +#[derive(Clone, Copy)] +struct DataBlob { + pub ptr: *mut u8, + pub len: u32, +} + +#[repr(C)] +union VariantValue { + pub bool: bool, + pub i32: i32, + pub f64: f64, + pub tm: Tm, + pub data_str: DataStr, + pub data_blob: DataBlob, +} + +#[repr(C)] +pub struct TVariant { + value: VariantValue, + elements: u32, //Dimension for an one-dimensional array in pvarVal + vt: VariantType, +} diff --git a/src/ffi/utils.rs b/src/ffi/utils.rs new file mode 100644 index 0000000..aad66cc --- /dev/null +++ b/src/ffi/utils.rs @@ -0,0 +1,14 @@ +use std::slice::from_raw_parts; + +pub unsafe fn get_str<'a>(s: *const u16) -> &'a [u16] { + unsafe fn strlen(s: *const u16) -> usize { + let mut i = 0; + while *s.add(i) != 0 { + i += 1; + } + i + 1 + } + + let len = strlen(s); + from_raw_parts(s, len) +} diff --git a/src/lib.rs b/src/lib.rs index c627313..4a0e8c7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,17 +1,17 @@ -mod addin1; -mod addin2; +pub mod add_in; mod ffi; +mod myaddin; use std::{ ffi::{c_int, c_long, c_void}, sync::atomic::{AtomicI32, Ordering}, }; -use addin1::Addin1; use ffi::{destroy_component, AttachType}; +use myaddin::MyAddIn; use utf16_lit::utf16_null; -use crate::{addin2::Addin2, ffi::create_component}; +use crate::ffi::create_component; pub static mut PLATFORM_CAPABILITIES: AtomicI32 = AtomicI32::new(-1); @@ -20,11 +20,7 @@ pub static mut PLATFORM_CAPABILITIES: AtomicI32 = AtomicI32::new(-1); pub unsafe extern "C" fn GetClassObject(name: *const u16, component: *mut *mut c_void) -> c_long { match *name as u8 { b'1' => { - let addin = Addin1::new(); - create_component(component, addin) - } - b'2' => { - let addin = Addin2::new(); + let addin = MyAddIn::new(); create_component(component, addin) } _ => 0, @@ -41,7 +37,7 @@ pub unsafe extern "C" fn DestroyObject(component: *mut *mut c_void) -> c_long { #[no_mangle] pub extern "C" fn GetClassNames() -> *const u16 { // small strings for performance - utf16_null!("1|2").as_ptr() + utf16_null!("1").as_ptr() } #[allow(non_snake_case)] diff --git a/src/addin1.rs b/src/myaddin.rs similarity index 87% rename from src/addin1.rs rename to src/myaddin.rs index 260e902..343dc1b 100644 --- a/src/addin1.rs +++ b/src/myaddin.rs @@ -1,4 +1,10 @@ -use crate::ffi::{Addin, Connection, ParamValue, ReturnValue, Tm}; +use crate::{ + add_in::AddIn, + ffi::{ + connection::Connection, + types::{ParamValue, ReturnValue, Tm}, + }, +}; use utf16_lit::utf16_null; const PROPS: &[&[u16]] = &[ @@ -11,9 +17,9 @@ const PROPS: &[&[u16]] = &[ &utf16_null!("PropBlob"), ]; -const METHODS: &[&[u16]] = &[&utf16_null!("Method1")]; +const METHODS: &[&[u16]] = &[&utf16_null!("Method1"), &utf16_null!("ExtEvent")]; -pub struct Addin1 { +pub struct MyAddIn { test: i32, prop_i32: i32, prop_f64: f64, @@ -21,11 +27,12 @@ pub struct Addin1 { prop_date: Tm, prop_str: String, prop_blob: Vec, + connection: Option<&'static Connection>, } -impl Addin1 { - pub fn new() -> Addin1 { - Addin1 { +impl MyAddIn { + pub fn new() -> MyAddIn { + MyAddIn { test: 11111, prop_i32: 22222, prop_f64: 333.33, @@ -33,16 +40,18 @@ impl Addin1 { prop_date: Tm::default(), prop_str: String::from("00000"), prop_blob: Vec::new(), + connection: None, } } } -impl Drop for Addin1 { +impl Drop for MyAddIn { fn drop(&mut self) {} } -impl Addin for Addin1 { +impl AddIn for MyAddIn { fn init(&mut self, _interface: &'static Connection) -> bool { + self.connection = Some(_interface); true } @@ -171,6 +180,7 @@ impl Addin for Addin1 { fn get_n_params(&mut self, num: usize) -> usize { match num { 0 => 3, + 1 => 0, _ => 0, } } @@ -187,6 +197,7 @@ impl Addin for Addin1 { fn has_ret_val(&mut self, num: usize) -> bool { match num { 0 => true, + 1 => true, _ => false, } } @@ -208,6 +219,13 @@ impl Addin for Addin1 { ret_value.set_str(buf.as_slice()); true } + 1 => { + let Some(con) = self.connection else { return false }; + let res = con.external_event("asd", "asd", "asd"); + + ret_value.set_bool(res); + true + } _ => false, } }