Dart Native Access lets you deal with native libraries from Dart with zero lines of C/C++ code. Just pure Dart.

How to ...

For instance, you want to call getppid function from libc library on Linux.

  1. Find method signature in documentation:

pid_t getpid(void);

  1. Map parameters types and return type to C date types:

FIXME: Platform specific step

typedef int pid_t;

  1. Map C types to Dart types and DNA type constants. See Type mapping.
  1. Define class Libc with annotation @Library:
class Libc {

libc.so.6 is library name

  1. Define method getppid. Annotate parameters with @Param and method with @Return with corresponding type constants:
class Libc {
  int getpid() { ... }

In this example method has no parameters.

  1. Finish with boilerplate code:

FIXME: This is temporary step for early versions

class Libc {
  dynamic lib = new DynamicLibrary<Libc>();  
  int getpid() { return lib.getpid(); }

  1. Use it
Libc libc = new Libc();
var processId = libc.getpid();

Type mapping

FIXME: Describe pointers and in/out parameters

| C | Dart |Constant|In/Out|Comments| |-----|-----|-----|-----|-----| |void|void|VOID||| |char|int|C_CHAR||| |short|int|C_SHORT||| |int|int|C_INT||| |long|int|C_LONG||| |longlong|int|C_LONGLONG||| |bool|bool|C_BOOL||| |float|double|C_FLOAT||| |double|double|C_DOUBLE||| |type |int|C_POINTER| |if you know raw pointer value| |type |TypedData|TYPEDDATA| |TypeData must be initialized and have expected by callee size| |---|---|---|---|---| |struct |T|TYPEDATA|In|where T is strut class. See Define structure| |struct |Ref<T>|TYPEDATA|Out|where T is strut class. See Define structure| |---|---|---|---| |char |String|C_STRING|In|| |char |Ref<String>|C_STRING|Out|| |int |List<int>|LISTINT|In|| |int |Ref<List<int>>|LISTINT|Out|| |char |List<String>|LISTSTRING|In|| |char |Ref<List<String>>|LISTSTRING|Out||

Out parameters must be annotate with @Out

Define method

T method(@Param(XYZ) P1 inParam, @Param(XYZ) @Out() Ref<P2> outParam)

Define structure

class Struct {
    T field;

Define library

class Library {

FIXME: Symlinks aren't supported yet



libc library

class Libc {
  dynamic lib = new DynamicLibrary<Libc>();

  int getpid() { return lib.getpid(); }      
  int getuid() { return lib.getuid(); }       
  void srand(@Param(C_UINT) int seed) { return lib.srand(seed); }      
  int rand() { return lib.rand(); }

void main(){
  Libc libc = new Libc();
  var processId = libc.getpid();
  print('pid $processId');

  var userId = libc.getuid();
  print('user id ${userId}');

  var rand = libc.rand();
  print('random $rand');    


kenel32 library

class Kernel32 {
  dynamic lib = new DynamicLibrary<Kernel32>();

  int GetCurrentProcess() { return lib.GetCurrentProcess(); }
  int GetProcessId(@Param(C_INT) int process) { return lib.GetProcessId(process); }
  int GetModuleFileNameA(@Param(C_INT) int process, @Param(C_STRING) @Out() Ref<String> imageFileName, 
    @Param(C_INT) int size) { return lib.GetModuleFileNameA(process, imageFileName, size); }
  bool GetProcessWorkingSetSize(@Param(C_INT) int process, 
    @Param(C_POINTER) Ref<int> minimumWorkingSetSize,
    @Param(C_POINTER) Ref<int> maximumWorkingSetSize) { return lib.GetProcessWorkingSetSize(process, minimumWorkingSetSize, maximumWorkingSetSize); }

  int GetLastError() { return lib.GetLastError(); }

void main(){
  Kernel32 kernel32 = new Kernel32();
  var process = kernel32.GetCurrentProcess();
  var processId = kernel32.GetProcessId(process);
  print('pid $processId = ${io.pid}');

  var min = new Ref<int>(0);
  var max = new Ref<int>(0);
  var result = kernel32.GetProcessWorkingSetSize(process, min, max);
  print('working set min ${min.value} max ${max.value}');

  var name = new Ref(new String.fromCharCodes(new List.filled(64, 0)));
  result = kernel32.GetModuleFileNameA(0, name, name.value.length);
  print('module name  ${name.value} result $result error ${kernel32.GetLastError()}');



  • Linux 64-bit
  • Windows 32-bit and 64-bit

Trade off

  • Performance?
  • A lot of things aren't supported yet



Dart Native Access