Dart/Flutter ffi(外部函数接口)本地回调,例如:sqlite3_exec

14

你好,我正在使用dart:ffi构建与我的本地c/c++库的接口,需要一种从c到dart的回调方式,例如在sqlite中:

int sqlite3_exec(
    sqlite3*,                                  /* An open database */
    const char *sql,                           /* SQL to be evaluated */
    int (*callback)(void*,int,char**,char**),  /* Callback function */
    void *,                                    /* 1st argument to callback */
    char **errmsg                              /* Error msg written here */
);
sqlite3_exec中的第三个参数是一个回调函数的函数指针。 因此,如果我使用 ffi 在 dart 中调用这个函数,我需要传递一个函数指针:而在dart:ffiPointer 类中,有一个名为fromFunction的函数,它接受一个dart静态函数和一个exceptionalReturn; 但仅仅通过调用此函数来获取dart管理的函数的函数指针时:会引发一个(sigterm),并且dart代码在进程中不再工作。
所以我的问题是:是否有办法在dart中获得一个本地回调,如Python、C#等?
附加信息: 在flutter项目中是否有一种方法可以包含dartino,因为这个ForeignDartFunction包含了我需要的内容。

你看过Pointer.fromFunction吗?https://api.dart.dev/stable/2.8.1/dart-ffi/Pointer/fromFunction.html - julemand101
@julemand101 是的,我做了,这是我的问题所暗示的,文档中没有fromFunction的示例。 - Ala'a Al Hallaq
啊,抱歉,我没有看到那一部分。 - julemand101
1
你确定回调函数是在主线程上执行,而不是在库中创建的线程上执行吗? - Richard Heap
@RichardHeap 我没有调用函数,只是在dart中获取回调函数指针时调用'Pointer.fromFunction'会引发'sigterm'。 - Ala'a Al Hallaq
1个回答

31

我成功地实现了一个样例。希望你可以将其应用到你的情况中。

样例C函数

EXTERNC int32_t foo(
                    int32_t bar,
                    int32_t (*callback)(void*, int32_t)
                    ) {
    return callback(nullptr, bar);
}

Dart代码

首先是typedefs。我们需要两个用于本地函数foo和一个用于Dart回调的typedef

typedef example_foo = Int32 Function(
    Int32 bar, Pointer<NativeFunction<example_callback>>);
typedef ExampleFoo = int Function(
    int bar, Pointer<NativeFunction<example_callback>>);

typedef example_callback = Int32 Function(Pointer<Void>, Int32);

以及回调函数的代码

  static int callback(Pointer<Void> ptr, int i) {
    print('in callback i=$i');
    return i + 1;
  }

并且查找

  ExampleFoo nativeFoo =
    nativeLib.lookup<NativeFunction<example_foo>>('foo').asFunction();

最后,像这样使用它:

  int foo(int i) {
    return nativeFoo(
      i,
      Pointer.fromFunction<example_callback>(callback, except),
    );
  }

正如预期,foo(123) 打印了 flutter: in callback i=123 并返回 124


谢谢,我已经有一个可用的示例了。我会将其标记为正确答案,因为它涵盖了所有需要的内容。 - Ala'a Al Hallaq
3
是的,我也应该展示那个。static const except = -1; - Richard Heap
我的问题出在 fromFunction 的第二个参数 exceptionalReturn 上,Dart 要求它是一个常量值,而显然 -5(和负数)对于 Dart 编译器/解释器来说不是一个常量值。 所以我需要问你,将该值存储在名为 except 的变量中是否可以正常工作。 - Ala'a Al Hallaq
5
需要注意的是,这只适用于由Dart创建的线程,因此同步调用、异步回调,例如如果Sqlite在由Sqlite创建的线程上回调,则不会工作,因为它会破坏Dart的线程并发安全模型,有关该模型的信息请参见:https://github.com/dart-lang/sdk/issues/37022。 - Maks
@RichardHeap 如果这样做的话,在C语言的main函数中调用foo时,是否可能接收到Dart返回的124作为返回值? - Jungwon
不行 - 如上面的评论所述,只有在从Dart调用该C函数本身时,您才能从C调用Dart。 - Richard Heap

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接