Dart 如何使用C語言函式庫 (Windows)

閱讀時間約 54 分鐘
  雖然Dart 語言本身支援跨平台的編譯方式,但在實務開發時還是不免需要使用外部非Dart語言所提供的函式庫進行功能開發且由於C 語言是最為廣泛且通用的程式語言,因此Dart語言也有提供支援與C語言函式庫互通性的方式;本篇主要是以MSVC作為C的編譯器來實作說明如何引用C語言會遇到的作法。

1.  動態載入C語言函式庫

  與一般C語言載入函式庫的方式相同在Dart語言中載入C函式語言函式庫同樣是操作流程: 1) 定義函式指標  2 ) 開啟C函式庫  3) 查找函式位址
#include <windows.h> 
 
// 1. Define function pointer for imported function prototypes.
typedef BOOL(__cdecl* CreateClassInstanceProc) (__inout HANDLE* ClassHandle);
// 2. Open and load DLL  
HINSTANCE hinstLib = LoadLibrary(TEXT("crosscode_wrapc_lib.dll"));
// 3. Find function addresses in loadded DLLs.
CreateClassInstanceProc CCIP =
  (CreateClassInstanceProc) GetProcAddress(hinstLib, "CreateClassInstance");
  而在Dart 語言中要完成上述載入函式庫的流程則需要先引用dart:ffi文件,且由於在dart:ffi中定義的NativeType資料格式與Dart中所對應的資料格式不完全對應,因此定義C函式指標需要同時以Dart 資料格式定義函式指標和以NativeType資料格式定義函式指標來進行對照。
import 'dart:ffi'
 
// 1. Define function pointer for imported function prototypes.
typedef CreateClassInstanceForNative = Int32 Function(Pointer classHandle);
typedef CreateClassInstanceForDarte = int Function(Pointer classHandle);
// 2. Open and load DLL  
final _wrapc_lib = 
  DynamicLibrary.open("crosscode_wrapc_lib.dll");
// 3. Find function addresses in loadded DLLs.
final createClassInstanceProc = _wrapc_lib.lookupFunction<CreateClassInstanceForNative, CreateClassInstanceForDarte>('CreateClassInstance');

2.  定義資料結構

  在引用C函數庫時常需要使用其定義的相關資結構作為傳遞參數則如何在Dart 語言中定義C函數可接受的資料結構是另一個主要的問題;本節將會自訂包含多個常用資料格式 (wchar_t, array, function pointer ... etc.) 的C語言資料結構並以此資料結構作為參數建立相關的函式來測試Dart語言轉換C語言資料結構的方法。   
typedef bool (*CallbackFunc)(double* pDoubleArray);
typedef bool (*CopyStructCallbackFunc)(PVOID pStruct);
typedef struct _UnrestrictedAlignmentStruct {
  int	intField;
  TCHAR charField;
  CallbackFunc funcptrField;
  float floatField;
  wchar_t stringField[15];
  double dubaryField[10];
} UnrestrictedAlignmentStruct, * pUnrestrictedAlignmentStruct;
#pragma pack(push, 1)
typedef struct _RestrictedAlignmentStruct {
  int	intField;
  TCHAR charField;
  CallbackFunc funcptrField;
  float floatField;
  wchar_t stringField[15];
  double dubaryField[10];
} RestrictedAlignmentStruct, *pRestrictedAlignmentStruct;
#pragma pack(pop)
  要在Dart語言中定義符合C函數的資料結構要使用 dart:ffi 文件中所定義的NativeType資料格式,在Dart語言中使用NativeType定義與C語言函式互通的資料結構需要特別指定Dart資料格式與NativeType資料格式的對照格式。
import 'dart:ffi';
typedef CallbackFuncForDart = int Function( Pointer<Double> pDoubleArray);
typedef CallbackFuncForFFI = Uint32 Function(Pointer<Double> pDoubleArray);
typedef CopyStructCallbackFuncForFFI = Bool Function(Pointer pStruct);
class UnrestrictedAlignmentStruct extends Struct {
  @Int32()
  external int intField;  
  @Uint16()
  external int charField;  
  external Pointer<NativeFunction<CallbackFuncForFFI>> funcptrField;  
  @Float()
  external double floatField;  
  @Array(15)
  external Array<Int16> stringField;  
  @Array(10)
  external Array<Double> dubaryField; 
}
@Packed(1)
class RestrictedAlignmentStruct extends Struct {
  @Int32()
  external int intField;
  @Int16()
  external int charField;  
  external Pointer<NativeFunction<CallbackFuncForFFI>> funcptrField;  
  @Float()
  external double floatField;
  @Array(15)
  external Array<Int16> stringField;
  @Array(10)
  external Array<Double> dubaryField; 
}

