如何使用 DLL 在 MQL4 程序之间交换值?



首先,我需要说我对DLL了解不多。

我正在尝试使用kernel32.dll的功能将数据从一个程序发送到另一个程序。我的程序是用 MQL4 编码的。

这是我用于服务器部分的代码,它应该保存数据:

#define INVALID_HANDLE_VALUE    -1
#define BUF_SIZE                256
#define PAGE_READWRITE          0x0004
#define FILE_MAP_ALL_ACCESS     0xf001F
#import "kernel32.dll"
int     CreateFileMappingA(int hFile, int lpAttributes, int flProtect, int dwMaximumSizeHigh, int dwMaximumSizeLow, string lpName);
int     MapViewOfFile(int hFileMappingObject, int dwDesiredAccess, int dwFileOffsetHigh, int dwFileOffsetLow, int dwNumberOfBytesToMap);
int     UnmapViewOfFile(int lpBaseAddress);
int     RtlMoveMemory(int DestPtr, string s, int Length);   
int     CloseHandle(int hwnd);  
int     CreateMutexA(int attr, int owner, string mutexName);
int     ReleaseMutex(int hnd);
int     WaitForSingleObject(int hnd, int dwMilliseconds);       
bool started = False;   
int hMapFile = 0;
int pBuf=0;
int hMutex;
int OnInit()
{
if(!started) {
started = true;
string szName="Global\Value1";
int hMapFile = CreateFileMappingA(INVALID_HANDLE_VALUE,0,PAGE_READWRITE,0,BUF_SIZE,szName);
if(hMapFile==0) {
Alert("CreateFileMapping failed!");
return;
}       
pBuf = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, BUF_SIZE);
if(pBuf==0) {
Alert("Map View failed!");
return;
}           
hMutex = CreateMutexA(0,0,"PriceMapMutex");     
}
}
void OnTick()
{
WaitForSingleObject(hMutex,1000);
if(pBuf==0) return;
string szMsg = DoubleToStr(Bid,Digits);
Comment("Data: ",szMsg);
RtlMoveMemory(pBuf, szMsg, StringLen(szMsg)+1);
ReleaseMutex(hMutex);
return(0);
}
int deinit()
{
switch(UninitializeReason()) {
case REASON_CHARTCLOSE:
case REASON_REMOVE:
UnmapViewOfFile(pBuf);
CloseHandle(hMapFile);
break;
}
return(0);  
}

这是我用于客户端部分的内容,它应该拾取数据:

#define INVALID_HANDLE_VALUE    -1
#define BUF_SIZE                1024
#define FILE_MAP_READ           4
extern int      BufferSize = 1024;
#import "kernel32.dll"
int     OpenFileMappingA(int dwDesiredAccess, bool bInheritHandle, string lpName);
string  MapViewOfFile(int hFileMappingObject, int dwDesiredAccess, int dwFileOffsetHigh, int dwFileOffsetLow, int dwNumberOfBytesToMap);
int     UnmapViewOfFile(string lpBaseAddress);
int     CloseHandle(int hwnd);
int     CreateMutexA(int attr, int owner, string mutexName);
int     ReleaseMutex(int hnd);
int     WaitForSingleObject(int hnd, int dwMilliseconds);   
string szName;
int hMapFile;
string obj;
string data;
int hMutex;
double dd;

int OnInit()
{
szName="Global\Value1";
hMapFile = OpenFileMappingA(FILE_MAP_READ,False,szName);
if(hMapFile==0) {
Alert("CreateFile Failed!");
return;
}
obj="data";
ObjectCreate(obj,OBJ_HLINE,0,0,0);
ObjectSet(obj,OBJPROP_COLOR,Gold);
hMutex = CreateMutexA(0,0,"PriceMapMutex");  
}
void OnDeinit(const int reason)
{
CloseHandle(hMapFile);   
Comment("");
ObjectDelete(obj);
return(0);  
}
void start()
{
getsignal();
Comment("Data: ",DoubleToStr(dd,Digits));
Sleep(50);
}
void getsignal() {
WaitForSingleObject(hMutex,333);
data = MapViewOfFile(hMapFile,FILE_MAP_READ,0,0,BUF_SIZE); 
dd = StrToDouble(data);
ReleaseMutex(hMutex);   
UnmapViewOfFile(data);          
ObjectMove(obj,0,Time[0],dd);
}

