Dart C/C++异步扩展

Dart和JavaScript一样,是一种单线程编程语言。如果把耗时的任务都放在Dart线程中,就会阻塞程序。Dart提供了同步和异步两种扩展方式。异步扩展可以把一个C/C++函数执行在一条工作线程上,这样就可以用于执行耗时的任务,不会阻塞程序。这里结合Dynamsoft C/C++ barcode SDK来实现一个Dart的异步扩展。

使用Visual Studio 2015创建Dart异步扩展

安装Dart SDKDynamsoft Barcode Reader

Dart的扩展由*.dart和*.dll文件组成。和JNI一样,*.dart文件中定义了一些调用C/C++接口的函数。这些函数会把上层的参数转发到native发送端口。同时创建一个接收端口用于接收native发送回来的数据。sample_asynchronous_extension.dart

library sample_asynchronous_extension;
 
import 'dart:async';
import 'dart:isolate';
import 'dart-ext:sample_extension';
 
class BarcodeReader {
  static SendPort _port;
 
  Future<List> readBarcode(String filename) {
    var completer = new Completer();
    var replyPort = new RawReceivePort();
    var args = new List(2);
    args[0] = filename;
    args[1] = replyPort.sendPort;
    _servicePort.send(args);
    replyPort.handler = (result) {
      replyPort.close();
      if (result != null) {
        completer.complete(result);
      } else {
        completer.completeError(new Exception("Reading barcode failed"));
      }
    };
    return completer.future;
  }
 
  SendPort get _servicePort {
    if (_port == null) {
      _port = _newServicePort();
    }
    return _port;
  }
 
  SendPort _newServicePort() native "BarcodeReader_ServicePort";
}

运行Visual Studio 2015创建一个空的Win32工程。应用属性选择DLL。把头文件和库的路径添加到工程属性中:

Dart include header

Dart lib path

添加依赖dart.libDBRx64.lib

Dart dependency

添加预处理DART_SHARED_LIB

Dart preprocessor

创建sample_extension_dllmain_win.cc

#if defined(_WIN32)

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

BOOL APIENTRY DllMain(HMODULE module, DWORD reason, LPVOID reserved) {
  return true;
}

#endif  // defined(_WIN32)

创建sample_extension.cc

添加头文件:

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "include/dart_api.h"
#include "include/dart_native_api.h"

#include "If_DBRP.h"

使用函数sample_extension_Init()和ResolveName()来初始化:

DART_EXPORT Dart_Handle sample_extension_Init(Dart_Handle parent_library) {
  if (Dart_IsError(parent_library)) {
    return parent_library;
  }
 
  Dart_Handle result_code =
      Dart_SetNativeResolver(parent_library, ResolveName, NULL);
  if (Dart_IsError(result_code)) {
    return result_code;
  }
 
  return Dart_Null();
}
 
struct FunctionLookup {
  const char* name;
  Dart_NativeFunction function;
};
 
 
FunctionLookup function_list[] = {
    {"BarcodeReader_ServicePort", barcodeReaderServicePort},
    {NULL, NULL}};
 
Dart_NativeFunction ResolveName(Dart_Handle name, int argc, bool* auto_setup_scope) {
  if (!Dart_IsString(name)) {
    return NULL;
  }
  Dart_NativeFunction result = NULL;
  if (auto_setup_scope == NULL) {
    return 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) {
      *auto_setup_scope = true;
      result = function_list[i].function;
      break;
    }
  }
 
  if (result != NULL) {
    Dart_ExitScope();
    return result;
  }
 
  Dart_ExitScope();
  return result;
}

使用Dynamsoft C/C++ barcode接口来读取条形码:

char **readBarcode(char *pszFileName, int *out_len) {
    char **values = NULL;
 
    __int64 llFormat = (OneD | QR_CODE | PDF417 | DATAMATRIX);
 
    char pszBuffer[512] = { 0 };
    int iMaxCount = MAX_BARCODE_AMOUNT;
    int iIndex = 0;
    ReaderOptions ro = { 0 };
    int iRet = -1;
    char * pszTemp = NULL;
    unsigned __int64 ullTimeBegin = 0;
    unsigned __int64 ullTimeEnd = 0;
    size_t iLen = 0;
    FILE* fp = NULL;
    int iExitFlag = 0;
 
    // Set license
    CBarcodeReader reader;
    reader.InitLicense("38B9B94D8B0E2B41FDE1FB60861C28C0");
 
    // Read barcode
    ullTimeBegin = GetTickCount();
    ro.llBarcodeFormat = llFormat;
    ro.iMaxBarcodesNumPerPage = iMaxCount;
    reader.SetReaderOptions(ro);
    iRet = reader.DecodeFile(pszFileName);
    ullTimeEnd = GetTickCount();
 
    // Output barcode result
    pszTemp = (char*)malloc(4096);
    if (iRet != DBR_OK && iRet != DBRERR_LICENSE_EXPIRED && iRet != DBRERR_QR_LICENSE_INVALID &&
        iRet != DBRERR_1D_LICENSE_INVALID && iRet != DBRERR_PDF417_LICENSE_INVALID && iRet != DBRERR_DATAMATRIX_LICENSE_INVALID)
    {
        sprintf_s(pszTemp, 4096, "Failed to read barcode: %s\r\n", DBR_GetErrorString(iRet));
        printf(pszTemp);
        free(pszTemp);
        return NULL;
    }
 
    pBarcodeResultArray paryResult = NULL;
    reader.GetBarcodes(&paryResult);
 
    if (paryResult->iBarcodeCount == 0)
    {
        sprintf_s(pszTemp, 4096, "No barcode found. Total time spent: %.3f seconds.\r\n", ((float)(ullTimeEnd - ullTimeBegin) / 1000));
        printf(pszTemp);
        free(pszTemp);
        reader.FreeBarcodeResults(&paryResult);
        return NULL;
    }
 
    sprintf_s(pszTemp, 4096, "Total barcode(s) found: %d. Total time spent: %.3f seconds\r\n\r\n", paryResult->iBarcodeCount, ((float)(ullTimeEnd - ullTimeBegin) / 1000));
    //printf(pszTemp);
 
    values = (char **)malloc((paryResult->iBarcodeCount + 1) * sizeof(char *));
 
    for (iIndex = 0; iIndex < paryResult->iBarcodeCount; iIndex++)
    {
        char* pszValue = (char*)calloc(paryResult->ppBarcodes[iIndex]->iBarcodeDataLength + 1, sizeof(char));
        memcpy(pszValue, paryResult->ppBarcodes[iIndex]->pBarcodeData, paryResult->ppBarcodes[iIndex]->iBarcodeDataLength);
        values[iIndex] = pszValue;
    }
 
    free(pszTemp);
    reader.FreeBarcodeResults(&paryResult);
    values[iIndex] = NULL;
    *out_len = iIndex;
 
    return values;
}

