
简介这份资源面向需要在通达信公式环境中处理文本数据的量化开发者与插件编写者聚焦一个具体痛点通达信公式数据以浮点数为主字符串类型无法直接传递必须借助句柄映射机制间接实现。资源包共3个文件包含1个inscode工程配置、1个html说明页面和1个gitignore忽略规则文件整体约6KB属于轻量级源码代码包便于快速导入与查阅。内容围绕字符串函数的工作原理展开给出初始化句柄到字符串的转换函数、由句柄反向获取字符串内容的函数以及一个可实际运行的测试插件并演示如何在公式逻辑中嵌入这些字符串处理能力。已有199人学习适合希望打通通达信DLL插件字符串支持、理解句柄映射思路并直接复用示例代码的开发者参考。1. 通达信 DLL 插件字符串支持一份能直接编译的 C 代码包拆解如果你写过通达信公式大概率遇到过这个场景想把外部数据、自定义指标或者一段业务逻辑塞进通达信里公式语言写起来束手束脚最后只能走 DLL 插件这条路。但真动手写的时候第一个卡住的地方往往不是算法而是字符串——通达信主程序和插件之间的字符串传递参数怎么定义、编码怎么处理、返回值怎么给官方文档语焉不详网上搜到的示例又七零八落。这份「通达信 DLL 插件字符串支持」代码包解决的就是这个具体问题它把插件里字符串输入输出的完整链路拆成了可编译、可调试的源码覆盖了参数声明、编码转换、缓冲区管理这几个最容易翻车的环节。适合已经会写基础 DLL 插件、但被字符串交互卡住的开发者也适合想系统看一眼通达信插件接口长什么样的新手。2. 通达信 DLL 接口的字符串机制从参数表到内存布局2.1 通达信插件函数的参数约定通达信调用 DLL 插件时走的是标准的导出函数约定。一个典型的插件函数签名长这样// 通达信插件标准导出函数原型 extern C __declspec(dllexport) void WINAPI PluginName( int nParamCount, // 参数个数 float* pfParam, // 数值型参数数组 char** ppszParam, // 字符串型参数数组 float* pfResult, // 数值型返回值数组 char** ppszResult, // 字符串型返回值数组 int nResultCount // 返回值个数 );这里的关键在于char** ppszParam和char** ppszResult。通达信传进来的字符串是一个字符指针数组每个元素指向一个以\0结尾的字符串。数值参数走float*字符串参数走char**两条通道是分开的。很多新手第一次写插件把字符串参数当成数值参数去读结果拿到的是指针地址而不是内容这就是没搞清楚内存布局。nParamCount告诉你实际传了几个参数pfParam和ppszParam的下标是对齐的——第 i 个参数如果是数值型从pfParam[i]取如果是字符串型从ppszParam[i]取。通达信不会告诉你哪个参数是哪种类型这个信息得在公式调用端自己保证。常见做法是在公式里用TDXDLL1(1, C, ABC)这种形式第一个参数是功能号后面按约定顺序传数值和字符串。2.2 字符串编码GBK 还是 UTF-8这是血泪经验最集中的地方。通达信主程序在中文 Windows 环境下内部字符串用的是 GBK 编码。你的插件如果按 UTF-8 去解析中文直接变乱码。反过来插件返回给通达信的字符串也必须转成 GBK否则公式端显示出来就是一堆问号。代码包里处理这件事的方式是封装两个转换函数#include windows.h #include string // UTF-8 转 GBK用于插件返回字符串给通达信 std::string Utf8ToGbk(const std::string utf8Str) { if (utf8Str.empty()) return ; // 先转宽字符 int wlen MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, nullptr, 0); std::wstring wstr(wlen, 0); MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, wstr[0], wlen); // 宽字符转 GBK int glen WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr); std::string gbkStr(glen, 0); WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, gbkStr[0], glen, nullptr, nullptr); // 去掉末尾多余的 \0 if (!gbkStr.empty() gbkStr.back() \0) gbkStr.pop_back(); return gbkStr; } // GBK 转 UTF-8用于插件读取通达信传入的字符串 std::string GbkToUtf8(const std::string gbkStr) { if (gbkStr.empty()) return ; int wlen MultiByteToWideChar(CP_ACP, 0, gbkStr.c_str(), -1, nullptr, 0); std::wstring wstr(wlen, 0); MultiByteToWideChar(CP_ACP, 0, gbkStr.c_str(), -1, wstr[0], wlen); int ulen WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr); std::string utf8Str(ulen, 0); WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, utf8Str[0], ulen, nullptr, nullptr); if (!utf8Str.empty() utf8Str.back() \0) utf8Str.pop_back(); return utf8Str; }逻辑说明Windows 的MultiByteToWideChar和WideCharToMultiByte是编码转换的标准 API中间用宽字符UTF-16做桥梁。CP_UTF8和CP_ACP分别指定源和目标编码CP_ACP在当前系统区域设置下就是 GBK。参数-1表示输入字符串以\0结尾函数会自动计算长度。转换后的字符串末尾会多一个\0用pop_back去掉避免拼接时出问题。提示如果你的开发环境默认字符集是 Unicodestd::string里存的可能是 UTF-8也可能是本地编码取决于你怎么赋值。建议在插件入口处统一转成 UTF-8 处理出口处再转回 GBK中间逻辑全部用 UTF-8这样最不容易乱。2.3 返回值缓冲区谁分配、谁释放字符串返回值的处理是另一个高频翻车点。通达信给插件传进来的ppszResult是一个预先分配好缓冲区的字符指针数组插件需要把结果拷贝进去而不是直接修改指针指向。常见错误是直接ppszResult[0] myString.c_str()这样做的后果是函数返回后myString被析构通达信拿到的是野指针轻则乱码重则崩溃。正确的做法是拷贝// 安全地写入字符串返回值 void SafeWriteResult(char** ppszResult, int index, const std::string value) { if (ppszResult nullptr || ppszResult[index] nullptr) return; // 假设通达信分配的缓冲区足够大常见为 256 或 1024 字节 // 这里用 strncpy_s 保证不溢出 strncpy_s(ppszResult[index], 256, value.c_str(), _TRUNCATE); }参数说明ppszResult[index]是通达信分配的缓冲区首地址256是假设的缓冲区大小实际值需要根据通达信版本确认_TRUNCATE表示超长时截断而不是报错。如果你不确定缓冲区大小保守做法是限制返回字符串长度在 200 字节以内。3. 把代码包跑起来编译、注册与公式调用3.1 编译环境与项目配置代码包提供的是 C 源码编译成 DLL 需要 Windows 平台下的编译器。我一般用 Visual Studio 的 MSVC 工具链社区版就够。新建项目时选「动态链接库 (DLL)」把源码文件加进去注意几个配置项配置项推荐值原因平台x86通达信主程序是 32 位插件必须匹配字符集使用多字节字符集避免 Unicode 宏导致的类型不匹配运行库多线程 (/MT)减少对 VC 运行时的依赖分发方便优化最大优化 (/O2)插件被频繁调用性能敏感平台选 x86 是硬性要求。我见过有人编译了 64 位 DLL 然后纳闷为什么通达信加载不了这就是没注意位数匹配。字符集选多字节是因为通达信接口用的是char*如果项目设成 Unicodechar*和TCHAR*的转换会多出一堆麻烦。3.2 导出函数的声明与注册编译出 DLL 后通达信需要知道从哪个函数入口调用。这通过公式里的TDXDLL1、TDXDLL2等函数来绑定。具体步骤第一步确认 DLL 导出了正确的函数名。用dumpbin /exports yourplugin.dll查看应该能看到类似_PluginName24的修饰名。如果用了extern C和__declspec(dllexport)名字会保持 C 风格。第二步把 DLL 放到通达信安装目录下的T0002\dlls文件夹里。这个路径是通达信约定的插件目录放别处它找不到。第三步在公式管理器里新建公式调用方式如下{通达信公式示例调用 DLL 插件处理字符串} DLLNAME : myplugin; PARAM1 : 1; STR1 : 测试输入; RESULT : TDXDLL1(PARAM1, C, STR1);这里的TDXDLL1对应第一个 DLL 入口PARAM1是功能号C是收盘价数值参数示例STR1是字符串参数。插件内部根据功能号决定走哪段逻辑。3.3 一个完整的字符串处理示例代码包里有一个字符串拼接的示例函数逻辑是接收两个字符串参数拼接后返回。核心实现extern C __declspec(dllexport) void WINAPI StrConcat( int nParamCount, float* pfParam, char** ppszParam, float* pfResult, char** ppszResult, int nResultCount) { // 参数校验至少需要两个字符串参数 if (nParamCount 2 || ppszParam nullptr) return; if (ppszParam[0] nullptr || ppszParam[1] nullptr) return; // 读取输入并转 UTF-8 处理 std::string s1 GbkToUtf8(ppszParam[0]); std::string s2 GbkToUtf8(ppszParam[1]); // 业务逻辑拼接 std::string result s1 s2; // 转回 GBK 写入返回值 std::string gbkResult Utf8ToGbk(result); SafeWriteResult(ppszResult, 0, gbkResult); }逻辑说明函数先做参数校验防止空指针导致崩溃。然后从ppszParam读取两个字符串转成 UTF-8 后拼接最后转回 GBK 写入ppszResult[0]。整个过程不修改输入指针不分配需要外部释放的内存是安全的写法。参数说明nParamCount是实际参数个数这里要求至少 2 个ppszParam[0]和ppszParam[1]是两个输入字符串ppszResult[0]是输出缓冲区。如果你的通达信版本对返回值个数有要求nResultCount可以用来判断。4. 避坑与排查字符串插件的五个高频翻车点4.1 中文乱码现象、原因与解决现象公式里传入中文插件处理后返回显示为乱码或问号。原因编码转换缺失或方向搞反。通达信传入的是 GBK插件按 UTF-8 解析或者插件返回 UTF-8通达信按 GBK 显示。解决在插件入口统一做GbkToUtf8出口统一做Utf8ToGbk。用上面封装的两个函数不要在每个分支里手动转容易漏。4.2 插件加载失败位数与依赖问题现象通达信公式里调用TDXDLL1返回错误或者根本没反应。原因DLL 位数不匹配64 位 DLL 放到 32 位通达信里或者缺少 VC 运行时依赖。解决确认编译平台是 x86用 Dependency Walker 检查依赖如果缺msvcp140.dll之类的改成静态链接运行库/MT。4.3 返回值截断缓冲区大小估计错误现象返回的字符串比预期短后半截丢失。原因通达信分配的返回值缓冲区大小有限常见是 256 字节。写入时没有检查长度或者strncpy_s的 size 参数给大了导致截断。解决限制返回字符串长度保守控制在 200 字节以内用strncpy_s并传_TRUNCATE确保不溢出。4.4 频繁调用导致性能下降现象公式在大量数据上运行时卡顿。原因每次调用都做编码转换和字符串拷贝开销累积。解决如果输入字符串在多次调用中不变可以在插件内做缓存或者把字符串处理逻辑移到公式端用通达信内置函数完成DLL 只处理必须的部分。4.5 多线程调用下的数据竞争现象插件在后台选股或预警中偶发崩溃。原因通达信可能在多线程环境下调用插件如果插件内用了全局变量或静态缓冲区会出现竞争。解决避免使用全局可变状态所有数据在函数栈上分配如果必须用静态数据加临界区保护。5. 进阶技巧用字符串参数做插件配置与调试输出字符串参数除了传业务数据还有一个实用场景做插件的运行时配置。比如你写了一个指标计算插件想让用户在不重新编译的情况下切换算法模式可以用一个字符串参数当配置项// 根据字符串参数选择算法分支 std::string mode GbkToUtf8(ppszParam[0]); if (mode fast) { // 快速算法 } else if (mode accurate) { // 精确算法 } else { // 默认算法 }这样公式端只需要改一个字符串常量就能切换插件行为比重新编译 DLL 方便得多。另一个技巧是用字符串返回值做调试输出。通达信公式的调试手段有限你可以在插件里把中间变量拼成字符串返回在公式里用MSGOUT或者直接显示在指标线上快速定位问题。我一般会在插件开发阶段加一个debug功能号返回内部状态字符串上线前再关掉。验证插件是否正常工作最直接的方法是写一个最小公式传入固定字符串调用插件把返回值画在副图上。如果显示正确说明链路通了如果乱码回去查编码如果没输出查 DLL 是否加载成功。从那以后我每次写完字符串插件都强制走一遍「最小公式验证 → 中文输入输出 → 边界长度测试」这三步能挡掉九成以上的问题。希望帮到你。本文还有配套的精品资源点击获取