3.  實作測試函式

  為了確認上述定義的資料結構與C語言函式庫是否能正確的傳遞與讀取資料結構的資訊,因此特別針常發生的使用情境定義下列其相應的函式進行驗證與實際執行的方式。

  3-1.  記憶體配置的長度

    由於在不同的程式語言中定義的資料結構可能因為其資料格式的長度差異而佔用的記憶體配置的大小不同而造成資料在轉換兩種不同的語言中傳遞錯誤;因此定義回傳在C語言函式中資料結構的記憶體配置長度的函式與Dart語言中相同資料結構是否為相同長度。
// Create a data struct in C executables
UnrestrictedAlignmentStruct sUnrestrictedAlignmentStruct = { 0 };
// Define the function prototype of the C library
typedef int(__stdcall* GetSizeOfUnrestrictedAlignmentStructProc) 
        (HANDLE pClassHandle, UnrestrictedAlignmentStruct sStrut);
// Find the the pointer of function in the C library
GetSizeOfUnrestrictedAlignmentStructProc getSizeOfUnrestrictedAlignmentStructProc =
        (GetSizeOfUnrestrictedAlignmentStructProc)GetProcAddress(hinstLib, "GetSizeOfUnrestrictedAlignmentStruct");
                  
// Display the memory size of data structures in executeables and libraries.
wprintf(L"Used memory size of an unrestricted alignment struct in execute(%llu) and library(%d)\n", 
        sizeof(sUnrestrictedAlignmentStruct),
        getSizeOfUnrestrictedAlignmentStructProc(hinstLib, sUnrestrictedAlignmentStruct));
// Create a data struct in Dart executables
final sUnrestrictedAlignmentStruct = calloc<UnrestrictedAlignmentStruct>()
// Define the function prototype of the C library
typedef GetSizeOfUnrestrictedAlignmentStructProcForNative = 
    int Function(Pointer classHandle,RestrictedAlignmentStruct confirmStrut);
typedef GetSizeOfUnrestrictedAlignmentStructProcForDart = 
    Int32 Function(Pointer classHandle,RestrictedAlignmentStruct confirmStrut);
// Find the the pointer of function in the C library
late final getSizeOfUnrestrictedAlignmentStructProc = _wrapc_lib.lookupFunction<
    GetSizeOfUnrestrictedAlignmentStructProcForDart,
    GetSizeOfUnrestrictedAlignmentStructProcForNative
  >('GetSizeOfUnrestrictedAlignmentStructProc');
// Display the memory size of data structures in executeables and libraries.
int retSize = getSizeOfUnrestrictedAlignmentStructProc(classHandle.value, sUnrestrictedAlignmentStruct.ref);
print("Used memory size of an unrestricted alignment struct in execute(${sizeOf<UnrestrictedAlignmentStruct>()}) and library( $retSize)");

  3-2.  字元轉換的正確性    

    由於不同程式語言可能採用的預設字元編碼(utf16, utf6, unicode... etc.)不同而可能造成函式在傳送與接送字串因編碼錯誤而造成判斷有誤甚至是造成執行崩潰(crash)或執行錯誤的情況,因此在C函式庫中定義函式用於判斷傳遞的資料結構的字串與函式庫中字串是否相同。
// Build and initial data structure in the C executable.
static const TCHAR* pCmpStr = L"Test String";
UnrestrictedAlignmentStruct sUnrestrictedAlignmentStruct = { 0 };
wcsncpy_s(sUnrestrictedAlignmentStruct.stringField, wcslen(pCmpStr) + 1, pCmpStr, sizeof(sUnrestrictedAlignmentStruct.stringField));
// Define the function prototype of the C library.
typedef bool (__stdcall* CompareStringOfUnrestrictedAlignmentStructProc)
      (HANDLE pClassHandle, pUnrestrictedAlignmentStruct pStrut);
// Find the the pointer of function in the C library.
CompareStringOfUnrestrictedAlignmentStructProc compareUnrestrictedAlignmentStructProc =
      (CompareStringOfUnrestrictedAlignmentStructProc)GetProcAddress(hinstLib, "CompareStringOfUnrestrictedAlignmentStruct");
        
