跳转至

ffi_plugin

TSL语言的跨平台实现的外部函数接口(Foreign Function Interface)插件。

安装

(已集成到mytsl发行版中)

动态库文件:Windows: ffi_plugin.dll, Linux: libffi_plugin.so。

把相关的动态库文件拷贝到执行服务器或者TSL目录的plugin目录。

使用指南

提供的TSL函数:

ffi_cb_def

ffi_cb_def(return_var, callback_name, ...args): 定义回调函数原型。

  • 参数列表

    参数 描述
    return_var 返回值类型定义,魔法参数类型。
    callback_name 回调原型名称,字符串类型。
    args 参数类型,魔法参数类型。
  • 返回值

    数组类型,如果发生错误:

    下标
    0 错误代码
    1 错误信息

    没有错误:

    下标
    0 0
  • 支持的类型定义

    类型 描述
    i8 有符号8位整数
    i16 有符号16位整数
    i32 有符号32位整数
    i64 有符号64位整数
    u8 无符号8位整数
    u16 无符号8位整数
    u32 无符号8位整数
    u64 无符号8位整数
    f32 32位浮点数
    f64 64位浮点数
    void
    pointer 指针
    char 8位字符
    int 有符号32位整数
    foat 32位浮点数
    doble 64位浮点数
    intptr 指针

    例子:

    // BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam);
    ffi_cb_def(@i32(), "EnumWindowsProc", @pointer(), @pointer());
    

ffi_cb_alloc

ffi_cb_alloc(callback_name, func): 分配回调指针。

  • 参数列表

    参数 描述
    callback_name 回调原型名称,字符串类型。
    func 函数,lambda或者字符串类型
  • 返回值

    数组类型,如果发生错误:

    下标
    0 错误代码
    1 错误信息

    没有错误:

    下标
    0 0
    1 回调指针

ffi_cb_free

ffi_cb_free(pointer): 释放回调指针。

  • 参数列表

    参数 描述
    pointer 回调指针。
  • 返回值 1

ffi_new

ffi_new(type_def, [vaule]): 分配系统内存。

  • 参数列表

    参数 描述
    type_def 类型定义,魔法参数类型。
    vaule 初始值,可选参数。

    类型定义参见ffi_cb_def。可以同时指定要分配的类型的个数,像数组一样。

    例如:

    [err, x] := ffi_new(@int()); // x = int[1],总共4个字节
    [errx] := ffi_new(@int(10));  // x = int[10],总共4*10个字节
    

    ffi_new还支持定义struct类的结构,例如:

    st_def := @struct(
          @i32("i1")
        , @i32("i2")
        , @i8("i3")
        , @float("f1")
        , @double("d1")
        , @char("s1", 16) // 相当于C的 char s1[16]
    ) -> "<1"; // 1字节对齐,小端字节序模式。如果不设置,用系统默认设置。
    
    [err, st] := ffi_new(st_def);
    st.i1 := 1;
    st.i2 := 2;
    st.i3 := 3;
    st.f1 := 12.34;
    st.d1 := 56.78;
    st.s1 := "1234567890";
    
    [err, data] := ffi_pack(st); // 用ffi_pack把结构输出成二进制类型
    

  • 返回值

    数组类型,如果发生错误:

    下标
    0 错误代码
    1 错误信息

    没有错误:

    下标
    0 0
    1 系统内存对象

Note

分配的系统内存是自动管理的,和相应变量生命周期一样。

系统内存对象的相关方法

value()

value(): 返回TSL格式的变量。

例如:

[err, x] :=ffi_new(@int(), 1);
vprintln(x.value()); // 打印:1
[err, x] :=ffi_new(@int(10), 1);
vprintln(x.value()); // 打印:array(1,1,1,1,1,1,1,1,1,1)
[err, x] :=ffi_new(@char(12), "hello world");
vprintln(x.value()); // 打印:hello world

string(): 返回字符串。

ffi_pack

ffi_pack(struct): 将结构转成二进制类型。

  • 参数列表

    参数 描述
    struct 结构对象。

    例如:

    st_def := @struct(
          @i32("i1")
        , @i32("i2")
        , @i8("i3")
        , @float("f1")
        , @double("d1")   // 相当于C的 doble d1
        , @char("s1", 16) // 相当于C的 char  s1[16]
    );
    [err, st] := ffi_new(st_def);
    [err, data] := ffi_pack(st);
    println("len={}", length(data));
    

  • 返回值

    数组类型,如果发生错误:

    下标
    0 错误代码
    1 错误信息

    没有错误:

    下标
    0 0
    1 二进制类型

ffi_unpack

ffi_unpack(struct_def, data): 将二进制类型或者字符串类型转成结构。

  • 参数列表

    参数 描述
    struct_def 结构定义,魔法参数类型。
    data 数据,二进制类型或者字符串类型

    例如:

    st_def := @struct(
          @i32("i1")
        , @i32("i2")
        , @i8("i3")
        , @float("f1")
        , @double("d1")
    );
    [err, st] := ffi_unpack(st_def, data);
    println("i1={}", st.i1);
    
  • 返回值

    数组类型,如果发生错误:

    下标
    0 错误代码
    1 错误信息

    没有错误:

    下标
    0 0
    1 结构对象

