如何向wchar_t*指针参数写入文本(C++导出DLL供Dart调用)
问题说明
需要将C实现的功能打包为DLL导出供Dart调用,核心需求是实现带wchar_t*指针参数的函数,通过该出参向调用方返回文本内容。因不熟悉C指针语法,自行编写的代码存在运行错误,未找到可行解决方案。
原有错误实现逻辑为枚举系统音频设备,将设备信息拼接为宽字符串后写入传入的指针缓冲区。
核心错误点
- 缓冲区长度参数传参错误:
wcscpy_s的第二个参数要求传入缓冲区可容纳的wchar_t元素个数,而测试代码中传入的sizeof(output)是缓冲区的总字节数。Windows平台下单个wchar_t占2字节,1000个元素的数组sizeof计算结果为2000,会导致函数误认为缓冲区长度是实际的2倍,写入时触发内存越界崩溃。 - 宽字符串输出方式错误:
cout是窄字符流,无法正确输出wchar_t*类型的宽字符串,会输出乱码或地址值,宽字符需要使用wcout输出。 - DLL导出配置缺失:给Dart调用的导出函数必须加
extern "C"标识,否则C++编译器会对函数名做名称修饰,Dart侧无法通过原函数名找到导出入口。 - 冗余写法:
listOutput += info.c_str()属于多余操作,std::wstring已经重载了对同类型字符串的拼接运算符,直接传入info对象即可。
修正后代码
#include <iostream> #include <vector> #include <string> // 此处替换为你项目中音频枚举、DeviceProps定义所需的头文件 // 固定加extern "C" 避免C++名称修饰,保证DLL导出函数名和代码中定义一致 extern "C" __declspec(dllexport) void getAudioDevices(wchar_t* output, int outBufferCharCount) { std::vector<DeviceProps> result = EnumAudioDevices(eRender); std::wstring listOutput; if (!result.empty()) { for (const auto& device : result) { std::wstring info; info += device.name; // PCWSTR类型可直接拼接 info += L"\n"; info += device.iconInfo;// PCWSTR类型可直接拼接 info += L"\n"; info += device.id; // LPWSTR类型可直接拼接 info += L"\n"; info += device.isActive ? L"true" : L"false"; info += L"\n[][][][]\n"; listOutput += info; } } // 安全拷贝字符串到传入的缓冲区,自动处理截断和末尾终止符 wcscpy_s(output, outBufferCharCount, listOutput.c_str()); } // 本地测试入口,编译DLL时可通过宏隔离不参与编译 #ifdef LOCAL_DEBUG int wmain(int argc, WCHAR* argv[]) { const int bufCharLen = 1000; WCHAR output[bufCharLen]; // 传入的长度参数为wchar_t元素个数,不是字节数 getAudioDevices(output, bufCharLen); // 宽字符串用wcout输出 wcout << output << std::endl; return 0; } #endif
Dart FFI调用注意事项
- Windows平台下
wchar_t对应UTF-16编码,Dart侧FFI类型映射为Pointer<Utf16>。 - 分配缓冲区时按单个字符2字节计算总内存大小,第二个参数传入分配的缓冲区可容纳的字符个数,和C++侧参数语义保持一致。
- 调用完成后通过
Utf16.fromUtf16()方法将指针内容转为Dart原生String,使用完成后及时释放手动分配的缓冲区内存。
内容的提问来源于stack exchange,提问作者Doger
相关产品推荐
相关产品推荐