// Compare the string of data structure in the C library.
wprintf(L"Compare string in C library : %s\n",
      compareUnrestrictedAlignmentStructProc(hinstLib, &sUnrestrictedAlignmentStruct) == 1 ? L"True " : L"False");
// Convert string to int array and copy to the stringField of structure.
extension StringArrayFill<T> on Array<Int16> {
  void fillFromList(List<T> list) {
    for (var i = 0; i < list.length; i++) {
      this[i] = list[i] as int;
}}}
// Build and initial data structure in the Dart executable.
final String pCmpStr = "Test String";
final sUnrestrictedAlignmentStruct = calloc<UnrestrictedAlignmentStruct>()
    ..ref.stringField.fillFromList(pCmpStr.codeUnits);
// Define the function prototype of the C library.
typedef CompareStringOfUnrestrictedAlignmentStructProcForNative = int Function(Pointer classHandle,Pointer<UnrestrictedAlignmentStruct> pStruct);
typedef CompareStringOfUnrestrictedAlignmentStructProcForDart = Int32 Function(Pointer classHandle,Pointer<UnrestrictedAlignmentStruct> pStruct);
// Find the the pointer of function in the C library.
late final compareStringOfUnrestrictedAlignmentStructProc = _wrapc_lib.lookupFunction<
    CompareStringOfUnrestrictedAlignmentStructProcForDart,
    CompareStringOfUnrestrictedAlignmentStructProcForNative
  >('CompareStringOfUnrestrictedAlignmentStruct');
