6

I created a struct with dart:ffi.

import 'dart:ffi';
import 'package:ffi/ffi.dart';

class TestStruct extends Struct{
   external Pointer<Utf8> strText;
   
   @Int32()
   external int nNum;

   @Bool()
   external bool bIsTrue;


   //contstruct
   TestStruct(String str, int number, bool state){
      strText = str as Pointer<Utf8>;
      nNum = number as int;
      bIsTrue = state as bool;
   }
}

I want to create a reference of TestStruct and use it. So I wrote the code.

TestStruct test = TestStruct("Text", 10, true);

but this is an error

Subclasses of 'Struct' and 'Union' are backed by native memory, and can't be instantiated by a generative constructor.  
Try allocating it via allocation, or load from a 'Pointer'.

I tried searching with the api documentation, but I didn't understand. Do you know how to create a struct as a reference?? thank you.

4 Answers 4

5

Example:

class InAddr extends Struct {

  factory InAddr.allocate(int sAddr) =>
      calloc<InAddr>().ref
        ..sAddr = sAddr;
        
  @Uint32()
  external int sAddr;
}

You can allocate this with calloc function

final Pointer<InAddr> inAddress = calloc<InAddr>();

And free the pointer with

calloc.free(inAddress);
Sign up to request clarification or add additional context in comments.

1 Comment

Unfortunately, factory won't work. You'll get an error when trying to call it.
4

While I am late to the party, writing a complete example so that it may be helpful for others new to the FFI scene.

If this is the dart representative struct (from C) -

import 'dart:ffi';
import 'package:ffi/ffi.dart';

class TestStruct extends Struct{
   
   @Int32()
   external int nNum;

   @Bool()
   external bool bIsTrue;

  // IMPORTANT: DO NOT DEFINE A CONSTRUCTOR since struct/union are natively allocated
   
}

You can instantiate from dart using ffi.Pointer like below.

// my_native_helper.dart

 final dynamicLibrary = ... ; // load .so/process

 void some_function() {
  final Pointer<TestStruct > inAddress = calloc<TestStruct >();
    inAddress.ref.nNum= 1234;
    inAddress.ref.bIsTrue = false;

    // ffigen generated method replicating C extern function
    // To auto generate this, define the C signature in a header file
    dynamicLibrary.receiveFromDart(inAddress);

    calloc.free(inAddress);
 }

The C method will look like below.

extern "C" void recieveFromDart(TestStruct* structPtr) {
  cout << structPtr->nNum << "/" << structPtr->bIsTrue << endl;
}

Comments

1

According to the doc you can't create instances of Struct classes: https://api.flutter.dev/flutter/dart-ffi/Struct-class.html

However, you typically would need pointers. So you can come up with something like that:

static Pointer<InAddr> allocate(int sAddr) {
    final pointer = calloc<InAddr>();
    pointer.ref.sAddr = sAddr;
    return pointer;
}

Comments

0

The syntax has changed in recent versions. If we have the following struct:

final class CLLocationCoordinate2D extends ffi.Struct {
  @ffi.Double()
  external double latitude;

  @ffi.Double()
  external double longitude;
}

We can instantiate it like this:

final coords = Struct.create<CLLocationCoordinate2D>();
coords.latitude = lat.toDouble();
coords.longitude = lng.toDouble();

From the flutter documentation:

An instance of a struct subclass cannot be created with a generative constructor. Instead, an instance can be created by StructPointer.ref, Struct.create, FFI call return values, FFI callback arguments, StructArray, and accessing Struct fields. To create an instance backed by native memory, use StructPointer.ref. To create an instance backed by Dart memory, use Struct.create.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.