繁体   English   中英

Dart 中的回调:dart:ffi 仅支持从原生代码调用静态 Dart 函数

[英]Callbacks in Dart: dart:ffi only supports calling static Dart functions from native code

这篇文章是这里的 Github 问题的副本。

dart --version Dart SDK 版本:2.15.0-116.0.dev (dev) (Thu Sep 16 09:47:01 2021 -0700) on "linux_x64"

我一直在寻找回调的例子,我试图让回调在 FFI 中为我工作。

我现在的情况

我的库中有一个函数,它需要一个指向函数的指针。 ffigen生成的相同绑定对我来说似乎是正确的。

int SetCallback(
    CallbackType callback,
  ) {
    return _SetCallback(
      callback,
    );
  }

  late final _SetCallbackPtr =
      _lookup<NativeFunction<Int32 Function(CallbackType)>>(
          'SetCallback');
  late final _SetCallback =
      _SetCallbackPtr.asFunction<int Function(CallbackType)>();

其中, typedef CallbackType = Pointer<NativeFunction<Void Function(Uint32)>>; .

我在这里要做的是在 Dart 中设置这个回调,将它传递给 FFI,本质上将它用作我在 C 中的回调。在我的 API 中,它从 FFI 代码中抽象出来(这意味着我有一个 MyLibrary 类充满了用户将直接调用的静态函数,这些函数又从我创建的 MyNativeLibrary 类的对象 _nativeLibrary 调用函数),我有:

  static int SetCallback({required CallbackFuncDart callback}) {
    Pointer<NativeFunction<CallbackFunc>> pointer = Pointer.fromFunction(callback);

    int status = _nativeLibrary.SetCallback(
      pointer,
    );
    if (STATUS_OK != status) {
      throw LibLexemeException(status);
    }
    return status;
  }

typedef CallbackFunc = Void Function(Uint32);
typedef CallbackFuncDart = void Function(int);

虽然sqlite ffi 示例在这里指出

dart:ffi 尚不支持的功能:

 Callbacks from C back into Dart.

我相信文档尚未更新以反映此处示例的更改。 由于样本没有任何 C/C++ 文件,或者不了解 C 函数的工作原理,因此这些样本还不是很清楚。 即便如此,我认为这个示例包含一个段(最后一个代码块),其中一个 Dart 函数作为回调传递,我已经在我的程序中复制了该回调。 我不清楚这将如何工作,但在尝试编译我的程序时,我得到:

ERROR: ../lib/library_lexeme.dart:180:74: Error: fromFunction expects a static function as parameter. dart:ffi only supports calling static Dart functions from native code. Closures and tear-offs are not supported because they can capture context.
ERROR:     Pointer<NativeFunction<CallbackFunc>> pointer = Pointer.fromFunction(callback);

简短的版本是您不能将回调作为参数传递:

static int SetCallback({required CallbackFuncDart callback}) {
    Pointer<NativeFunction<CallbackFunc>> pointer = Pointer.fromFunction(callback); // <-- this isn't considered a static function

这很烦人,但是您必须使用提前定义的静态函数才能从 C 调用您的 dart 回调。

显然目前只能通过 ffi 传递静态函数。 但是,如果您必须访问实例的数据并且您确定该实例存在,您可以使用我的解决方法。 我对实例使用静态列表。 这既愚蠢又丑陋,但对我有用:

class CallbackClass {
  static Int8 classCallback(int id) { 
    final instance = instanceList[id];
    return instance.instanceCallback();
  }

  Int8 instanceCallback() { return instanceId; }

  static List<CallbackClass> instanceList = <CallbackClass>[];
  late final int instanceId;

  CallbackClass {
    instanceId = instanceList.length;
    instanceList.insert(instanceId, this);
    myFFImapping.passCallback(instanceId, Pointer.fromFunction<>(classCallback);)
  }
}

为了清楚起见,我省略了必要的 c 代码、FFI 映射和强制转换以纠正类型,所以它显然不会像这样编译。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM