在 MQL5 中使用资源·进阶篇
📘

在 MQL5 中使用资源·进阶篇

第 2/3 篇

声音与图像文件该丢进哪个沙箱目录

在 MQL5 里调用 ObjectSetString() 或 PlaySound() 时,文件必须落在客户端沙箱内,跨目录读取会被直接拒绝。可用目录分三类:客户端安装目录(terminal_directory)、当前 Windows 用户的客户端数据目录(terminal_data_directory\MQL5\),以及带 FILE_COMMON 标志才能写的全体客户端共享文件夹。 路径开头的反斜杠决定搜索基准。以 "\\" 起头,文件相对 terminal_data_directory\MQL5\ 找;不开头则相对调用函数的 EX5 所在文件夹找。PlaySound() 若前两种都落空,还会去 terminal_directory\Sounds\ 兜底。 具体现象:写 "\\one.wav" 会搜 terminal_data_directory\MQL5\one.wav;写 "four.wav" 先搜 EX5 同目录,没有才去 terminal_directory\Sounds\。图像同理,"bird.bmp" 落 MQL5 根,"\\Files\\swan.bmp" 落 MQL5\Files。 别把 terminal_directory 和 terminal_data_directory 当一回事,某些装法里二者路径重合只是偶然。写路径恒定用双反斜杠 "\\",单反斜杠在编译期会被当成控制字符吞掉。 下一段脚本跑完,MT5 终端日志会直接打印出你机器上三个真实目录,复制出来对照就不会放错文件。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------
class=class="str">"cmt">//|                                                  WhereMyFolders.mq5 |
class=class="str">"cmt">//|                 Copyright class="num">2011, MetaQuotes Software Corp. |
class=class="str">"cmt">//|                                 [MQL5官方文档] |
class=class="str">"cmt">//+------------------------------------------------------------------
class="macro">#class="kw">property copyright "Copyright class="num">2011, MetaQuotes Software Corp."
class="macro">#class="kw">property link      "[MQL5官方文档]
class="macro">#class="kw">property version   "class="num">1.00"
class=class="str">"cmt">//+------------------------------------------------------------------
class=class="str">"cmt">//| 脚本程序开始函数                                      |
class=class="str">"cmt">//+------------------------------------------------------------------
class="type">void OnStart()
  {
class=class="str">"cmt">//--- 客户端的开始文件夹 - terminal_directory
   class="type">class="kw">string terminal_path=TerminalInfoString(TERMINAL_PATH);
class=class="str">"cmt">//--- 保存客户端数据的文件夹 - terminal_data_directory
   class="type">class="kw">string terminal_data_path=TerminalInfoString(TERMINAL_DATA_PATH);
class=class="str">"cmt">//--- 所有客户端的共享文件夹 - common_terminal_folder
   class="type">class="kw">string common_data_path=TerminalInfoString(TERMINAL_COMMONDATA_PATH);  
   class=class="str">"cmt">//--- 显示所有路径 
   Print("TERMINAL_PATH(terminal_directory) = ",TerminalInfoString(TERMINAL_PATH));
   Print("TERMINAL_DATA_PATH(terminal_data_directory) = ",TerminalInfoString(TERMINAL_DATA_PATH));
   Print("TERMINAL_COMMONDATA_PATH(comon_terminal_folder) = ",TerminalInfoString(TERMINAL_COMMONDATA_PATH));  
  }
PlaySound("\\one.wav");
PlaySound("\\Files\\two.wav");
PlaySound("\\MySounds\\three.wav");
PlaySound("four.wav");
class=class="str">"cmt">//--- 为 OBJ_BITMAP_LABEL 对象设置图像
class="type">bool res=ObjectSetString(class="num">0,object_name,OBJPROP_BMPFILE,class="num">0,"bird.bmp");class=class="str">"cmt">// 指定修饰符 class="num">0
class=class="str">"cmt">//--- 为 OBJ_BITMAP 对象设置图像
class="type">bool set=ObjectSetString(class="num">0,object_name,OBJPROP_BMPFILE,"\\Files\\swan.bmp");class=class="str">"cmt">// 无修饰符
class=class="str">"cmt">//--- 为 OBJ_BITMAP 对象设置图像

「给图表对象挂位图的两种路径」

在 MT5 里用 ObjectSetString 给 OBJ_BITMAP 类对象指定图片时,路径写法直接影响资源能否加载。下面两段代码都省略了修饰符参数,但指向的文件位置不同,验证时容易踩坑。 第一段把位图指向终端相对路径下的 \MyPictures\dog.bmp,第二段只传了 cat.bmp 文件名。前者依赖你手动在终端目录建好 MyPictures 文件夹,后者要求 bmp 已放在当前 chart 可识别的默认资源位,否则 ObjectSetString 会返回 false。 实盘加载贵金属 1 分钟图做按钮贴图时,若返回 false 概率偏高,优先查文件后缀大小写和位深——MT5 对 24/32 位 bmp 兼容更稳,16 色老格式常加载失败。外汇与贵金属图表叠加位图属于低风险界面改造,但自动化改图脚本若误删对象,可能引发指标重绘,仍需注意平台高风险特性。

MQL5 / C++
class="type">bool done=ObjectSetString(class="num">0,object_name,OBJPROP_BMPFILE,"\\MyPictures\\dog.bmp");class=class="str">"cmt">// 无修饰符
class=class="str">"cmt">//--- 为 OBJ_BITMAP 对象设置图像
class="type">bool result=ObjectSetString(class="num">0,object_name,OBJPROP_BMPFILE,"cat.bmp");class=class="str">"cmt">// 无修饰符

◍ 把图像声音焊进 EX5 本身

在 MQL5 程序里调用图像或声音,常规做法是把媒体文件丢进对应客户端目录。问题是编译好的 EX5 一旦换台机器跑,就得连文件一起搬,漏一个就报错。 编译器指令 #resource 能直接把资源路径写死进 EX5。编译时指定路径的文件会被打包进可执行文件,运行时不再依赖外部目录。 实测下来,一个 EA 不仅能用自己的资源,还能跨 EX5 调指标或库里的资源——只要对方也是编译进体的。这意味着部署时只传一个文件就够了。 外汇与贵金属自动化涉及高风险,资源封装只解决分发便利,不改善策略盈亏。

MQL5 / C++
class="macro">#resource path_to_resource_file

资源路径的搜索规则与禁区

在 MT5 里给 EA 或指标挂资源,靠的是 #resource 指令把文件编译进 ex5。路径字符串本身不能长于 63 个字符,超长直接编译失败,这一点在批量塞图标时很容易踩。 编译器认路径时有先后逻辑:开头带反斜杠 "\",就相对 terminal_data_directory\MQL5\ 找;不带,就相对写这条指令的源码所在目录找。也就是说同样写 "picture.bmp",放在源码同目录能编过,挪到 MQL5 根下就找不到了。 两条红线不能碰:路径里禁止出现 "..\\" 和 ":\\" 子串,前者防越目录,后者防盘符跳转。下面这段把正确和错误写法都列出来了,开 MT5 新建个脚本粘进去编译就能验证。

MQL5 / C++
class="macro">#resource "<path_to_resource_file>"
class=class="str">"cmt">//--- 正确指定一个资源
class="macro">#resource "\Images\euro.bmp" class=class="str">"cmt">// euro.bmp 位于 terminal_data_directory\MQL5\Images\
class="macro">#resource "picture.bmp"        class=class="str">"cmt">// picture.bmp 位于源文件相同目录
class="macro">#resource "Resource\map.bmp"   class=class="str">"cmt">// 资源位于文件夹 source_file_directory\Resource\map.bmp
 
class=class="str">"cmt">//--- 不正确的指定资源文件
class="macro">#resource ":picture_2.bmp"     class=class="str">"cmt">// 使用 ":" 是不允许的
class="macro">#resource "..\picture_3.bmp"   class=class="str">"cmt">// 使用 ".." 是不允许的
class="macro">#resource "\Files\Images\Folder_First\My_panel\Labels\too_long_path.bmp" class=class="str">"cmt">//超过 class="num">63 个字符

「资源名怎么写编译器才认」

用 #resource 把图片、音频等塞进 EX5 之后,程序任意位置都能调它,关键就在于「资源名」怎么定。编译器取的是路径字符串里不以反斜杠开头的那段作为名字,比如写 "\\Images\\cat.bmp",实际资源名就是 Images\cat.bmp;直接写 "dog.bmp",名字就是 dog.bmp。 资源名不区分大小写,dog.bmp 和 DOG.bmp 在编译器眼里是同一个,起名时不用纠结大小写规范,但团队协作用统一写法能少踩坑。 下面这段声明可以直接贴进 MQ5 文件顶部验证:资源名由路径推导,带反斜杠前缀的会被剥掉,多级目录原样保留。开 MT5 随便建个脚本,#resource 后 Print 一下资源名就能看到映射结果。

MQL5 / C++
class="macro">#resource "\Images\cat.bmp"                 class=class="str">"cmt">// 资源名 - Images\cat.bmp
class="macro">#resource "dog.bmp"                           class=class="str">"cmt">// 资源名 - dog.bmp
class="macro">#resource "Resource\map.bmp"                  class=class="str">"cmt">// 资源名 - Resource\map.bmp
class="macro">#resource "\Files\Pictures\bird.bmp"         class=class="str">"cmt">// 资源名 - Files\Pictures\bird.bmp
class="macro">#resource "\Files\good.wav"                   class=class="str">"cmt">// 资源名 - Files\good.wav
class="macro">#resource "\Sounds\thrill.wav"               class=class="str">"cmt">// 资源名 - Sounds\thrill.wav

常见问题

放终端的 Sounds 目录下最稳,MQL 程序读相对路径时优先认这里;别塞进自己随便建的 data 子目录,否则加载可能静默失败。
OBJPROP_BMP 是给已有对象(如按钮)挂背景图,Bitmap Label 是独立图像对象;前者随控件走,后者可自由定位且不依赖父对象。
小布可读取你导出的程序信息并列出内嵌资源清单,打开对应品种页就能看到是否含图像或音频,省去手动反编译核对。
编译器只认工程内相对路径或 :: 开头的全局资源名,上级目录跳转符被禁;用 :: 前缀表示已焊进 EX5 的内部资源。
不会,焊死进 EX5 的资源完全内置,加载时只解包自身;原文件删了也不影响,但更新图得重新编译。