如何使用 DLL 在 MQL4 程序之间交换值?
How to use DLLs to exchange values between MQL4 programs?
首先我要说我对 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:
我想交换多个值( value1, value2, value3, ... )。出于某种原因,我为 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 小时内再次工作。
有人知道吗?
最好的主意?
我能建议您的最好的事情是 停止尝试调整 KERNEL32.DLL
已发布 API 以使其与 MetaTrader Terminal 4 代码执行一起使用生态系统,而是开始设计一个专业的分布式系统,独立于将对象注入 O/S 页面文件并与信号量和 MUTEX-es 打交道。
除了最好的下一步:
- MQL4 代码不应阻塞。必须将 MUTEX 信号转换为非阻塞状态
- MQL4 代码/API 映射器应该尊重 MQL4
中的数据类型及其实际内存大小
- MQL4 代码应该符合最近的 New-MQL4 规则(部分在 "old"-MQL4 中)
- MQL4 声明
string
不是 C 语言 string
,而是 struct
!小心轻放!
- MQL4 代码在多个地方违反语法规则,只需使用
#property strict
进行测试
- MQL4 代码在忽略名称空间边界/声明范围时是 "shooting itself in leg"
- MQL4 代码忽略潜在的错误状态,不检查任何
GetLastError()
来处理此类冲突
- MQL4 代码没有优雅地 return 资源(忘记清除它们)
- 提议的 MQL4 代码将自身暴露在
KERNEL32.DLL
API 使用解锁隐形安全漏洞/启用 运行 次劫持黑客 的巨大风险中
- 更好地使用关注点分离,使用 ZeroMQ 或 nanomsg 消息传递到 "exchange values between ( not only ) MQL4 programs"
文件介质
我同意,如果您需要进行 MT4 到 MT4 的接口,Kernel32 不是一个好的选择。原因是 Kernel32 是 Windows specific。 EA 不适用于 Mac。此外,随意使用 Kernel32 DLL 可能会导致内存泄漏(例如,您的 5 小时直播)。另外,它要求用户知道如何启用 DLL(你会惊讶有多少用户不知道如何启用它)。
建议:
如果您只需要 SAME MT4 交易(图表之间的 EA),则使用 GlobalVariableGet()
、GlobalVariableSet()
等
如果您需要在 2 个不同的 MT4 之间进行交易(在同一台 PC 上)——即使它是跨不同的经纪商 MT4,那么请使用 FILE 系统:Files\FilePipe.mqh
它允许您写入通用 MT4文件夹:
#include <Files\FilePipe.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?])。
首先我要说我对 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:
我想交换多个值( value1, value2, value3, ... )。出于某种原因,我为 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 小时内再次工作。
有人知道吗?
最好的主意?
我能建议您的最好的事情是 停止尝试调整 KERNEL32.DLL
已发布 API 以使其与 MetaTrader Terminal 4 代码执行一起使用生态系统,而是开始设计一个专业的分布式系统,独立于将对象注入 O/S 页面文件并与信号量和 MUTEX-es 打交道。
除了最好的下一步:
- MQL4 代码不应阻塞。必须将 MUTEX 信号转换为非阻塞状态
- MQL4 代码/API 映射器应该尊重 MQL4 中的数据类型及其实际内存大小
- MQL4 代码应该符合最近的 New-MQL4 规则(部分在 "old"-MQL4 中)
- MQL4 声明
string
不是 C 语言string
,而是struct
!小心轻放! - MQL4 代码在多个地方违反语法规则,只需使用
#property strict
进行测试
- MQL4 代码在忽略名称空间边界/声明范围时是 "shooting itself in leg"
- MQL4 代码忽略潜在的错误状态,不检查任何
GetLastError()
来处理此类冲突 - MQL4 代码没有优雅地 return 资源(忘记清除它们)
- 提议的 MQL4 代码将自身暴露在
KERNEL32.DLL
API 使用解锁隐形安全漏洞/启用 运行 次劫持黑客 的巨大风险中
- 更好地使用关注点分离,使用 ZeroMQ 或 nanomsg 消息传递到 "exchange values between ( not only ) MQL4 programs"
文件介质
我同意,如果您需要进行 MT4 到 MT4 的接口,Kernel32 不是一个好的选择。原因是 Kernel32 是 Windows specific。 EA 不适用于 Mac。此外,随意使用 Kernel32 DLL 可能会导致内存泄漏(例如,您的 5 小时直播)。另外,它要求用户知道如何启用 DLL(你会惊讶有多少用户不知道如何启用它)。
建议:
如果您只需要 SAME MT4 交易(图表之间的 EA),则使用 GlobalVariableGet()
、GlobalVariableSet()
等
如果您需要在 2 个不同的 MT4 之间进行交易(在同一台 PC 上)——即使它是跨不同的经纪商 MT4,那么请使用 FILE 系统:Files\FilePipe.mqh
它允许您写入通用 MT4文件夹:
#include <Files\FilePipe.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?])。