// Compare the string of data structure in the C library
String isSame = compareStringOfUnrestrictedAlignmentStructProc(classHandle.value, sUnrestrictedAlignmentStruct) == 1 ? "True" : "False";  
print("Compare string in C library : $isSame&quot;);   

  3-3.  回調函數的執行

    回調函數是一種常用於程式與程式之間互相建立傳遞通知訊息的手段,且由於是傳遞函式的指標位置且不同的程式語言對於函式參數載入與讀取的方式也不盡相同,因此若在轉換過程中發生誤差則可能造成執行崩潰(crash)或執行錯誤的情況,所以在函式庫中定義函式來執行資料結構中的回調函數。
// Define the prototype of the callback function
typedef int (*CallbackFunc)(double* pDoubleArray);
typedef bool (*CopyStructCallbackFunc)(PVOID pStruct);
// Define the callback function of data structure.
int comparArray(double *cmpArray) {
  for (int i = 0; i < 10; i++) {
    if (cmpArray[i] != notifyDouble[i]) 
      return 0;
  }
  return 1;
}
// Define double array 
static double notifyDouble[] = {
  0, 0.1, 2.2, 3.33, 44.44, 55.555, 666.666, 777.7777,
  8888.8888, 99999.9999 };
// Define the function prototype of the C library.
typedef bool(__stdcall* NotifyCallbackOfUnrestrictedAlignmentStructProc)
      (HANDLE pClassHandle, pUnrestrictedAlignmentStruct pStruct);
// Build and initial data structure in the C executable.
UnrestrictedAlignmentStruct sUnrestrictedAlignmentStruct = { 0 };
sUnrestrictedAlignmentStruct.funcptrField = comparArray;
for (int i = 0; i < 10; i++) {
  sUnrestrictedAlignmentStruct.dubaryField[i] = notifyDouble[i];
}
// Find the the pointer of function in the C library.
NotifyCallbackOfUnrestrictedAlignmentStructProc notifyCallbackOfUnrestrictedAlignmentStructProc =
      (NotifyCallbackOfUnrestrictedAlignmentStructProc)GetProcAddress(hinstLib, "NotifyCallbackOfUnrestrictedAlignmentStruct");
  
// Execute callback function for unrestricted alignment structure in C library.
wprintf(L"Execute callback function in C library : %d\n", 
      notifyCallbackOfUnrestrictedAlignmentStructProc(hinstLib, &sUnrestrictedAlignmentStruct));
// Define the prototype of the callback function
typedef CallbackFuncForDart = int Function( Pointer<Double> pDoubleArray);
typedef CallbackFuncForFFI = Uint32 Function(Pointer<Double> pDoubleArray);
typedef CopyStructCallbackFuncForFFI = Bool Function(Pointer pStruct);
// Define the callback function of data structure.
int checkArray(List<double> cmpArray){
  for (int i =0; i < cmpArray.length;i++){
    if (cmpArray.elementAt(i) != notifyDouble.elementAt(i)) {  
      return 0;
  }}
  return 1;
}
// Define double array 
final List<double> notifyDouble = [ 0, 0.1, 2.2, 3.33, 44.44, 55.555, 666.666, 777.7777,
    8888.8888, 99999.9999];
// Define the function prototype of the C library.
typedef NotifyCallbackOfUnrestrictedAlignmentStructProcForNative = Int32 Function(Pointer pClassHandle, Pointer<UnrestrictedAlignmentStruct> pStruct);
typedef NotifyCallbackOfUnrestrictedAlignmentStructProcForDart = int Function(Pointer pClassHandle, Pointer<UnrestrictedAlignmentStruct> pStruct);
// Build and initial data structure in the Dart executable.
final sUnrestrictedAlignmentStruct = calloc<UnrestrictedAlignmentStruct>()
    ..ref.funcptrField = Pointer.fromFunction<CallbackFuncForFFI>(comparArray, 0)      
// Find the the pointer of function in the C library.
late final notifyCallbackOfUnrestrictedAlignmentStructProc = wrapclib.lookupFunction<
    NotifyCallbackOfUnrestrictedAlignmentStructProcForNative,
    NotifyCallbackOfUnrestrictedAlignmentStructProcForDart
  >('NotifyCallbackOfUnrestrictedAlignmentStruct');
// Execute callback function for unrestricted alignment structure in C library.
isSame = notifyCallbackOfUnrestrictedAlignmentStructProc(classHandle.value, sUnrestrictedAlignmentStruct) == 1 ? "True":"False";
print("Execute callback function in C library : $isSame");

  3-4.  驗證資料結構的資料

     由於資料結構可能由許多不同的資料格式所組成,因此可能在傳遞時發生部份資料內容有錯誤,所以在函式庫中定義複製資料結構的函式並透過回調函式回傳至執行檔中顯示其複製結果。
// Define a callback function to display replicated data. 
bool getUnrestrictedAlignmentStructProc(PVOID pStruct) {    
  pUnrestrictedAlignmentStruct pUAS = (pUnrestrictedAlignmentStruct) pStruct;
  wprintf(L"stringField : %s    floatField : %f     intField : %d     charField : %c \n",
        
  pUAS->stringField, pUAS->floatField, pUAS->intField, pUAS->charField);
  wprintf(L"Verify the data of dubaryField : %s\n", comparArray(pUAS->dubaryField) == 1 ? L"True" : L"False");
  bool bRetVal = pUAS->funcptrField(notifyDouble) == 1;
  wprintf(L"Execute the function porinter of pointerField : %s", bRetVal ? L"True" : L"False");
  return bRetVal;
}
// Define the function prototype of the C library.
typedef bool(__stdcall* CopyDataOfUnrestrictedAlignmentStructWithCallbackProc) 
      (HANDLE pClassHandle, UnrestrictedAlignmentStruct sStruct, CopyStructCallbackFunc pCopyCallbackFunc);
// Build and initial data structure in the C executable.
UnrestrictedAlignmentStruct sUnrestrictedAlignmentStruct = { 0 };
sUnrestrictedAlignmentStruct.charField = 'A';
sUnrestrictedAlignmentStruct.floatField = 456.123f;
sUnrestrictedAlignmentStruct.intField = 123;
sUnrestrictedAlignmentStruct.funcptrField = comparArray;
wcsncpy_s(sUnrestrictedAlignmentStruct.stringField, wcslen(pCmpStr) + 1, pCmpStr, sizeof(sUnrestrictedAlignmentStruct.stringField));
for (int i = 0; i < 10; i++) {
  sUnrestrictedAlignmentStruct.dubaryField[i] = notifyDouble[i];
}
// Find the the pointer of function in the C library.
CopyDataOfUnrestrictedAlignmentStructWithCallbackProc copyDataOfUnrestrictedAlignmentStructWithCallbackProc =
      (CopyDataOfUnrestrictedAlignmentStructWithCallbackProc) GetProcAddress(hinstLib, "CopyDataOfUnrestrictedAlignmentStructWithCallback");
       
// Validate each field of the replicated data structure in C library.
wprintf(L"\nCopy structure data in C library : %d\n", 
      copyDataOfUnrestrictedAlignmentStructWithCallbackProc(hinstLib, sUnrestrictedAlignmentStruct, getUnrestrictedAlignmentStructProc));
// Define a callback function to display replicated data. 
int getUnrestrictedAlignmentStructProc(Pointer pStruct){
  int iRetVal = 0;
  var pUAS = pStruct.cast<UnrestrictedAlignmentStruct>();
  List<int> strList = [];
  List<double> doubleList =[] ;

  pUAS.ref.dubaryField.fillFromArray(doubleList,10);
  pUAS.ref.stringField.fillFromArray(strList, 15);
  print ('stringField : ${String.fromCharCodes (strList)} floatField : ${pUAS.ref.floatField} intField : ${pUAS.ref.intField} charField : ${String.fromCharCode(pUAS.ref.charField)}');

  var pPassParm = calloc.allocate<Double>(sizeOf<Double>() * 10);
  for (int i = 0;i<10;i++) {
    pPassParm[i] = doubleList[i];
  }

  String isSame = comparArray(pPassParm) == 1 ? "True" : "False";
  print("Verify the data of dubaryField : $isSame");

  final callbackFuncProc = pUAS.ref.funcptrField
      .cast<NativeFunction<CallbackFuncForFFI>>().asFunction<CallbackFuncForDart>();

  iRetVal = callbackFuncProc(pPassParm);
  isSame = iRetVal == 1 ? "True" : "False";
  print ("Execute the function porinter of pointerField : $isSame");

  calloc.free(pPassParm);
  return iRetVal;
}
// Define the function prototype of the C library.
typedef CopyDataOfRestrictedAlignmentStructWithCallbackProcForNative = Int32 Function(Pointer classHandle, RestrictedAlignmentStruct sStruct, Pointer<NativeFunction<CopyStructCallbackFuncForFFI>> pCopyCallbackFunc);
typedef CopyDataOfRestrictedAlignmentStructWithCallbackProcForDart = int Function(Pointer classHandle, RestrictedAlignmentStruct sStruct, Pointer<NativeFunction<CopyStructCallbackFuncForFFI>> pCopyCallbackFunc);
 
// Build and initial data structure in the Dart executable.
final sUnrestrictedAlignmentStruct = calloc<UnrestrictedAlignmentStruct>()
      ..ref.charField = 'A'.codeUnitAt(0)     
      ..ref.floatField = 456.123
      ..ref.intField = 123
      ..ref.funcptrField = Pointer.fromFunction<CallbackFuncForFFI>(comparArray, 0)       
      ..ref.stringField.fillFromList(pCmpStr.codeUnits)
      ..ref.dubaryField.fillFromList(notifyDouble);   
// Find the the pointer of function in the C library.
late final copyDataOfUnrestrictedAlignmentStructWithCallbackProc = wrapclib.lookupFunction<
    CopyDataOfUnrestrictedAlignmentStructWithCallbackProcForNative,
    CopyDataOfUnrestrictedAlignmentStructWithCallbackProcForDart
  >('CopyDataOfUnrestrictedAlignmentStructWithCallback');
// Validate each field of the replicated data structure in C library.
isSame =  copyDataOfUnrestrictedAlignmentStructWithCallbackProc(
        classHandle.value, 
        sUnrestrictedAlignmentStruct.ref, 
        Pointer.fromFunction<CopyStructCallbackFuncForFFI>(getUnrestrictedAlignmentStructProc, false)
      ) == 1 ? "True" : "False";     
print("Copy structure data in C library : $isSame");

  3-5.  回傳資料結構的完整性

    C 語言對於資料結構的記憶體配置規則可藉由設定 pack 的方式來進行調整且若配置規則不一致時會影響資料轉換後函式引用,而dart:ffi 對於資料結構也有提供調整記憶體配置的方式以避免與 C 語言函數所建立的資料結構有所差異而導致資料結構的不完整,因此分別定義使用設定預定對齊格式的資料結構進行來驗證是否能正確執行C函式庫中的函式。
// Default alignment according to computer architecture.
typedef struct _UnrestrictedAlignmentStruct {
    int intField;
    TCHAR charField;
    CallbackFunc funcptrField;
    float floatField;
    wchar_t stringField[15];
    double dubaryField[10];
} UnrestrictedAlignmentStruct, * pUnrestrictedAlignmentStruct;
// Default alignment according to pack function.
#pragma pack(push, 1)
typedef struct _RestrictedAlignmentStruct {
    int intField;
    TCHAR charField;
    CallbackFunc funcptrField;
    float floatField;
    wchar_t stringField[15];
    double dubaryField[10];
} RestrictedAlignmentStruct, *pRestrictedAlignmentStruct;
#pragma pack(pop)
// Default alignment according to computer architecture.
class UnrestrictedAlignmentStruct  extends Struct {
  @Int32()
  external int intField;
  @Uint16()
  external int charField;  
  external Pointer<NativeFunction<CallbackFuncForFFI>> funcptrField;
  @Float()
  external double floatField;
  @Array(15)
  external Array<Int16> stringField;
  @Array(10)
  external Array<Double> dubaryField; 
}
// Default alignment according to pack function.
@Packed(1)
class RestrictedAlignmentStruct  extends Struct {
  @Int32()
  external int intField;
  @Int16()
  external int charField;  
  external Pointer<NativeFunction<CallbackFuncForFFI>> funcptrField;
  @Float()
  external double floatField;
  @Array(15)
  external Array<Int16> stringField;
  @Array(10)
  external Array<Double> dubaryField; 
}

4.  自動轉換C語言標頭檔套件

  在pub.dev中有提供將C語言標頭檔的內容自動轉換成Dart語言所支援dart:ffi中定義的NativeType資料格式的工具套件。

  4-1.  設定流程

    1.  環境需求
     使用FFIGEN套件前需要先行安裝Visual Studio With C++ 與LLVM套件並在開發專案的pubspec.yaml文件中設定安裝ffigen套件,才能正常的執行其套件功能。
Install Visual Studio C++
wingetinstall -e --id LLVM.LLVMll
LLVM 安裝路徑
// pubspec.yaml
dev_dependencies:
  ffigen: ^4.0.0
    
    2.  新增FFIGEN套件的組態檔
    新增FFIGEN轉換的組態檔,ffigen提供下列兩種設定的方式:
    2-1. 新增ffigen專屬的yaml檔案並搭配 --config 參數來指定組態檔。
name: AutoConvertByffigen
description: A starting point for Dart libraries or applications.
output: 'lib/crosscode_by_auto.dart'
headers:
  entry-points:   
    - 'third_party/crosscode_wrap_cfunc.h'   
   
  # 只轉換下列的header文件而其內所引用的相關header文件將不會被轉換
  include-directives:  
    - '**crosscode_defstruct.h'
    - '**crosscode_wrap_cfunc.h'
structs:
  include:
    - '.*' 
  exclude:
    - '_ExcludeUnrestrictedAlignmentStruct'  
  # 移除起始"_"符號並加入FFI字串
  rename:
    '_(.*)': 'FFI$1'
# 此選項中只有被引用的typedef才會進行轉換
typedefs:
  # 若要直接引用其原始定義而不要建立其對應的定義
  exclude:
    - 'CallbackFunc2'
    - 'UChar'
  # 將轉換後的定義變數名稱加入ForFFI字串
  rename: 
    '(.*)': '$1'
functions: 
  include:
    - '.*' 
  # 指定排除轉換的函式
  exclude:
    - 'ExcludeFunction' 
# 指定型別對應至NativeType型別  
typedef-map:
  'TCHAR': 'Int16' 
comments:
  style: any
  length: full
preamble:
  /* ************** Cross Code Co.Ltd ********************
  how to auto convert from C to dart by ffigen packages       
  ***************************************************** */
    2-2. 在pubspec.yaml中新增ffigen標籤來設定組態資訊
name: crosscode_wrapc_exe
description: A sample command-line application.
version: 1.0.0
homepage: https://vocus.cc/user/61ca9f1bfd89780001efa2a6
environment:
  sdk: '>=2.15.1 <3.0.0'
dependencies:
  ffi: ^1.1.0
dev_dependencies:
  lints: ^1.0.0
  test: ^1.16.0
  ffigen: ^4.0.0
ffigen:
  name: AutoConvertByffigen
  description: Convert Header file of C to dart file of Dart by ffigen package
  output: 'lib/crosscode_by_auto.dart'
  headers:
    entry-points:   
      - 'third_party/crosscode_wrap_cfunc.h'   
    # 只轉換下列的header文件而其內所引用的相關header文件將不會被轉換
    include-directives:  
      - '**crosscode_defstruct.h'
      - '**crosscode_wrap_cfunc.h'
  structs:
    include:
      - '.*' 
    exclude:
      - '_ExcludeUnrestrictedAlignmentStruct' 
    # 移除起始"_"符號並加入FFI字串
    rename:
      '_(.*)': 'FFI$1'
  # 此選項中只有被引用的typedef才會進行轉換
  typedefs:
    # 若要直接引用其原始定義而不要建立其對應的定義
    exclude:
      - 'CallbackFunc2'
      - 'UChar'
    # 將轉換後的定義變數名稱加入ForFFI字串
    rename: 
      '(.*)': '$1'
  functions: 
    include:
      - '.*' 
    # 指定排除轉換的函式
    exclude:
      - 'ExcludeFunction' 
  # 指定C型別對應至NativeType型別
  typedef-map:
    'TCHAR': 'Int16' 
  comments:
    style: any
    length: full
  preamble:
  /* ************** Cross Code Co.Ltd ********************
    how to auto convert from C to dart by ffigen packages       
  ***************************************************** */
GitHub : https://github.com/crosscode-software/dart_wrap_c
 

留言0
查看全部
avatar-img
發表第一個留言支持創作者!
本範例主要說明如何運用Flutter 繪圖與動態相關的API並搭配provider套件進行實作輪盤賭選擇 ( Roulette Wheel Selection ) 程式。
說明Flutter 模組(Module)專案範例的架構與如何載入Android專案中的流程與執行畫面
說明Flutter 插件(Plugin)專案範例的架構與實際載入並執行在各平台的顯示畫面
說明Flutter 包(Package)專案範例的架構與實際載入並執行在各平台的顯示畫面
說明Flutter 骨架(skeleton)專案範例的架構與在各平台執行的顯示畫面
說明Flutter 應用軟體(Application)專案範例的架構與在各平台執行的顯示畫面
本範例主要說明如何運用Flutter 繪圖與動態相關的API並搭配provider套件進行實作輪盤賭選擇 ( Roulette Wheel Selection ) 程式。
說明Flutter 模組(Module)專案範例的架構與如何載入Android專案中的流程與執行畫面
說明Flutter 插件(Plugin)專案範例的架構與實際載入並執行在各平台的顯示畫面
說明Flutter 包(Package)專案範例的架構與實際載入並執行在各平台的顯示畫面
說明Flutter 骨架(skeleton)專案範例的架構與在各平台執行的顯示畫面
說明Flutter 應用軟體(Application)專案範例的架構與在各平台執行的顯示畫面
你可能也想看
Google News 追蹤
Thumbnail
徵的就是你 🫵 超ㄅㄧㄤˋ 獎品搭配超瞎趴的四大主題,等你踹共啦!還有機會獲得經典的「偉士牌樂高」喔!馬上來參加本次的活動吧!
Thumbnail
隨著理財資訊的普及,越來越多台灣人不再將資產侷限於台股,而是將視野拓展到國際市場。特別是美國市場,其豐富的理財選擇,讓不少人開始思考將資金配置於海外市場的可能性。 然而,要參與美國市場並不只是盲目跟隨標的這麼簡單,而是需要策略和方式,尤其對新手而言,除了選股以外還會遇到語言、開戶流程、Ap
Thumbnail
本文介紹了 Dart 中具有參數的函式。具有參數的函式允許靈活地處理不同輸入,增強程式碼的模組化和可重用性。透過範例說明,讀者能夠理解如何定義和使用這些函式,並掌握進階概念以提升程式設計能力。
Thumbnail
在這篇文章中,我們介紹了 Dart 中的字串資料類型,包括如何使用單引號和雙引號定義字串、如何建立多行字串,以及如何使用字串插入。字串資料型態在處理文字、顯示訊息或進行字串操作時非常實用,開發者可以根據需求靈活運用這些特性。
Thumbnail
這篇內容,將會講解什麼是函式,以及與函式相關的知識。包括函式的簡介、Runtime Function、自訂函式、Script Function 腳本函式、Method 方法。
Thumbnail
本章講述了C#開發中的程序集,命名空間和 NuGet 包管理器。程序集是 .NET 應用的基礎,命名空間用於組織和預防命名衝突,而 NuGet 用於管理 .NET 的外部庫和依賴項。
Thumbnail
本章節旨在介紹 C# 中函數的基本結構,包括訪問修飾符、返回類型、方法名稱、參數列表和方法體。同時,也介紹了函數的各種呼叫方式、參數傳遞方式和返回值類型。讀者可以通過本章節,深入理解 C# 中函數的使用和應用。
Thumbnail
C#程式由一或多個檔案組成,包含命名空間、類別、結構、介面、列舉和委派等型別。Main方法是C#應用程式的進入點。在C#中,註解用於在程式碼中添加說明,有單行和多行兩種類型。變數的定義需要指定變數的類型和名稱,可以一次為多個變數賦值。
Thumbnail
C#是一種開源、跨平台、面向對象的編程語言,具有類型安全、泛型、模式匹配等特性。廣泛應用於桌面和Web應用程序、遊戲開發、移動應用、雲計算等領域。全球數十萬家公司像微軟、Unity Technologies、Stack Overflow等使用C#支持其業務。C#還提供豐富的進階學習資源和主題。
Thumbnail
C 語言的函式庫定義了許多好用的函式,在寫 C++ 的時候可以拿來用。這是因為 C++ 當初在設計的時候,就有刻意把 C 涵蓋進來。 基本用法 首先要導入 C 語言的標準函式庫: #include <cstdlib> 以 c 作為開頭表示它是 C 語言的函式庫,只是被我們拿來 C++ 的程式
Thumbnail
介紹C++ 語法 資料型態,架構說明 程式語言為人類與電腦溝通的工具 程式設計流程: 定義問題 -> 問題分析 -> 撰寫演算法 ->程式撰寫 -> 程式執行及維護
Thumbnail
徵的就是你 🫵 超ㄅㄧㄤˋ 獎品搭配超瞎趴的四大主題,等你踹共啦!還有機會獲得經典的「偉士牌樂高」喔!馬上來參加本次的活動吧!
Thumbnail
隨著理財資訊的普及,越來越多台灣人不再將資產侷限於台股,而是將視野拓展到國際市場。特別是美國市場,其豐富的理財選擇,讓不少人開始思考將資金配置於海外市場的可能性。 然而,要參與美國市場並不只是盲目跟隨標的這麼簡單,而是需要策略和方式,尤其對新手而言,除了選股以外還會遇到語言、開戶流程、Ap
Thumbnail
本文介紹了 Dart 中具有參數的函式。具有參數的函式允許靈活地處理不同輸入,增強程式碼的模組化和可重用性。透過範例說明,讀者能夠理解如何定義和使用這些函式,並掌握進階概念以提升程式設計能力。
Thumbnail
在這篇文章中,我們介紹了 Dart 中的字串資料類型,包括如何使用單引號和雙引號定義字串、如何建立多行字串,以及如何使用字串插入。字串資料型態在處理文字、顯示訊息或進行字串操作時非常實用,開發者可以根據需求靈活運用這些特性。
Thumbnail
這篇內容,將會講解什麼是函式,以及與函式相關的知識。包括函式的簡介、Runtime Function、自訂函式、Script Function 腳本函式、Method 方法。
Thumbnail
本章講述了C#開發中的程序集,命名空間和 NuGet 包管理器。程序集是 .NET 應用的基礎,命名空間用於組織和預防命名衝突,而 NuGet 用於管理 .NET 的外部庫和依賴項。
Thumbnail
本章節旨在介紹 C# 中函數的基本結構,包括訪問修飾符、返回類型、方法名稱、參數列表和方法體。同時,也介紹了函數的各種呼叫方式、參數傳遞方式和返回值類型。讀者可以通過本章節,深入理解 C# 中函數的使用和應用。
Thumbnail
C#程式由一或多個檔案組成,包含命名空間、類別、結構、介面、列舉和委派等型別。Main方法是C#應用程式的進入點。在C#中,註解用於在程式碼中添加說明,有單行和多行兩種類型。變數的定義需要指定變數的類型和名稱,可以一次為多個變數賦值。
Thumbnail
C#是一種開源、跨平台、面向對象的編程語言,具有類型安全、泛型、模式匹配等特性。廣泛應用於桌面和Web應用程序、遊戲開發、移動應用、雲計算等領域。全球數十萬家公司像微軟、Unity Technologies、Stack Overflow等使用C#支持其業務。C#還提供豐富的進階學習資源和主題。
Thumbnail
C 語言的函式庫定義了許多好用的函式,在寫 C++ 的時候可以拿來用。這是因為 C++ 當初在設計的時候,就有刻意把 C 涵蓋進來。 基本用法 首先要導入 C 語言的標準函式庫: #include <cstdlib> 以 c 作為開頭表示它是 C 語言的函式庫,只是被我們拿來 C++ 的程式
Thumbnail
介紹C++ 語法 資料型態,架構說明 程式語言為人類與電腦溝通的工具 程式設計流程: 定義問題 -> 問題分析 -> 撰寫演算法 ->程式撰寫 -> 程式執行及維護