ffi_typeof

ffi_typeof(struct_def | struct): 输出结构的定义。

  • 参数列表

    参数 描述
    struct_def 结构定义,魔法参数类型。也可以是结构对象。

    例如:

    st_def := @struct(
          @i32("i1")
        , @i32("i2")
        , @i8("i3")
        , @float("f1")
        , @double("d1")
    );
    [err, st_info] := ffi_typeof(st_def);
    println("{}", st_info);
    // 打印:
    array("type":"struct","size":24L,"alignment":8,"field":(("i1","int",1,4L,0L),("i2","int",1,4L,4L),("i3","i8",1,1L,8L),("f1","float",1,4L,12L),("d1","f64",1,8L,16L)))
    

  • 返回值

    数组类型,如果发生错误:

    下标
    0 错误代码
    1 错误信息

    没有错误:

    下标
    0 0
    1 数组类型,下标"type"是类型,下标"size"是结构总共占用字节数,下标"alignment"是对齐方式,下标"field"是包含的字段。

    结果数组"field"子项的内容: | 下标 | 值 | |:----|:----| |0|字段名| |1|类型| |2|个数| |3|占用字节数| |4|起始位置|

ffi_sizeof

ffi_sizeof(mem|struct|@struct.field): 输出结构的定义。

  • 参数列表

    参数 描述
    mem 系统内存对象,也可以是结构对象或者结构对象的字段的地址。

    例如:

    st_def := @struct(
          @i32("i1")
        , @i32("i2")
        , @i8("i3")
        , @float("f1")
        , @double("d1")
    );
    [err, size] := ffi_sizeof(st_def);
    [err, st]   := ffi_new(@st_def);
    [err, size] := ffi_sizeof(st);
    [err, size] := ffi_sizeof(@st.f1); // 用@struct.field来取结构字段的地址
    [err, p]    := ffi_new(@int());
    [err, size] := ffi_sizeof(p);
    [err, size] := ffi_sizeof(@int());
    

  • 返回值

    数组类型,如果发生错误:

    下标
    0 错误代码
    1 错误信息

    没有错误:

    下标
    0 0
    1 大小,整数类型。

ffi_copy

ffi_copy(dst, src, [len] ): 内存拷贝,功能类似C的memcpy。

  • 参数列表

    参数 描述
    dst 系统内存对象,也可以是结构对象或者结构对象的字段的地址。
    src 系统内存对象,也可以是结构对象或者结构对象的字段的地址。
    len 长度,整数类型,可选参数。

    例如:

    st_def := @struct(
          @i32("i1")
        , @i32("i2")
        , @i8("i3")
        , @float("f1")
        , @double("d1")
    );
    [err, st]   := ffi_new(@st_def);
    [err, st2]  := ffi_new(@st_def);
    [err, size] := ffi_copy(st, st2);
    [err, size] := ffi_copy(@st.i1, @st2.i2);
    

  • 返回值

    数组类型,如果发生错误:

    下标
    0 错误代码
    1 错误信息

    没有错误:

    下标
    0 0
    1 拷贝的字节数,整数类型。

ffi_fill

ffi_fill(dst, len, [c] ): 内存填充,功能类似C的memset。

  • 参数列表

    参数 描述
    dst 系统内存对象,也可以是结构对象或者结构对象的字段的地址。
    src 系统内存对象,也可以是结构对象或者结构对象的字段的地址。
    len 长度,整数类型,可选参数。

    例如:

    st_def := @struct(
          @i32("i1")
        , @i32("i2")
        , @i8("i3")
        , @float("f1")
        , @double("d1")
    );
    [err, size] := ffi_sizeof(st_def);
    [err, st]   := ffi_new(@st_def);
    [err, len]  := ffi_fill(st, size, 0);
    [err, len]  := ffi_fill(@st.i1, 10, 0);
    

  • 返回值

    数组类型,如果发生错误:

    下标
    0 错误代码
    1 错误信息

    没有错误:

    下标
    0 0
    1 填充的字节数,整数类型。

范例

EnumWindows回调

// 定义回调原型
ffi_cb_def(@i32(), "EnumWindowsProc", @pointer(), @intptr());
// 分配回调指针
[err, cb] := ffi_cb_alloc("EnumWindowsProc", 
    function(h, p) 
    begin 
        println("h={},p={}", h, p);
        [err, buffer] := ffi_new(@char(512)); // 分配512字节接收ClassName
        pp := GetClassNameA(h, buffer, 512);
        vprintln(pp, buffer.string());
        return 1;
    end);
EnumWindows(cb, 0);
// 使用完释放回调指针
ffi_cb_free(cb);

function EnumWindows(proc:pointer;param:pointer):int;stdcall;external "User32.dll"  name "EnumWindows";
function GetClassNameA(HH:pointer;var name:string;len:integer):pointer;stdcall;external "User32.dll"  name "GetClassNameA"; 

附录

更新历史

  • 2022-8-23 初始发布。