把返回的数据封装到Dart_CObjects中:

void wrappedBarcodeReader(Dart_Port dest_port_id,
    Dart_CObject* message) {
    Dart_Port reply_port_id = ILLEGAL_PORT;
    if (message->type == Dart_CObject_kArray &&
        2 == message->value.as_array.length) {
        // Use .as_array and .as_int32 to access the data in the Dart_CObject.
        Dart_CObject* param0 = message->value.as_array.values[0];
        Dart_CObject* param1 = message->value.as_array.values[1];
 
        if (param0->type == Dart_CObject_kString &&
            param1->type == Dart_CObject_kSendPort) {
            char * pszFileName = param0->value.as_string;
            reply_port_id = param1->value.as_send_port.id;
 
            int length = 0;
            char **values = readBarcode(pszFileName, &length);
            char **pStart = values;
            if (values != NULL) {
                Dart_CObject* results[MAX_BARCODE_AMOUNT];
                Dart_CObject collection[MAX_BARCODE_AMOUNT];
                int index = 0;
                char * pszValue = NULL;
                while ((pszValue = *pStart) != NULL) {
                    Dart_CObject value;
                    value.type = Dart_CObject_kString;
                    value.value.as_string = pszValue;
                    collection[index] = value;
 
                    ++pStart;
                    ++index;
                }
 
                for (int i = 0; i < length; i++) {
                    results[i] = &(collection[i]);
                }
 
                Dart_CObject message;
                message.type = Dart_CObject_kArray;
                message.value.as_array.length = length;
                message.value.as_array.values = results;
                Dart_PostCObject(reply_port_id, &message);
                freeString(values);
 
                return;
            }
        }
    }
    Dart_CObject result;
    result.type = Dart_CObject_kNull;
    Dart_PostCObject(reply_port_id, &result);
}

打开dart_native_api.h查看Dart_CObjects 是如何定义的:

typedef struct _Dart_CObject {
  Dart_CObject_Type type;
  union {
    bool as_bool;
    int32_t as_int32;
    int64_t as_int64;
    double as_double;
    char* as_string;
    struct {
      bool neg;
      intptr_t used;
      struct _Dart_CObject* digits;
    } as_bigint;
    struct {
      Dart_Port id;
      Dart_Port origin_id;
    } as_send_port;
    struct {
      int64_t id;
    } as_capability;
    struct {
      intptr_t length;
      struct _Dart_CObject** values;
    } as_array;
    struct {
      Dart_TypedData_Type type;
      intptr_t length;
      uint8_t* values;
    } as_typed_data;
    struct {
      Dart_TypedData_Type type;
      intptr_t length;
      uint8_t* data;
      void* peer;
      Dart_WeakPersistentHandleFinalizer callback;
    } as_external_typed_data;
  } value;
} Dart_CObject;

设置端口:

void barcodeReaderServicePort(Dart_NativeArguments arguments) {
    Dart_EnterScope();
    Dart_SetReturnValue(arguments, Dart_Null());
    Dart_Port service_port =
        Dart_NewNativePort("BarcodeReaderService", wrappedBarcodeReader, true);
    if (service_port != ILLEGAL_PORT) {
        Dart_Handle send_port = HandleError(Dart_NewSendPort(service_port));
        Dart_SetReturnValue(arguments, send_port);
    }
    Dart_ExitScope();
}

编译工程生成sample_extension.dll。拷贝sample_asynchronous_extension.dartsample_extension.dllDynamsoftBarcodeReaderx64.dll到同一个目录:

Dart native extension

创建barcode_reader.dart测试Dart异步扩展:

import 'sample_asynchronous_extension.dart';
 
void main() {
  BarcodeReader reader = new BarcodeReader();
  reader.readBarcode(r'f:\AllSupportedBarcodeTypes.bmp').then((values) {
    if (values != null) {
      for (var number in values) {
        print(number);
      }
    }
  });
}

 

Dart console barcode reader

源码

https://github.com/yushulx/dart-native-extension

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值