5

samples_extension 可以与 C 库链接一起使用,但是 C++ 库呢?

我有一个基于类的 C++ 库,我想将其用作本机扩展,因此我们有例如:-

class Connect {
      open(...);
  ....
}

在 C++ 中,我想要在 Dart 中有一个类似的类。

查看 dart_api.h 和 dart_native_api.h 我不清楚我如何将类指针从 C++ 来回传递给 Dart,以及我如何调用它们的方法并将其与 Dart 类实例联系起来。ResolveName 如何与 connection->open() 类型调用一起工作,还是我们完全不同。

4

2 回答 2

6

可以回答您的问题的基本项目:

cpp_extension.cc

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#ifdef _WIN32
#include "windows.h"
#else
#include <stdbool.h>
#include <dlfcn.h>
#include <unistd.h>
#include <sys/mman.h>
#endif

#include "dart_api.h"

Dart_NativeFunction ResolveName(Dart_Handle name, int argc, bool* auto_setup_scope);

DART_EXPORT Dart_Handle cpp_extension_Init(Dart_Handle parent_library) {
  if (Dart_IsError(parent_library)) { return parent_library; }

  Dart_Handle result_code = Dart_SetNativeResolver(parent_library, ResolveName);
  if (Dart_IsError(result_code)) return result_code;

  return Dart_Null();
}

Dart_Handle HandleError(Dart_Handle handle) {
  if (Dart_IsError(handle)) Dart_PropagateError(handle);
  return handle;
}

class Connection {
  int* buffer;
  bool opened;

  public:
    Connection() {
      opened = false;
      buffer = new int[1000000];
      memset(buffer, 1, 1000000);
    }

    void close() {
      opened = false;
    } 

    void open(const char* connectionString) {
      opened = true;
    }

    ~Connection() {
      delete buffer;
    }
};

void ConnectionClose(Dart_NativeArguments arguments) {
  Connection* connection;
  Dart_Handle dh_handle;

  Dart_EnterScope();
  dh_handle = Dart_GetNativeArgument(arguments, 0);
  connection = (Connection*)dh_handle;
  connection->close();
  Dart_Handle result = Dart_Null();
  Dart_SetReturnValue(arguments, result);
  Dart_ExitScope();
}

void ConnectionCreate(Dart_NativeArguments arguments) {  
  Connection* connection;
  Dart_Handle result;

  Dart_EnterScope();
  connection = new Connection();
  result = Dart_NewInteger((int64_t)connection);
  Dart_SetReturnValue(arguments, result);
  Dart_ExitScope();
}

void ConnectionPeerFinalizer(Dart_WeakPersistentHandle handle, void *peer) {
  delete (Connection*) peer;
}

void ConnectionPeerRegister(Dart_NativeArguments arguments) {
  int64_t peer;
  Dart_Handle dh_object;
  Dart_Handle dh_peer;

  Dart_EnterScope();
  dh_object = Dart_GetNativeArgument(arguments, 0);
  dh_peer = Dart_GetNativeArgument(arguments, 1);
  Dart_IntegerToInt64(dh_peer, &peer);
  Dart_NewWeakPersistentHandle(dh_object, (void*)peer, ConnectionPeerFinalizer);
  Dart_SetReturnValue(arguments, Dart_Null());
  Dart_ExitScope();
}

void ConnectionOpen(Dart_NativeArguments arguments) { 
  Connection* connection;
  const char* connectionString;
  Dart_Handle dh_connectionString;
  Dart_Handle dh_handle;

  Dart_EnterScope();
  dh_handle = Dart_GetNativeArgument(arguments, 0);
  dh_connectionString = Dart_GetNativeArgument(arguments, 1);
  Dart_StringToCString(dh_connectionString, &connectionString);
  connection = (Connection*)dh_handle;
  connection->open(connectionString);  
  Dart_Handle result = Dart_Null();
  Dart_SetReturnValue(arguments, result);
  Dart_ExitScope();
}

struct FunctionLookup {
  const char* name;
  Dart_NativeFunction function;
};

FunctionLookup function_list[] = {
  {"ConnectionClose", ConnectionClose},
  {"ConnectionCreate", ConnectionCreate},
  {"ConnectionOpen", ConnectionOpen},
  {"ConnectionPeerRegister", ConnectionPeerRegister},
  {NULL, NULL}};

Dart_NativeFunction ResolveName(Dart_Handle name, int argc, bool* auto_setup_scope) {
  if (!Dart_IsString(name)) return NULL;
  Dart_NativeFunction result = NULL;
  Dart_EnterScope();
  const char* cname;
  HandleError(Dart_StringToCString(name, &cname));

  for (int i=0; function_list[i].name != NULL; ++i) {
    if (strcmp(function_list[i].name, cname) == 0) {
      result = function_list[i].function;
      break;
    }
  }
  Dart_ExitScope();
  return result;
}

cpp_extension.dart

library dart_and_cpp_classes.ext_cpp_extension;

import "dart-ext:cpp_extension";

class Connection {
  final String connectionString;

  int _handle;

  bool _opened = false;

  Connection(this.connectionString) {
    _handle = _create();
    _peerRegister(this, _handle);
  }

  bool get opened => _opened;

  void close() {
    _close(_handle);
    _opened = false;
  }

  void open() {
    _open(_handle, connectionString);
    _opened = true;
  }

  int _create() native "ConnectionCreate";

  void _close(int handle) native "ConnectionClose";

  void _open(int handle, String connectionString) native "ConnectionOpen";

  void _peerRegister(Object object, int handle) native "ConnectionPeerRegister";
}

use_cpp_extension.dart

import 'package:dart_and_cpp_classes/cpp_extension.dart';

void main() {
  var count = 500;
  var connections = [];
  for(var i = 0; i < count; i++) {
    var connection = new Connection("MYSQL");
    connection.open();
    connection.close();
    connections.add(connection);
  }

  connections = null;
  print("Done");
}

这是 github 上的基本(即用型)包:https ://github.com/mezoni/dart_and_cpp_classes

此包中的其他必需文件。

跑:

  • bin/build_cpp_extension.dart
  • bin/use_cpp_extension.dart

附言

我不是 C++ 程序员。

请原谅我在这种语言中的任何不准确之处。

于 2014-01-16T08:41:04.763 回答
3

好的,稍微挖掘一下,我现在已经猜到了,我在 Dart 中这样做:-

bool open() native 'Connection::open';

并在我的解析器中寻找字符串 'Connection::open' 然后调用本机函数。所以,这意味着我的本机函数被命名为“connectionOpen”和“messageOpen”等,所以我可以解决这些问题。

于 2014-01-16T11:52:46.767 回答