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

时间:2017-05-27 05:50:26

标签: 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:
我想交换多个值(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个小时内再次工作。

有人有任何想法吗?

2 个答案:

答案 0 :(得分:4)

文件媒体

我同意如果你需要进行MT4到MT4的接口,Kernel32不是一个好的选择。原因是Kernel32 Windows特定。 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管道不到2ms)。它甚至适用于跨代理接口(在两个不同的代理之间交换信息[feed?])。

答案 1 :(得分:1)

最好的主意?

我建议您最好的建议是停止尝试调整KERNEL32.DLL 已发布的API,使其与MetaTrader Terminal 4代码执行生态系统一起使用,而不是开始设计专业的分布式系统,独立于将对象注入O / S页面文件并与信号量和MUTEX-es混淆。

除了最好的下一步:

  • MQL4代码不应该阻止。 MUTEX信令变为非阻塞状态是必须的
  • MQL4代码/ API映射器应该尊重MQL4中的数据类型及其实际内存大小
  • MQL4代码应符合最近的 -MQL4规则(部分位于“old” -MQL4)
  • MQL4声明 string 不是C-lang string,而是 struct !小心轻放!
  • MQL4代码违反了多个地方的语法规则,只需使用 #property strict 进行测试
  • 当忽略名称空间边界/声明范围
  • 时,MQL4代码“在腿上射击”
  • MQL4代码忽略潜在的错误状态,而不是检查任何GetLastError()来处理此类碰撞
  • MQL4代码无法正常返回资源(忘记清除它们)
  • 提出的MQL4代码暴露了KERNEL32.DLL API使用解锁隐形安全漏洞/启用运行时劫持黑客的巨大风险
  • 更好地利用问题分离,使用ZeroMQ或nanomsg消息传递 (不仅仅是) MQL4程序之间的交换价值”