diff --git a/src/addin1.rs b/src/addin1.rs index fb78915..b7ce016 100644 --- a/src/addin1.rs +++ b/src/addin1.rs @@ -14,6 +14,7 @@ const PROPS: &[&[u16]] = &[ const METHODS: &[&[u16]] = &[&utf16_null!("Method1")]; pub struct Addin1 { + test: i32, prop_i32: i32, prop_f64: f64, prop_bool: bool, @@ -25,6 +26,7 @@ pub struct Addin1 { impl Addin1 { pub fn new() -> Addin1 { Addin1 { + test: 12345, prop_i32: 0, prop_f64: 0.0, prop_bool: false, @@ -44,10 +46,6 @@ impl Addin for Addin1 { true } - fn get_info(&mut self) -> u16 { - 1000 - } - fn done(&mut self) {} fn register_extension_as(&mut self) -> &'static [u16] { @@ -68,7 +66,7 @@ impl Addin for Addin1 { fn get_prop_val(&mut self, num: usize, val: ReturnValue) -> bool { match num { - 0 => val.set_i32(111226), + 0 => val.set_i32(self.test), 1 => val.set_i32(self.prop_i32), 2 => val.set_f64(self.prop_f64), 3 => val.set_bool(self.prop_bool), @@ -87,6 +85,13 @@ impl Addin for Addin1 { fn set_prop_val(&mut self, num: usize, val: &ParamValue) -> bool { match num { + 0 => match val { + ParamValue::I32(x) => { + self.test = *x; + true + } + _ => false, + }, 1 => match val { ParamValue::I32(x) => { self.prop_i32 = *x; @@ -140,7 +145,7 @@ impl Addin for Addin1 { fn is_prop_writable(&mut self, num: usize) -> bool { match num { - 0 => false, + 0 => true, 1 => true, 2 => true, 3 => true, diff --git a/src/addin2.rs b/src/addin2.rs new file mode 100644 index 0000000..d8a81cc --- /dev/null +++ b/src/addin2.rs @@ -0,0 +1,121 @@ +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 index 9f09169..4d6ede7 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -219,7 +219,11 @@ struct TVariant { pub trait Addin { fn init(&mut self, interface: &'static Connection) -> bool; - fn get_info(&mut self) -> u16; + + /// 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; @@ -354,8 +358,7 @@ unsafe extern "system" fn find_prop( component: &mut LanguageExtenderBase, name: *const u16, ) -> c_long { - let len = strlen(name); - let name = from_raw_parts(name, len); + let name = get_str(name); match component.addin.find_prop(name) { Some(i) => i as c_long, None => -1, @@ -432,8 +435,7 @@ unsafe extern "system" fn find_method( component: &mut LanguageExtenderBase, name: *const u16, ) -> c_long { - let len = strlen(name); - let name = from_raw_parts(name, len); + let name = get_str(name); match component.addin.find_method(name) { Some(i) => i as c_long, None => -1, @@ -551,8 +553,7 @@ struct LocaleBaseVTable { } unsafe extern "system" fn set_locale(component: &mut LocaleBase, loc: *const u16) { - let len = strlen(loc); - let loc = from_raw_parts(loc, len); + let loc = get_str(loc); component.addin.set_locale(loc) } @@ -570,8 +571,7 @@ unsafe extern "system" fn set_user_interface_language_code( component: &mut UserLanguageBase, lang: *const u16, ) { - let len = strlen(lang); - let lang = from_raw_parts(lang, len); + let lang = get_str(lang); component.addin.set_user_interface_language_code(lang) } @@ -588,30 +588,27 @@ struct ComponentBase { } unsafe extern "system" fn destroy(component: *mut *mut ComponentBase) { - let component = unsafe { Box::from_raw(*component) }; - drop(component); + let comp = Box::from_raw(*component); + drop(comp); } #[repr(C)] -#[allow(dead_code)] struct InitDoneBase { - _vptr1: Box>, - _vptr2: Box>, - _vptr3: Box>, - _vptr4: Box>, + _vptr1: usize, + _vptr2: usize, + _vptr3: usize, + _vptr4: usize, destroy: unsafe extern "system" fn(*mut *mut ComponentBase), memory: Option<&'static MemoryManager>, addin: T, } -// type InitDoneBase = ComponentBase; - #[repr(C)] #[allow(dead_code)] struct LanguageExtenderBase { - _vptr2: Box>, - _vptr3: Box>, - _vptr4: Box>, + _vptr2: usize, + _vptr3: usize, + _vptr4: usize, destroy: unsafe extern "system" fn(*mut *mut ComponentBase), memory: Option<&'static MemoryManager>, addin: T, @@ -620,8 +617,8 @@ struct LanguageExtenderBase { #[repr(C)] #[allow(dead_code)] struct LocaleBase { - _vptr3: Box>, - _vptr4: Box>, + _vptr3: usize, + _vptr4: usize, destroy: unsafe extern "system" fn(*mut *mut ComponentBase), memory: Option<&'static MemoryManager>, addin: T, @@ -630,13 +627,13 @@ struct LocaleBase { #[repr(C)] #[allow(dead_code)] struct UserLanguageBase { - _vptr4: Box>, + _vptr4: usize, destroy: unsafe extern "system" fn(*mut *mut ComponentBase), memory: Option<&'static MemoryManager>, addin: T, } -pub fn create_component(addin: T) -> *mut c_void { +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")] @@ -693,26 +690,26 @@ pub fn create_component(addin: T) -> *mut c_void { addin, }); - let p = Box::leak(c); - p as *mut ComponentBase as *mut c_void + *component = Box::into_raw(c) as *mut c_void; + 1 } -pub fn destroy_component(component: *mut *mut c_void) { +pub unsafe fn destroy_component(component: *mut *mut c_void) -> c_long { #[repr(C)] - #[allow(dead_code)] struct ComponentWrapper { - vptr1: Box, - vptr2: Box, - vptr3: Box, - vptr4: Box, + vptr1: usize, + vptr2: usize, + vptr3: usize, + vptr4: usize, destroy: unsafe extern "system" fn(*mut *mut c_void), } - unsafe { - let wrapper = *component as *mut ComponentWrapper; - let wrapper = &mut *wrapper; - (wrapper.destroy)(component); - } + let wrapper = *component as *mut ComponentWrapper; + let wrapper = &mut *wrapper; + (wrapper.destroy)(component); + *component = ptr::null_mut(); + + 0 } #[repr(C)] @@ -759,11 +756,16 @@ pub struct Connection { vptr1: &'static ConnectionVTable, } -fn strlen(s: *const u16) -> usize { - let mut i = 0; - while unsafe { *s.add(i) } != 0 { +unsafe fn get_str<'a>(s: *const u16) -> &'a [u16] { + unsafe fn strlen(s: *const u16) -> usize { + let mut i = 0; + while unsafe { *s.add(i) } != 0 { + i += 1; + } i += 1; + i } - i += 1; - i + + let len = strlen(s); + from_raw_parts(s, len) } diff --git a/src/lib.rs b/src/lib.rs index 8b8c4d3..9212661 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,9 @@ mod addin1; +mod addin2; mod ffi; use std::{ - ffi::{c_long, c_void, c_int}, + ffi::{c_int, c_long, c_void}, sync::atomic::{AtomicI32, Ordering}, }; @@ -10,36 +11,42 @@ use addin1::Addin1; use ffi::{destroy_component, AttachType}; use utf16_lit::utf16_null; -use crate::ffi::create_component; +use crate::{addin2::Addin2, ffi::create_component}; pub static mut PLATFORM_CAPABILITIES: AtomicI32 = AtomicI32::new(-1); #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn GetClassObject(_name: *const u16, component: *mut *mut c_void) -> c_long { - let addin = Addin1::new(); - unsafe { - *component = create_component(addin); +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(); + create_component(component, addin) + } + _ => 0, } - 1 } #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn DestroyObject(component: *mut *mut c_void) -> c_long { - destroy_component(component); - 0 +pub unsafe extern "C" fn DestroyObject(component: *mut *mut c_void) -> c_long { + destroy_component(component) } #[allow(non_snake_case)] #[no_mangle] pub extern "C" fn GetClassNames() -> *const u16 { - utf16_null!("Class1").as_ptr() + // small strings for performance + utf16_null!("1|2").as_ptr() } #[allow(non_snake_case)] #[no_mangle] -pub extern "C" fn SetPlatformCapabilities(capabilities: c_int) -> c_long { +pub extern "C" fn SetPlatformCapabilities(capabilities: c_int) -> c_int { unsafe { PLATFORM_CAPABILITIES.store(capabilities, Ordering::Relaxed); }