跳转至

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个字节
    [err,x] := 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 初始发布。