10 分钟掌握 MQL5 的 DLL(第二部分):使用 Visual Studio 2017 创建·综合运用
把复杂对象塞进 DLL 的两条路
在 MT5 里往外部 DLL 传对象是个硬限制:含动态数组、嵌套对象的结构体无法直接丢进导出函数。若你拿不到函数库源码,常规改数据结构的方法就走不通,只能绕道。 第一条路是 StructToCharArray()。示例里先把 Str 结构转成 uchar 数组再传指针,但这个函数只认 POD 结构(纯旧数据,无构造/虚表),遇到带动态对象的封装就失效。作者本人也没在真实代码上验证过它的边界行为,实用性存疑。 更稳的思路是在脚本侧把对象序列化成 JSON 字符串,DLL 内再反解成原生结构,反向同理。MQL5、C++、C# 都有现成解析器可用。代价是封装/解封费时间,但能处理极复杂嵌套,且封装器可后续优化复用,不必重写。 外汇与贵金属 EA 调用第三方库本就高风险,DLL 崩溃可能直接拖垮终端;动手前建议在脚本里先跑通最小结构体再逐步加压。
class="kw">struct Str { ... }; Str s; class="type">uchar ch[]; StructToCharArray(s,ch); SomeExportFunc(ch); class="macro">#pragma pack(class="num">1) typedef class="kw">struct D_a { ... }Da, *PDa; class="macro">#pragma pack() class="type">void SomeExportFunc(class="type">char* pA) { PDa = (PDa)pA; ...... }
◍ 用 DLL 绕开终端限制发邮件
想在 MT5 里让 EA 或脚本主动推送邮件,又不想被终端的邮箱设置绑死,可以自己编一个 DLL 接管发送逻辑。这个思路的核心是把 SMTP 收发做成独立函数库,调用方只传地址、账号和正文,不依赖 MT5 选项里的邮件配置,哪怕终端里邮件功能关了也不影响外发。 导出函数只有一个 SendSomeMail,参数顺序很直白:addr_from 和 addr_to 是收发件人;subject 与 text_body 是主题和正文;smtp_server、smtp_user、smtp_password 对应服务器地址、登录名和密码。注意发件人必须实名,因为函数库不会做匿名中继,你要在邮件服务器上有真实账号。 端口在函数库里写死了标准 25,一次调用只能发到一个收件人地址;要群发就用不同 addr_to 反复调。底层借用了微软论坛流传已久的 CDO 示例(C++ 部分不在此贴出,原工程包里有完整项目),稳定性经过社区反复验证。 下面的 MQL5 脚本演示怎么接这个 DLL:把 X 占位符换成你自己的邮箱和 SMTP 信息,跑 OnStart 就能看到 Print 回来的发送结果布尔值。外汇与贵金属交易信号推送涉及高风险,任何自动通知都只是辅助,不构成方向建议。
SENDSOMEMAIL_API <span class="keyword">class="type">bool</span> SendSomeMail(LPCWSTR addr_from, LPCWSTR addr_to, LPCWSTR subject, LPCWSTR text_body, LPCWSTR smtp_server, LPCWSTR smtp_user, LPCWSTR smtp_password); <span class="preprocessor">class="macro">#class="kw">import </span><span class="class="type">class="kw">string">"SendSomeMail.dll"</span> <span class="keyword">class="type">bool</span> SendSomeMail(<span class="keyword">class="type">class="kw">string</span> addr_from,<span class="keyword">class="type">class="kw">string</span> addr_to,<span class="keyword">class="type">class="kw">string</span> subject,<span class="keyword">class="type">class="kw">string</span> text_body,<span class="keyword">class="type">class="kw">string</span> smtp_server,<span class="keyword">class="type">class="kw">string</span> smtp_user,<span class="keyword">class="type">class="kw">string</span> smtp_password); <span class="preprocessor">class="macro">#class="kw">import </span><span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span> <span class="comment">class=class="str">"cmt">//| 脚本程序开始函数 |</span> <span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span> <span class="keyword">class="type">void</span> <span class="functions">OnStart</span>() { <span class="keyword">class="type">bool</span> b = SendSomeMail(<span class="class="type">class="kw">string">"XXX@XXX.XX"</span>, <span class="class="type">class="kw">string">"XXXXXX@XXXXX.XX"</span>, <span class="class="type">class="kw">string">"hello"</span>, <span class="class="type">class="kw">string">"hello from me to you"</span>,<span class="class="type">class="kw">string">"smtp.XXX.XX"</span>, <span class="class="type">class="kw">string">"XXXX@XXXX.XXX"</span>, <span class="class="type">class="kw">string">"XXXXXXXXX"</span>); <span class="functions">Print</span>(<span class="class="type">class="kw">string">"Send mail: "</span>, b); }
「DLL 封装保护的现实边界」
顺带提一个实战里容易踩坑的点:编译出来的 DLL 如果怕被反编译,常规做法是套封装器。我手头实测过两个——Themida 2.4.6.0 和 VMProtect Ultimate 3.0.9,把最早的 Project2.dll 各封了一遍,在 MT5 终端里用现成脚本调导出函数,都能正常跑起来。 但这不意味着换别的封装工具也稳。封装后的函数库能不能被终端加载、调用会不会崩,和封装器的实现强相关,目前没有统一保证。Project2_Pack.zip 里放了上述两种封装好的版本,想验证的可以直接丢进终端试。 外汇和贵金属 EA 开发本身高风险,封装只是代码层防护,不改变策略盈亏概率,别把保护强度误当成稳定性背书。
随文附带的可复用工程包
这一节把全文用到的工程文件列清了,方便直接在 MT5 里跑通 DLL 调用链路。核心就两个项目:Project2 是简单 DLL 的示范,Project2.mq5 作为脚本去调它;SendSomeMail 则是发邮件的 DLL 项目,配套 SendSomeMail.mq5 脚本调用。 附件体积差异很大,Project2.zip 仅 18.65 KB,而用 Themida 和 VMProtect 加壳后的 Project2_Pack.zip 达到 4645.25 KB,说明保护后的二进制膨胀了约 249 倍。做外汇或贵金属自动化时,这种加壳会增加被杀软误报的概率,实盘前先在隔离环境验一遍。 想验证就下载 Project2.mq5(3.42 KB)和 Project2.zip,按原文步骤在 VS 编译 DLL 后丢进 MT5 的 MQL5/Libraries,跑脚本看能否正常加载。加密壳那版建议只用于研究,别直接挂实盘账户。