mirror of
https://github.com/medigor/example-native-api-rs.git
synced 2025-06-08 23:36:11 +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"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
opt-level = "z" # Optimize for size.
|
# opt-level = "z" # Optimize for size.
|
||||||
lto = true # Enable Link Time Optimization
|
lto = true # Enable Link Time Optimization
|
||||||
codegen-units = 1 # Reduce number of codegen units to increase optimizations.
|
codegen-units = 1 # Reduce number of codegen units to increase optimizations.
|
||||||
panic = "abort" # Abort on panic
|
panic = "abort" # Abort on panic
|
||||||
strip = true # Automatically strip symbols from the binary.
|
strip = true # Automatically strip symbols from the binary.
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
utf16_lit="2.0"
|
utf16_lit = "2.0"
|
||||||
smallvec = "1.11"
|
smallvec = "1.11"
|
||||||
|
@ -23,6 +23,9 @@
|
|||||||
* [src/lib.rs](src/lib.rs) - корень крейта, здесь располагаются экспортные функции GetClassNames и др.
|
* [src/lib.rs](src/lib.rs) - корень крейта, здесь располагаются экспортные функции GetClassNames и др.
|
||||||
* [src/ffi.rs](src/ffi.rs) - в этом модуле всё что связано с взаимодействием, также здесь находится весь небезопасный код.
|
* [src/ffi.rs](src/ffi.rs) - в этом модуле всё что связано с взаимодействием, также здесь находится весь небезопасный код.
|
||||||
* [src/addin1.rs](src/addin1.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), минимальный тестовый код.
|
* [conf1c](conf1c) - конфигурация 1С (выгрузка из конфигуратора 8.3.22), минимальный тестовый код.
|
||||||
|
|
||||||
## Разработка
|
## Разработка
|
||||||
@ -55,10 +58,10 @@
|
|||||||
"env": {"DISPLAY": ":1"}
|
"env": {"DISPLAY": ":1"}
|
||||||
```
|
```
|
||||||
Для разработки и тестирования также подходит [Учебная версия 1С](https://online.1c.ru/catalog/free/learning.php), но версия для windows только x32.
|
Для разработки и тестирования также подходит [Учебная версия 1С](https://online.1c.ru/catalog/free/learning.php), но версия для windows только x32.
|
||||||
При разработке использовался rust 1.66.
|
При разработке использовался rust последней стабильной версии.
|
||||||
|
|
||||||
## Поддержка платформ
|
## Поддержка платформ
|
||||||
У меня в проде не используется, используйте на свой страх и риск!
|
У меня в проде не используется, но в тестах использовал, поблем не замечено, также производные разработки тоже успешно используются.
|
||||||
- Windows x64 - тестировал, работает и gnu и msvc.
|
- Windows x64 - тестировал, работает и gnu и msvc.
|
||||||
- Windows x32 - тестировал, работает и gnu и msvc.
|
- Windows x32 - тестировал, работает и gnu и msvc.
|
||||||
- Linux x64 - тестировал, работает.
|
- Linux x64 - тестировал, работает.
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?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">
|
<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>
|
<ConfigVersions>
|
||||||
<Metadata name="Configuration.Конфигурация" id="72b21170-d6cc-48ee-8426-d69353f61fd5" configVersion="c712ec3fc94b2b4182496f0827cf4bff00000000"/>
|
<Metadata name="Configuration.Конфигурация" id="72b21170-d6cc-48ee-8426-d69353f61fd5" configVersion="7bb3aedfabf3f347b0d90a1723e8f3c800000000"/>
|
||||||
<Metadata name="Configuration.Конфигурация.HomePageWorkArea" id="29e7f5a4-dc26-408a-bd6e-083b5bf1384c.8" configVersion="33c420fc5cc12348954bd259bb0c136000000000"/>
|
<Metadata name="Configuration.Конфигурация.HomePageWorkArea" id="29e7f5a4-dc26-408a-bd6e-083b5bf1384c.8" configVersion="e07ffb9930bcfd419cc94bfed56fc39700000000"/>
|
||||||
<Metadata name="DataProcessor.Обработка1" id="33179d0b-730e-44f5-b20c-1af11f7f1f60" configVersion="86cf80c3e753094aa1ab6bbb3cce13b400000000"/>
|
<Metadata name="DataProcessor.Обработка1" id="33179d0b-730e-44f5-b20c-1af11f7f1f60" configVersion="3864a8102742ba46ac0ed9ae8552c89d00000000"/>
|
||||||
<Metadata name="DataProcessor.Обработка1.Form.Форма" id="24033a67-5ef1-4265-9a88-eb7f279ce1cb" configVersion="b49039a0c3894b41a732cee38bfae78d00000000"/>
|
<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="4773009ef4f1164eadd05bc75928d86900000000"/>
|
<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="63a64f60c307414fabfabd0d777a47cc00000000"/>
|
<Metadata name="Language.Русский" id="e3ac9659-5250-4530-9ca6-3f4f4ef6413a" configVersion="9b1ab00d6dd15a48b70a736c7e6be41900000000"/>
|
||||||
</ConfigVersions>
|
</ConfigVersions>
|
||||||
</ConfigDumpInfo>
|
</ConfigDumpInfo>
|
@ -21,6 +21,16 @@
|
|||||||
<CommandName>Form.Command.Тест2</CommandName>
|
<CommandName>Form.Command.Тест2</CommandName>
|
||||||
<ExtendedTooltip name="Тест2РасширеннаяПодсказка" id="4"/>
|
<ExtendedTooltip name="Тест2РасширеннаяПодсказка" id="4"/>
|
||||||
</Button>
|
</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>
|
</ChildItems>
|
||||||
<Attributes>
|
<Attributes>
|
||||||
<Attribute name="Объект" id="1">
|
<Attribute name="Объект" id="1">
|
||||||
@ -79,5 +89,35 @@
|
|||||||
</ToolTip>
|
</ToolTip>
|
||||||
<Action>Тест1</Action>
|
<Action>Тест1</Action>
|
||||||
</Command>
|
</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>
|
</Commands>
|
||||||
</Form>
|
</Form>
|
@ -91,3 +91,61 @@
|
|||||||
Сообщить(СтрШаблон("Длительность: %1", Конец - Начало));
|
Сообщить(СтрШаблон("Длительность: %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;
|
||||||
use utf16_lit::{utf16, utf16_null};
|
|
||||||
|
use crate::{
|
||||||
|
ffi::{Addin, ParamValue, Tm, Variant},
|
||||||
|
name,
|
||||||
|
};
|
||||||
|
|
||||||
const PROPS: &[&[u16]] = &[
|
const PROPS: &[&[u16]] = &[
|
||||||
&utf16_null!("Test"),
|
name!("Test"),
|
||||||
&utf16_null!("PropI32"),
|
name!("PropI32"),
|
||||||
&utf16_null!("PropF64"),
|
name!("PropF64"),
|
||||||
&utf16_null!("PropBool"),
|
name!("PropBool"),
|
||||||
&utf16_null!("PropDate"),
|
name!("PropDate"),
|
||||||
&utf16_null!("PropStr"),
|
name!("PropStr"),
|
||||||
&utf16_null!("PropBlob"),
|
name!("PropBlob"),
|
||||||
];
|
];
|
||||||
|
|
||||||
const METHODS: &[&[u16]] = &[&utf16_null!("Method1"), &utf16_null!("Method2")];
|
const METHODS: &[&[u16]] = &[name!("Method1"), name!("Method2")];
|
||||||
|
|
||||||
pub struct Addin1 {
|
pub struct Addin1 {
|
||||||
test: i32,
|
test: i32,
|
||||||
@ -42,14 +46,8 @@ impl Drop for Addin1 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Addin 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] {
|
fn register_extension_as(&mut self) -> &'static [u16] {
|
||||||
&utf16_null!("Class1")
|
name!("Class1")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_n_props(&mut self) -> usize {
|
fn get_n_props(&mut self) -> usize {
|
||||||
@ -235,8 +233,4 @@ impl Addin for Addin1 {
|
|||||||
_ => false,
|
_ => 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 crate::{
|
||||||
use utf16_lit::utf16_null;
|
simple::{Addin, MethodInfo, Methods, PropInfo},
|
||||||
|
ffi::{ParamValue, Variant}, name,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct Addin2 {
|
pub struct Addin2 {
|
||||||
test1: i32,
|
prop1: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Addin2 {
|
impl Addin2 {
|
||||||
pub fn new() -> Addin2 {
|
pub fn new() -> Addin2 {
|
||||||
Addin2 { test1: 12345 }
|
Addin2 { prop1: 0 }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for Addin2 {
|
fn method1(&mut self, param: &mut Variant, ret_value: &mut Variant) -> bool {
|
||||||
fn drop(&mut self) {}
|
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 {
|
impl Addin for Addin2 {
|
||||||
fn init(&mut self, _interface: &'static Connection) -> bool {
|
fn name() -> &'static [u16] {
|
||||||
true
|
name!("Class2")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn done(&mut self) {}
|
fn methods() -> &'static [MethodInfo<Self>] {
|
||||||
|
&[
|
||||||
fn register_extension_as(&mut self) -> &'static [u16] {
|
MethodInfo {
|
||||||
&utf16_null!("Class2")
|
name: name!("Method1"),
|
||||||
|
method: Methods::Method1(Self::method1),
|
||||||
|
},
|
||||||
|
MethodInfo {
|
||||||
|
name: name!("Method2"),
|
||||||
|
method: Methods::Method2(Self::method2),
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_n_props(&mut self) -> usize {
|
fn properties() -> &'static [PropInfo<Self>] {
|
||||||
1
|
&[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,
|
vt: VariantType,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused_variables)]
|
||||||
pub trait Addin {
|
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
|
/// default 2000, don't use version 1000, because static objects are created
|
||||||
fn get_info(&mut self) -> u16 {
|
fn get_info(&mut self) -> u16 {
|
||||||
2000
|
2000
|
||||||
}
|
}
|
||||||
fn done(&mut self);
|
fn done(&mut self) {}
|
||||||
fn register_extension_as(&mut self) -> &'static [u16];
|
fn register_extension_as(&mut self) -> &'static [u16];
|
||||||
fn get_n_props(&mut self) -> usize;
|
fn get_n_props(&mut self) -> usize {
|
||||||
fn find_prop(&mut self, name: &[u16]) -> Option<usize>;
|
0
|
||||||
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 find_prop(&mut self, name: &[u16]) -> Option<usize> {
|
||||||
fn set_prop_val(&mut self, num: usize, val: &ParamValue) -> bool;
|
None
|
||||||
fn is_prop_readable(&mut self, num: usize) -> bool;
|
}
|
||||||
fn is_prop_writable(&mut self, num: usize) -> bool;
|
fn get_prop_name(&mut self, num: usize, alias: usize) -> Option<&'static [u16]> {
|
||||||
fn get_n_methods(&mut self) -> usize;
|
None
|
||||||
fn find_method(&mut self, name: &[u16]) -> Option<usize>;
|
}
|
||||||
fn get_method_name(&mut self, num: usize, alias: usize) -> Option<&'static [u16]>;
|
fn get_prop_val(&mut self, num: usize, val: &mut Variant) -> bool {
|
||||||
fn get_n_params(&mut self, num: usize) -> usize;
|
false
|
||||||
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 set_prop_val(&mut self, num: usize, val: &ParamValue) -> bool {
|
||||||
fn call_as_proc(&mut self, method_num: usize, params: &mut [Variant]) -> 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(
|
fn call_as_func(
|
||||||
&mut self,
|
&mut self,
|
||||||
method_num: usize,
|
method_num: usize,
|
||||||
params: &mut [Variant],
|
params: &mut [Variant],
|
||||||
val: &mut Variant,
|
val: &mut Variant,
|
||||||
) -> bool;
|
) -> bool {
|
||||||
fn set_locale(&mut self, loc: &[u16]);
|
false
|
||||||
fn set_user_interface_language_code(&mut self, lang: &[u16]);
|
}
|
||||||
|
fn set_locale(&mut self, loc: &[u16]) {}
|
||||||
|
fn set_user_interface_language_code(&mut self, lang: &[u16]) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
mod addin1;
|
mod addin1;
|
||||||
mod addin2;
|
mod addin2;
|
||||||
|
mod simple;
|
||||||
mod ffi;
|
mod ffi;
|
||||||
|
mod macros;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
ffi::{c_int, c_long, c_void},
|
ffi::{c_int, c_long, c_void},
|
||||||
@ -8,11 +10,10 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use addin1::Addin1;
|
use addin1::Addin1;
|
||||||
use ffi::{destroy_component, AttachType};
|
use addin2::Addin2;
|
||||||
|
use ffi::{create_component, destroy_component, AttachType};
|
||||||
use utf16_lit::utf16_null;
|
use utf16_lit::utf16_null;
|
||||||
|
|
||||||
use crate::{addin2::Addin2, ffi::create_component};
|
|
||||||
|
|
||||||
pub static mut PLATFORM_CAPABILITIES: AtomicI32 = AtomicI32::new(-1);
|
pub static mut PLATFORM_CAPABILITIES: AtomicI32 = AtomicI32::new(-1);
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[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…
x
Reference in New Issue
Block a user