14

Hello I am using dart:ffi to build an interface with my native c/c++ library. and I needed a way to get a callback from c to dart as an example in 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 */
);

the third parameter in sqlite3_exec is function pointer to a callback. so if I called this function in dart using ffi I need to pass a function pointer: and in dart:ffi Pointer class there is a function named fromFunction witch accepts a dart static function and an exceptionalReturn; but just by calling this function to get the function pointer of a dart managed function: a (sigterm) is raised and the dart code no long work in the process.

So My Question: Is there any way to get a native callback in dart, as in Python, c#, ..

Extra: Is there any way to include dartino in a flutter project, since this ForeignDartFunction covers what I need.

ch271828n
  • 15,854
  • 5
  • 53
  • 88
Ala'a Al Hallaq
  • 455
  • 5
  • 11

1 Answers1

29

I got an example to work. Hopefully you can adapt this to your case.

Example C function

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

Dart code

First the typedefs. We need two for the native function foo and one for the Dart callback.

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);

and the code for the callback

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

and the lookup

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

and, finally, use it like this:

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

as expected, foo(123) prints flutter: in callback i=123 and returns 124

Richard Heap
  • 48,344
  • 9
  • 130
  • 112
  • thank you, I already had a working example,I will mark this as a correct answer since it covers every thing needed. – Ala'a Al Hallaq May 01 '20 at 21:26
  • 3
    Yes, I should have shown that too. `static const except = -1;` – Richard Heap May 01 '20 at 21:29
  • my issue was with the 2nd parameter `exceptionalReturn ` in `fromFunction`, dart requires it to be a constant value, and apparently -5 (and negative value) is not a constant value for the dart compiler /interpreter. So I need to ask you did it work correctly having the value stored in a variable named `except`. – Ala'a Al Hallaq May 01 '20 at 21:29
  • 4
    It should be noted that this will only work for a Dart created thread, so sync calls, async callbacks, ie. if theSqlite does the callback on a thread Sqlite created will **NOT** work as its breaks Darts threading-concurrency safety model, which is tracked in: https://github.com/dart-lang/sdk/issues/37022. – Maks Aug 18 '21 at 01:29
  • @RichardHeap If so, is it possible to receive 124, the retrun value of dart, when calling foo from `main` in C? – Jungwon Oct 19 '22 at 01:56
  • No - as in the comment above, you can only call from C to Dart if that C function is itself being called from Dart. – Richard Heap Oct 19 '22 at 12:59