mirror of
https://github.com/medigor/example-native-api-rs.git
synced 2024-11-21 17:56:37 +02:00
add simple example
This commit is contained in:
parent
7d8b2f500d
commit
d74087af76
12
Cargo.toml
12
Cargo.toml
@ -7,12 +7,12 @@ edition = "2021"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[profile.release]
|
||||
opt-level = "z" # Optimize for size.
|
||||
lto = true # Enable Link Time Optimization
|
||||
codegen-units = 1 # Reduce number of codegen units to increase optimizations.
|
||||
panic = "abort" # Abort on panic
|
||||
strip = true # Automatically strip symbols from the binary.
|
||||
# opt-level = "z" # Optimize for size.
|
||||
lto = true # Enable Link Time Optimization
|
||||
codegen-units = 1 # Reduce number of codegen units to increase optimizations.
|
||||
panic = "abort" # Abort on panic
|
||||
strip = true # Automatically strip symbols from the binary.
|
||||
|
||||
[dependencies]
|
||||
utf16_lit="2.0"
|
||||
utf16_lit = "2.0"
|
||||
smallvec = "1.11"
|
||||
|
@ -23,6 +23,9 @@
|
||||
* [src/lib.rs](src/lib.rs) - корень крейта, здесь располагаются экспортные функции GetClassNames и др.
|
||||
* [src/ffi.rs](src/ffi.rs) - в этом модуле всё что связано с взаимодействием, также здесь находится весь небезопасный код.
|
||||
* [src/addin1.rs](src/addin1.rs) - здесь непосредственно реализация компоненты, причем весь код безопасный.
|
||||
* [src/addin2.rs](src/addin2.rs) - упрощенный вариант, используется другой трейт.
|
||||
* [src/easy.rs](src/easy.rs) - трейт Addin для упрощенного варианта.
|
||||
* [src/macros.rs](src/macros.rs) - содержит единственный макрос `name!` для удобного задания имен свойств, методов, классов.
|
||||
* [conf1c](conf1c) - конфигурация 1С (выгрузка из конфигуратора 8.3.22), минимальный тестовый код.
|
||||
|
||||
## Разработка
|
||||
@ -55,10 +58,10 @@
|
||||
"env": {"DISPLAY": ":1"}
|
||||
```
|
||||
Для разработки и тестирования также подходит [Учебная версия 1С](https://online.1c.ru/catalog/free/learning.php), но версия для windows только x32.
|
||||
При разработке использовался rust 1.66.
|
||||
При разработке использовался rust последней стабильной версии.
|
||||
|
||||
## Поддержка платформ
|
||||
У меня в проде не используется, используйте на свой страх и риск!
|
||||
У меня в проде не используется, но в тестах использовал, поблем не замечено, также производные разработки тоже успешно используются.
|
||||
- Windows x64 - тестировал, работает и gnu и msvc.
|
||||
- Windows x32 - тестировал, работает и gnu и msvc.
|
||||
- Linux x64 - тестировал, работает.
|
||||
|
@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ConfigDumpInfo xmlns="http://v8.1c.ru/8.3/xcf/dumpinfo" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" format="Hierarchical" version="2.15">
|
||||
<ConfigVersions>
|
||||
<Metadata name="Configuration.Конфигурация" id="72b21170-d6cc-48ee-8426-d69353f61fd5" configVersion="c712ec3fc94b2b4182496f0827cf4bff00000000"/>
|
||||
<Metadata name="Configuration.Конфигурация.HomePageWorkArea" id="29e7f5a4-dc26-408a-bd6e-083b5bf1384c.8" configVersion="33c420fc5cc12348954bd259bb0c136000000000"/>
|
||||
<Metadata name="DataProcessor.Обработка1" id="33179d0b-730e-44f5-b20c-1af11f7f1f60" configVersion="86cf80c3e753094aa1ab6bbb3cce13b400000000"/>
|
||||
<Metadata name="DataProcessor.Обработка1.Form.Форма" id="24033a67-5ef1-4265-9a88-eb7f279ce1cb" configVersion="b49039a0c3894b41a732cee38bfae78d00000000"/>
|
||||
<Metadata name="DataProcessor.Обработка1.Form.Форма.Form" id="24033a67-5ef1-4265-9a88-eb7f279ce1cb.0" configVersion="4773009ef4f1164eadd05bc75928d86900000000"/>
|
||||
<Metadata name="Language.Русский" id="e3ac9659-5250-4530-9ca6-3f4f4ef6413a" configVersion="63a64f60c307414fabfabd0d777a47cc00000000"/>
|
||||
<Metadata name="Configuration.Конфигурация" id="72b21170-d6cc-48ee-8426-d69353f61fd5" configVersion="7bb3aedfabf3f347b0d90a1723e8f3c800000000"/>
|
||||
<Metadata name="Configuration.Конфигурация.HomePageWorkArea" id="29e7f5a4-dc26-408a-bd6e-083b5bf1384c.8" configVersion="e07ffb9930bcfd419cc94bfed56fc39700000000"/>
|
||||
<Metadata name="DataProcessor.Обработка1" id="33179d0b-730e-44f5-b20c-1af11f7f1f60" configVersion="3864a8102742ba46ac0ed9ae8552c89d00000000"/>
|
||||
<Metadata name="DataProcessor.Обработка1.Form.Форма" id="24033a67-5ef1-4265-9a88-eb7f279ce1cb" configVersion="26d36b8115680a42a52b99d8b011342e00000000"/>
|
||||
<Metadata name="DataProcessor.Обработка1.Form.Форма.Form" id="24033a67-5ef1-4265-9a88-eb7f279ce1cb.0" configVersion="368ad81321aa084d82a53c976986a94100000000"/>
|
||||
<Metadata name="Language.Русский" id="e3ac9659-5250-4530-9ca6-3f4f4ef6413a" configVersion="9b1ab00d6dd15a48b70a736c7e6be41900000000"/>
|
||||
</ConfigVersions>
|
||||
</ConfigDumpInfo>
|
@ -21,6 +21,16 @@
|
||||
<CommandName>Form.Command.Тест2</CommandName>
|
||||
<ExtendedTooltip name="Тест2РасширеннаяПодсказка" id="4"/>
|
||||
</Button>
|
||||
<Button name="Тест3" id="24">
|
||||
<Type>UsualButton</Type>
|
||||
<CommandName>Form.Command.Тест3</CommandName>
|
||||
<ExtendedTooltip name="Тест3РасширеннаяПодсказка" id="25"/>
|
||||
</Button>
|
||||
<Button name="Тест4" id="26">
|
||||
<Type>UsualButton</Type>
|
||||
<CommandName>Form.Command.Тест4</CommandName>
|
||||
<ExtendedTooltip name="Тест4РасширеннаяПодсказка" id="27"/>
|
||||
</Button>
|
||||
</ChildItems>
|
||||
<Attributes>
|
||||
<Attribute name="Объект" id="1">
|
||||
@ -79,5 +89,35 @@
|
||||
</ToolTip>
|
||||
<Action>Тест1</Action>
|
||||
</Command>
|
||||
<Command name="Тест3" id="3">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Тест3</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<ToolTip>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Тест3</v8:content>
|
||||
</v8:item>
|
||||
</ToolTip>
|
||||
<Action>Тест3</Action>
|
||||
</Command>
|
||||
<Command name="Тест4" id="4">
|
||||
<Title>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Тест4</v8:content>
|
||||
</v8:item>
|
||||
</Title>
|
||||
<ToolTip>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Тест4</v8:content>
|
||||
</v8:item>
|
||||
</ToolTip>
|
||||
<Action>Тест4</Action>
|
||||
</Command>
|
||||
</Commands>
|
||||
</Form>
|
@ -91,3 +91,61 @@
|
||||
Сообщить(СтрШаблон("Длительность: %1", Конец - Начало));
|
||||
|
||||
КонецПроцедуры
|
||||
|
||||
&НаКлиенте
|
||||
Процедура Тест3(Команда)
|
||||
Тест3НаСервере(ИмяФайла);
|
||||
КонецПроцедуры
|
||||
|
||||
&НаСервереБезКонтекста
|
||||
Процедура Тест3НаСервере(ИмяФайла)
|
||||
|
||||
Попытка
|
||||
ОбъектКомпоненты2 = Новый ("AddIn.Test.Class2");
|
||||
Исключение
|
||||
Если Не ПодключитьВнешнююКомпоненту(ИмяФайла, "Test", ТипВнешнейКомпоненты.Native, ТипПодключенияВнешнейКомпоненты.НеИзолированно) Тогда
|
||||
ВызватьИсключение "Не удалось подключить";
|
||||
КонецЕсли;
|
||||
ОбъектКомпоненты2 = Новый ("AddIn.Test.Class2");
|
||||
КонецПопытки;
|
||||
|
||||
Если ОбъектКомпоненты2.Method1(111) <> 222 Тогда
|
||||
ВызватьИсключение "Не удалось вызвать Method1";
|
||||
КонецЕсли;
|
||||
|
||||
Если ОбъектКомпоненты2.Method2(111, 222) <> 333 Тогда
|
||||
ВызватьИсключение "Не удалось вызвать Method2";
|
||||
КонецЕсли;
|
||||
|
||||
Если ОбъектКомпоненты2.Prop1 <> 333 Тогда
|
||||
ВызватьИсключение "Свойство Prop1 содержит неверное значение";
|
||||
КонецЕсли;
|
||||
Сообщить("Тест выполнен успешно");
|
||||
|
||||
КонецПроцедуры
|
||||
|
||||
&НаКлиенте
|
||||
Процедура Тест4(Команда)
|
||||
Тест4НаСервере(ИмяФайла);
|
||||
КонецПроцедуры
|
||||
|
||||
&НаСервереБезКонтекста
|
||||
Процедура Тест4НаСервере(ИмяФайла)
|
||||
|
||||
Попытка
|
||||
ОбъектКомпоненты2 = Новый ("AddIn.Test.Class2");
|
||||
Исключение
|
||||
Если Не ПодключитьВнешнююКомпоненту(ИмяФайла, "Test", ТипВнешнейКомпоненты.Native, ТипПодключенияВнешнейКомпоненты.НеИзолированно) Тогда
|
||||
ВызватьИсключение "Не удалось подключить";
|
||||
КонецЕсли;
|
||||
ОбъектКомпоненты2 = Новый ("AddIn.Test.Class2");
|
||||
КонецПопытки;
|
||||
|
||||
Начало = ТекущаяУниверсальнаяДатаВМиллисекундах();
|
||||
Для К = 1 По 1000000 Цикл
|
||||
ОбъектКомпоненты2.Prop1 = 123;
|
||||
КонецЦикла;
|
||||
Конец = ТекущаяУниверсальнаяДатаВМиллисекундах();
|
||||
Сообщить(СтрШаблон("Длительность: %1 мс", Конец - Начало));
|
||||
|
||||
КонецПроцедуры
|
||||
|
@ -1,17 +1,21 @@
|
||||
use crate::ffi::{Addin, Connection, ParamValue, Tm, Variant};
|
||||
use utf16_lit::{utf16, utf16_null};
|
||||
use utf16_lit::utf16;
|
||||
|
||||
use crate::{
|
||||
ffi::{Addin, ParamValue, Tm, Variant},
|
||||
name,
|
||||
};
|
||||
|
||||
const PROPS: &[&[u16]] = &[
|
||||
&utf16_null!("Test"),
|
||||
&utf16_null!("PropI32"),
|
||||
&utf16_null!("PropF64"),
|
||||
&utf16_null!("PropBool"),
|
||||
&utf16_null!("PropDate"),
|
||||
&utf16_null!("PropStr"),
|
||||
&utf16_null!("PropBlob"),
|
||||
name!("Test"),
|
||||
name!("PropI32"),
|
||||
name!("PropF64"),
|
||||
name!("PropBool"),
|
||||
name!("PropDate"),
|
||||
name!("PropStr"),
|
||||
name!("PropBlob"),
|
||||
];
|
||||
|
||||
const METHODS: &[&[u16]] = &[&utf16_null!("Method1"), &utf16_null!("Method2")];
|
||||
const METHODS: &[&[u16]] = &[name!("Method1"), name!("Method2")];
|
||||
|
||||
pub struct Addin1 {
|
||||
test: i32,
|
||||
@ -42,14 +46,8 @@ impl Drop for Addin1 {
|
||||
}
|
||||
|
||||
impl Addin for Addin1 {
|
||||
fn init(&mut self, _interface: &'static Connection) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn done(&mut self) {}
|
||||
|
||||
fn register_extension_as(&mut self) -> &'static [u16] {
|
||||
&utf16_null!("Class1")
|
||||
name!("Class1")
|
||||
}
|
||||
|
||||
fn get_n_props(&mut self) -> usize {
|
||||
@ -235,8 +233,4 @@ impl Addin for Addin1 {
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn set_locale(&mut self, _loc: &[u16]) {}
|
||||
|
||||
fn set_user_interface_language_code(&mut self, _lang: &[u16]) {}
|
||||
}
|
||||
|
162
src/addin2.rs
162
src/addin2.rs
@ -1,116 +1,80 @@
|
||||
use crate::ffi::{Addin, Connection, ParamValue, Variant};
|
||||
use utf16_lit::utf16_null;
|
||||
use crate::{
|
||||
simple::{Addin, MethodInfo, Methods, PropInfo},
|
||||
ffi::{ParamValue, Variant}, name,
|
||||
};
|
||||
|
||||
pub struct Addin2 {
|
||||
test1: i32,
|
||||
prop1: i32,
|
||||
}
|
||||
|
||||
impl Addin2 {
|
||||
pub fn new() -> Addin2 {
|
||||
Addin2 { test1: 12345 }
|
||||
Addin2 { prop1: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Addin2 {
|
||||
fn drop(&mut self) {}
|
||||
fn method1(&mut self, param: &mut Variant, ret_value: &mut Variant) -> bool {
|
||||
let ParamValue::I32(value) = param.get() else {
|
||||
return false;
|
||||
};
|
||||
self.prop1 = value;
|
||||
ret_value.set_i32(value * 2);
|
||||
true
|
||||
}
|
||||
|
||||
fn method2(
|
||||
&mut self,
|
||||
param1: &mut Variant,
|
||||
param2: &mut Variant,
|
||||
ret_value: &mut Variant,
|
||||
) -> bool {
|
||||
let ParamValue::I32(value1) = param1.get() else {
|
||||
return false;
|
||||
};
|
||||
let ParamValue::I32(value2) = param2.get() else {
|
||||
return false;
|
||||
};
|
||||
self.prop1 = value1 + value2;
|
||||
ret_value.set_i32(self.prop1);
|
||||
true
|
||||
}
|
||||
|
||||
fn set_prop1(&mut self, value: &ParamValue) -> bool {
|
||||
let ParamValue::I32(value) = value else {
|
||||
return false;
|
||||
};
|
||||
self.prop1 = *value;
|
||||
true
|
||||
}
|
||||
|
||||
fn get_prop1(&mut self, value: &mut Variant) -> bool {
|
||||
value.set_i32(self.prop1);
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl Addin for Addin2 {
|
||||
fn init(&mut self, _interface: &'static Connection) -> bool {
|
||||
true
|
||||
fn name() -> &'static [u16] {
|
||||
name!("Class2")
|
||||
}
|
||||
|
||||
fn done(&mut self) {}
|
||||
|
||||
fn register_extension_as(&mut self) -> &'static [u16] {
|
||||
&utf16_null!("Class2")
|
||||
fn methods() -> &'static [MethodInfo<Self>] {
|
||||
&[
|
||||
MethodInfo {
|
||||
name: name!("Method1"),
|
||||
method: Methods::Method1(Self::method1),
|
||||
},
|
||||
MethodInfo {
|
||||
name: name!("Method2"),
|
||||
method: Methods::Method2(Self::method2),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn get_n_props(&mut self) -> usize {
|
||||
1
|
||||
fn properties() -> &'static [PropInfo<Self>] {
|
||||
&[PropInfo {
|
||||
name: name!("Prop1"),
|
||||
getter: Some(Self::get_prop1),
|
||||
setter: Some(Self::set_prop1),
|
||||
}]
|
||||
}
|
||||
|
||||
fn find_prop(&mut self, name: &[u16]) -> Option<usize> {
|
||||
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: &mut Variant) -> 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<usize> {
|
||||
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: Variant,
|
||||
) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn has_ret_val(&mut self, _method_num: usize) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn call_as_proc(&mut self, _method_num: usize, _params: &mut [Variant]) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn call_as_func(
|
||||
&mut self,
|
||||
_method_num: usize,
|
||||
_params: &mut [Variant],
|
||||
_val: &mut Variant,
|
||||
) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn set_locale(&mut self, _loc: &[u16]) {}
|
||||
|
||||
fn set_user_interface_language_code(&mut self, _lang: &[u16]) {}
|
||||
}
|
||||
|
71
src/ffi.rs
71
src/ffi.rs
@ -236,37 +236,70 @@ struct TVariant {
|
||||
vt: VariantType,
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
pub trait Addin {
|
||||
fn init(&mut self, interface: &'static Connection) -> bool;
|
||||
fn init(&mut self, interface: &'static Connection) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// default 2000, don't use version 1000, because static objects are created
|
||||
fn get_info(&mut self) -> u16 {
|
||||
2000
|
||||
}
|
||||
fn done(&mut self);
|
||||
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<usize>;
|
||||
fn get_prop_name(&mut self, num: usize, alias: usize) -> Option<&'static [u16]>;
|
||||
fn get_prop_val(&mut self, num: usize, val: &mut Variant) -> 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<usize>;
|
||||
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: Variant) -> bool;
|
||||
fn has_ret_val(&mut self, method_num: usize) -> bool;
|
||||
fn call_as_proc(&mut self, method_num: usize, params: &mut [Variant]) -> bool;
|
||||
fn get_n_props(&mut self) -> usize {
|
||||
0
|
||||
}
|
||||
fn find_prop(&mut self, name: &[u16]) -> Option<usize> {
|
||||
None
|
||||
}
|
||||
fn get_prop_name(&mut self, num: usize, alias: usize) -> Option<&'static [u16]> {
|
||||
None
|
||||
}
|
||||
fn get_prop_val(&mut self, num: usize, val: &mut Variant) -> bool {
|
||||
false
|
||||
}
|
||||
fn set_prop_val(&mut self, num: usize, val: &ParamValue) -> bool {
|
||||
false
|
||||
}
|
||||
fn is_prop_readable(&mut self, num: usize) -> bool {
|
||||
false
|
||||
}
|
||||
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<usize> {
|
||||
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: Variant) -> bool {
|
||||
true
|
||||
}
|
||||
fn has_ret_val(&mut self, method_num: usize) -> bool {
|
||||
false
|
||||
}
|
||||
fn call_as_proc(&mut self, method_num: usize, params: &mut [Variant]) -> bool {
|
||||
false
|
||||
}
|
||||
fn call_as_func(
|
||||
&mut self,
|
||||
method_num: usize,
|
||||
params: &mut [Variant],
|
||||
val: &mut Variant,
|
||||
) -> bool;
|
||||
fn set_locale(&mut self, loc: &[u16]);
|
||||
fn set_user_interface_language_code(&mut self, lang: &[u16]);
|
||||
) -> bool {
|
||||
false
|
||||
}
|
||||
fn set_locale(&mut self, loc: &[u16]) {}
|
||||
fn set_user_interface_language_code(&mut self, lang: &[u16]) {}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
@ -1,6 +1,8 @@
|
||||
mod addin1;
|
||||
mod addin2;
|
||||
mod simple;
|
||||
mod ffi;
|
||||
mod macros;
|
||||
|
||||
use std::{
|
||||
ffi::{c_int, c_long, c_void},
|
||||
@ -8,11 +10,10 @@ use std::{
|
||||
};
|
||||
|
||||
use addin1::Addin1;
|
||||
use ffi::{destroy_component, AttachType};
|
||||
use addin2::Addin2;
|
||||
use ffi::{create_component, destroy_component, AttachType};
|
||||
use utf16_lit::utf16_null;
|
||||
|
||||
use crate::{addin2::Addin2, ffi::create_component};
|
||||
|
||||
pub static mut PLATFORM_CAPABILITIES: AtomicI32 = AtomicI32::new(-1);
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
|
7
src/macros.rs
Normal file
7
src/macros.rs
Normal file
@ -0,0 +1,7 @@
|
||||
/// Null terminated utf-16 static string, used for names
|
||||
#[macro_export]
|
||||
macro_rules! name {
|
||||
($text:expr) => {
|
||||
&utf16_lit::utf16_null!($text)
|
||||
};
|
||||
}
|
306
src/simple.rs
Normal file
306
src/simple.rs
Normal file
@ -0,0 +1,306 @@
|
||||
use crate::ffi::{self, ParamValue, Variant};
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub enum Methods<T> {
|
||||
Method0(fn(&mut T, &mut Variant) -> bool),
|
||||
Method1(fn(&mut T, &mut Variant, &mut Variant) -> bool),
|
||||
Method2(fn(&mut T, &mut Variant, &mut Variant, &mut Variant) -> bool),
|
||||
Method3(fn(&mut T, &mut Variant, &mut Variant, &mut Variant, &mut Variant) -> bool),
|
||||
Method4(
|
||||
fn(&mut T, &mut Variant, &mut Variant, &mut Variant, &mut Variant, &mut Variant) -> bool,
|
||||
),
|
||||
Method5(
|
||||
fn(
|
||||
&mut T,
|
||||
&mut Variant,
|
||||
&mut Variant,
|
||||
&mut Variant,
|
||||
&mut Variant,
|
||||
&mut Variant,
|
||||
&mut Variant,
|
||||
) -> bool,
|
||||
),
|
||||
Method6(
|
||||
fn(
|
||||
&mut T,
|
||||
&mut Variant,
|
||||
&mut Variant,
|
||||
&mut Variant,
|
||||
&mut Variant,
|
||||
&mut Variant,
|
||||
&mut Variant,
|
||||
&mut Variant,
|
||||
) -> bool,
|
||||
),
|
||||
Method7(
|
||||
fn(
|
||||
&mut T,
|
||||
&mut Variant,
|
||||
&mut Variant,
|
||||
&mut Variant,
|
||||
&mut Variant,
|
||||
&mut Variant,
|
||||
&mut Variant,
|
||||
&mut Variant,
|
||||
&mut Variant,
|
||||
) -> bool,
|
||||
),
|
||||
}
|
||||
|
||||
impl<T> Methods<T> {
|
||||
fn params(&self) -> usize {
|
||||
match self {
|
||||
Methods::Method0(_) => 0,
|
||||
Methods::Method1(_) => 1,
|
||||
Methods::Method2(_) => 2,
|
||||
Methods::Method3(_) => 3,
|
||||
Methods::Method4(_) => 4,
|
||||
Methods::Method5(_) => 5,
|
||||
Methods::Method6(_) => 6,
|
||||
Methods::Method7(_) => 7,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn call(&self, addin: &mut T, params: &mut [Variant], val: &mut Variant) -> bool {
|
||||
match self {
|
||||
Methods::Method0(f) => f(addin, val),
|
||||
Methods::Method1(f) => {
|
||||
let Some((p1, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
f(addin, p1, val)
|
||||
}
|
||||
Methods::Method2(f) => {
|
||||
let Some((p1, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
let Some((p2, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
f(addin, p1, p2, val)
|
||||
}
|
||||
Methods::Method3(f) => {
|
||||
let Some((p1, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
let Some((p2, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
let Some((p3, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
f(addin, p1, p2, p3, val)
|
||||
}
|
||||
Methods::Method4(f) => {
|
||||
let Some((p1, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
let Some((p2, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
let Some((p3, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
let Some((p4, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
f(addin, p1, p2, p3, p4, val)
|
||||
}
|
||||
|
||||
Methods::Method5(f) => {
|
||||
let Some((p1, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
let Some((p2, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
let Some((p3, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
let Some((p4, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
let Some((p5, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
f(addin, p1, p2, p3, p4, p5, val)
|
||||
}
|
||||
|
||||
Methods::Method6(f) => {
|
||||
let Some((p1, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
let Some((p2, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
let Some((p3, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
let Some((p4, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
let Some((p5, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
let Some((p6, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
f(addin, p1, p2, p3, p4, p5, p6, val)
|
||||
}
|
||||
|
||||
Methods::Method7(f) => {
|
||||
let Some((p1, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
let Some((p2, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
let Some((p3, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
let Some((p4, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
let Some((p5, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
let Some((p6, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
let Some((p7, params)) = params.split_first_mut() else {
|
||||
return false;
|
||||
};
|
||||
f(addin, p1, p2, p3, p4, p5, p6, p7, val)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MethodInfo<T> {
|
||||
pub name: &'static [u16],
|
||||
pub method: Methods<T>,
|
||||
}
|
||||
|
||||
pub struct PropInfo<T> {
|
||||
pub name: &'static [u16],
|
||||
pub getter: Option<fn(&mut T, &mut Variant) -> bool>,
|
||||
pub setter: Option<fn(&mut T, &ParamValue) -> bool>,
|
||||
}
|
||||
|
||||
pub trait Addin {
|
||||
fn name() -> &'static [u16];
|
||||
|
||||
fn get_info() -> u16 {
|
||||
2000
|
||||
}
|
||||
|
||||
fn methods() -> &'static [MethodInfo<Self>]
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
&[]
|
||||
}
|
||||
|
||||
fn properties() -> &'static [PropInfo<Self>]
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
&[]
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
impl<T: Addin + 'static> ffi::Addin for T {
|
||||
fn register_extension_as(&mut self) -> &'static [u16] {
|
||||
T::name()
|
||||
}
|
||||
|
||||
fn get_info(&mut self) -> u16 {
|
||||
T::get_info()
|
||||
}
|
||||
|
||||
fn get_n_props(&mut self) -> usize {
|
||||
T::properties().len()
|
||||
}
|
||||
|
||||
fn find_prop(&mut self, name: &[u16]) -> Option<usize> {
|
||||
T::properties().iter().position(|x| x.name == name)
|
||||
}
|
||||
|
||||
fn get_prop_name(&mut self, num: usize, alias: usize) -> Option<&'static [u16]> {
|
||||
T::properties().get(num).map(|x| &x.name).copied()
|
||||
}
|
||||
|
||||
fn get_prop_val(&mut self, num: usize, val: &mut Variant) -> bool {
|
||||
let Some(property) = T::properties().get(num) else {
|
||||
return false;
|
||||
};
|
||||
let Some(getter) = property.getter else {
|
||||
return false;
|
||||
};
|
||||
getter(self, val)
|
||||
}
|
||||
|
||||
fn set_prop_val(&mut self, num: usize, val: &ParamValue) -> bool {
|
||||
let Some(property) = T::properties().get(num) else {
|
||||
return false;
|
||||
};
|
||||
let Some(setter) = property.setter else {
|
||||
return false;
|
||||
};
|
||||
setter(self, val)
|
||||
}
|
||||
|
||||
fn is_prop_readable(&mut self, num: usize) -> bool {
|
||||
T::properties()[num].getter.is_some()
|
||||
}
|
||||
|
||||
fn is_prop_writable(&mut self, num: usize) -> bool {
|
||||
T::properties()[num].setter.is_some()
|
||||
}
|
||||
|
||||
fn get_n_methods(&mut self) -> usize {
|
||||
T::methods().len()
|
||||
}
|
||||
|
||||
fn find_method(&mut self, name: &[u16]) -> Option<usize> {
|
||||
T::methods().iter().position(|x| x.name == name)
|
||||
}
|
||||
|
||||
fn get_method_name(&mut self, num: usize, alias: usize) -> Option<&'static [u16]> {
|
||||
T::methods().get(num).map(|x| &x.name).copied()
|
||||
}
|
||||
|
||||
fn get_n_params(&mut self, num: usize) -> usize {
|
||||
let Some(info) = T::methods().get(num) else {
|
||||
return 0;
|
||||
};
|
||||
info.method.params()
|
||||
}
|
||||
|
||||
fn get_param_def_value(&mut self, method_num: usize, param_num: usize, value: Variant) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn has_ret_val(&mut self, method_num: usize) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn call_as_proc(&mut self, method_num: usize, params: &mut [Variant]) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn call_as_func(
|
||||
&mut self,
|
||||
method_num: usize,
|
||||
params: &mut [Variant],
|
||||
val: &mut Variant,
|
||||
) -> bool {
|
||||
let Some(info) = T::methods().get(method_num) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
info.method.call(self, params, val)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user