如何使用dart:ffi调用返回函数指针的C++函数?
用dart:ffi调用带函数指针的C++函数指南
1. 导入必要的dart:ffi库
在Dart文件开头导入相关依赖:
import 'dart:ffi'; import 'package:ffi/ffi.dart'; // 提供字符串转换、内存管理的扩展方法
2. 定义C类型对应的FFI Typedef
将C++中的函数指针和导出函数映射为Dart可识别的类型:
2.1 映射unmanaged_callback_ptr
对应C++中void* (*unmanaged_callback_ptr)(const char*, const char*):
// 原生函数指针的底层定义 typedef UnmanagedCallbackNative = Pointer<Void> Function(Pointer<Utf8>, Pointer<Utf8>); // Dart侧可调用的函数类型 typedef UnmanagedCallback = Pointer<Void> Function(Pointer<Utf8>, Pointer<Utf8>);
2.2 映射managed_direct_method_ptr
对应C++中char* (*managed_direct_method_ptr)(const char*, const char*, unmanaged_callback_ptr):
// 原生函数指针的底层定义 typedef ManagedDirectMethodNative = Pointer<Utf8> Function( Pointer<Utf8>, Pointer<Utf8>, Pointer<NativeFunction<UnmanagedCallbackNative>>, ); // Dart侧可调用的函数类型 typedef ManagedDirectMethod = Pointer<Utf8> Function( Pointer<Utf8>, Pointer<Utf8>, UnmanagedCallback, );
2.3 映射C++导出函数
分别映射CreateManagedDelegate和InvokeManagedFunction:
// 映射CreateManagedDelegate函数 typedef CreateManagedDelegateNative = Pointer<NativeFunction<ManagedDirectMethodNative>> Function( Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, ); typedef CreateManagedDelegate = Pointer<NativeFunction<ManagedDirectMethodNative>> Function( Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, ); // 映射InvokeManagedFunction函数 typedef InvokeManagedFunctionNative = Pointer<Utf8> Function( Pointer<Utf8>, Pointer<Utf8>, Pointer<NativeFunction<UnmanagedCallbackNative>>, ); typedef InvokeManagedFunction = Pointer<Utf8> Function( Pointer<Utf8>, Pointer<Utf8>, UnmanagedCallback, );
3. 加载动态库并绑定函数
根据平台加载对应的C++动态库(Windows为.dll,Linux为.so,macOS为.dylib):
// 替换为你的动态库路径 final DynamicLibrary lib = DynamicLibrary.open('libcpplib.so'); // 绑定CreateManagedDelegate final CreateManagedDelegate createManagedDelegate = lib.lookupFunction<CreateManagedDelegateNative, CreateManagedDelegate>( 'CreateManagedDelegate', ); // 绑定InvokeManagedFunction final InvokeManagedFunction invokeManagedFunction = lib.lookupFunction<InvokeManagedFunctionNative, InvokeManagedFunction>( 'InvokeManagedFunction', );
4. 处理CreateManagedDelegate返回的函数指针
调用C++函数获取原生函数指针后,转换为Dart可调用的函数:
// 将Dart字符串转换为C兼容的Utf8指针 final Pointer<Utf8> libName = 'your_lib_name'.toNativeUtf8(); final Pointer<Utf8> typeName = 'your_type_name'.toNativeUtf8(); final Pointer<Utf8> methodName = 'your_method_name'.toNativeUtf8(); // 调用C++函数获取原生函数指针 final Pointer<NativeFunction<ManagedDirectMethodNative>> nativeMethodPtr = createManagedDelegate( libName, typeName, methodName, ); // 转换为Dart可直接调用的函数 final ManagedDirectMethod managedMethod = nativeMethodPtr.asFunction<ManagedDirectMethod>(); // 释放临时内存,避免泄漏 calloc.free(libName); calloc.free(typeName); calloc.free(methodName);
5. 定义并传递回调函数
回调函数必须是顶级函数或静态函数,防止被Dart GC回收导致崩溃:
// 符合UnmanagedCallback类型的回调函数 Pointer<Void> myUnmanagedCallback(Pointer<Utf8> arg1, Pointer<Utf8> arg2) { // 将C字符串转换为Dart字符串 final String strArg1 = arg1.toDartString(); final String strArg2 = arg2.toDartString(); // 业务逻辑处理 print('回调收到参数:$strArg1, $strArg2'); // 返回void*类型,无需返回值时返回nullptr return nullptr; }
调用获取到的managedMethod并传入回调:
// 准备调用参数 final Pointer<Utf8> arg1 = 'param1'.toNativeUtf8(); final Pointer<Utf8> arg2 = 'param2'.toNativeUtf8(); // 调用托管方法 final Pointer<Utf8> resultPtr = managedMethod(arg1, arg2, myUnmanagedCallback); // 处理返回结果 final String result = resultPtr.toDartString(); print('调用结果:$result'); // 释放内存 calloc.free(arg1); calloc.free(arg2); calloc.free(resultPtr); // 需确认C侧是否由Dart负责释放该内存
6. 调用InvokeManagedFunction示例
直接调用该函数并传递回调:
final Pointer<Utf8> funcName = 'target_func'.toNativeUtf8(); final Pointer<Utf8> funcArgs = 'func_args'.toNativeUtf8(); final Pointer<Utf8> invokeResult = invokeManagedFunction(funcName, funcArgs, myUnmanagedCallback); print('Invoke结果:${invokeResult.toDartString()}'); // 释放内存 calloc.free(funcName); calloc.free(funcArgs); calloc.free(invokeResult);
关键注意事项
- 内存管理:所有通过
toNativeUtf8()创建的指针必须用calloc.free()释放;C++返回的指针需明确内存归属,避免泄漏。 - 回调存活:回调函数需保持存活(如存为全局变量),禁止使用匿名函数或实例方法,防止被GC回收。
- 平台适配:动态库文件名需根据运行平台调整,可通过
Platform.isWindows等条件分支处理。
内容的提问来源于stack exchange,提问作者BND
相关产品推荐
相关产品推荐