代码基本有效。但是,我面临着两个主要问题。

问题1:
我想交换多个值(值1,值2,值3,...)。出于某种原因,我使用哪个名称似乎无关紧要szName="Global\Value1".服务器保存该值,无论我使用什么名称szName="Global\Value1"szName="Global\Value2"szName="Global\Value3",客户端都会拾取它。因此,例如,在服务器代码中,我使用szName="Global\Value1",在我的客户端代码中,我使用szName="Global\Value3"客户端仍然拾取服务器写入szName="Global\Value1"的值。

问题2:
我的客户端只能稳定大约5个小时。之后,我在客户端程序中收到一条消息,说

"There is a problem and the program needs to be closed...".

然后我关闭并重新启动我的客户端,它在接下来的 5 小时内再次工作。

有人知道吗?

文件介质

我同意,如果您需要进行MT4到MT4接口,Kernel32不是一个好的选择。原因是Kernel32是Windows特定的。EA 无法在Mac上运行。此外,弄乱 Kernel32 DLL 可能会导致内存泄漏(例如,您的 5 小时实时)。另外,它要求用户知道如何启用DLL(你会惊讶于有多少用户不知道如何启用它)。

建议:

如果您只需要相同的MT4交换(图表之间的EA),则使用GlobalVariableGet()GlobalVariableSet()等。

如果您需要在2个不同的MT4(在同一台PC上)之间进行交换 - 即使它在不同的经纪人MT4之间,请使用FILE系统:FilesFilePipe.mqh允许您写入公共MT4文件夹:

#include <FilesFilePipe.mqh>
CFilePipe   voPipeOut;
voPipeOut.Open("yourFileName.txt", FILE_WRITE|FILE_COMMON|FILE_BIN);
voPipeOut.WriteString("WhatEverMessage, probably some CSV value here");
voPipeOut.Close();

随后

CFilePipe   voPipeFile;
string      vsInString      = "";
voPipeFile.Open("yourFileName.txt", FILE_SHARE_READ|FILE_COMMON|FILE_BIN);
voPipeFile.Seek(0,SEEK_SET);
voPipeFile.ReadString( vsInString );
voPipeFile.Close();

这样,您的 EA 将不依赖于 DLL,并且也可以在各种环境中工作。它非常快(1Mb 管道不到 2 毫秒)。它甚至适用于跨代理接口(在 2 个不同的代理之间交换信息 [feed?])。

最好的主意?

我能建议你做的最好的事情是停止尝试调整已发布KERNEL32.DLLAPI以使其与MetaTrader终端4代码执行生态系统一起使用,而是开始设计一个专业的分布式系统,而不是将对象注入O/S页面文件并使用信号量和MUTEX-es。

除了最好的下一步:

  • MQL4 代码永远不应该阻塞。必须将互斥信号转换为非阻塞状态
  • MQL4 代码/API 映射器应尊重 MQL4 中的数据类型及其实际内存大小
  • MQL4
  • 代码应符合最新的MQL4 规则(部分位于"旧">-MQL4 中)
  • MQL4 声明string不是 C-langstring,而是struct!小心处理!
  • MQL4 代码在多个地方违反了语法规则,只需使用#property strict进行测试
  • MQL4 代码在忽略命名空间边界/声明范围时"自枪自悯
  • "
  • MQL4 代码忽略潜在的错误状态,不检查任何处理此类冲突GetLastError()
  • MQL4 代码不会优雅地返回资源(忘记清除它们)
  • 提议的 MQL4 代码将自己暴露在KERNEL32.DLLAPI 使用解锁隐形安全漏洞/启用运行时劫持黑客的巨大风险中
  • 更好地使用关注点分离,使用 ZeroMQ 或 nanomsg 消息传递来"在(不仅是)MQL4 程序之间交换值">

最新更新