MetaTrader的拓展应用,创建自己的DLL程序

  • Post author:
  • Post category:其他






MetaTrader的拓展应用,创建你自己的DLL程序


MetaTrader的拓展应用,创建你自己的DLL程序。文章原系英文,在网络中可以搜寻得到。


在MT4中,使用DLLs(动态链接库)来做什么?


MQL4能让你做事情是极为有限的,有很多事情在MQL4上做不了。为了得到Windows操作系统的全部控制(比如,进入windows注册表或文件,处理相关的APIs)您得需要:


1)引用Windows的公用DLLs,导入你所需要的函数功能,这就是一个范例:


#import “user32.dll”

int MessageBoxA(int hWnd, string lpText, string lpCaption, int uType);


上述语句中我们使用关键字#import来导入user32.dll之函数:MessageBoxA函数


这样我们就能在我们自己的代码上使用该函数。


2)第二个选择,就是通过C++创建自己的动态连接库DLLs,它和Windows的公用DLLs一样,可在我们的代码中调用。这就是今天我们将要学习的内容。


DLL编译工具


最佳选择是Visaul C++,我使用Microsoft Visual c++ 6。现在,让我们创建第一个DLL,它将带给我们一句简单的问候语”Hello World!”。


Hello, World! 动态链接库的编译


1)第一步,打开Visual C++


2)“文件”菜单里选择“新建”,出现一个对话窗:


3)在对话窗中选择”MFC AppWizard (dll)”,输入工程名称:”demo”,点击OK;


注解:你可以选择”Win32 Dynamic-Link Library”代替”MFC AppWizard (dll)”但这样的话你就不能使用”CString”类型,而”CString”类型是应用起来较为简单的MFC类型。


4)出现另一个对话窗,无需更改其默认的选择,按”完成”确认。然后,会弹出一个信息窗口,按”OK”。


5)恭喜!你已创建一个名为”demo”的工程文件,你可以开始写你自己的DLL代码了。请打开”demo.cpp”文件看看…


首先我们拟写一行代码:


#define MT4_EXPFUNC __declspec(dllexport)


你必须把此行代码放在这些代码的后面:


#include “stdafx.h”

#include “demo.h”


#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif


6)再增加一些代码,在”demo.cpp”的这行代码后面(也就是文件的末端):


CDemoApp theApp;


我们写入这样的代码,来描述”Hello”函数:


MT4_EXPFUNC void __stdcall Hello(char* say)

{


MessageBox(NULL,say,”demo”,NULL);

}


7)我们有了”Hello”函数:其功能是把一个字符串说出来,而且不返回任何值(void)。


在C++中,我们需要在一个DEF文件里声明该函数,才能给供外部调用。


我们打开”demo.def”文件,在文件尾部添加一行代码(粗体):


; demo.def : Declares the module parameters for the DLL.


LIBRARY “demo”

DESCRIPTION ‘demo Windows Dynamic Link Library’


EXPORTS

; Explicit exports can go here

Hello


8)按F7编译该DLL,如果您和我一样幸运的话,编译中将不会提示任何错误或警告。在Debug文件夹里,可以找到demo.dll文件。


测试我们的demo.dll


Hi,朋友,我们在C++里一步一步地建立了我们第一个DLL程序,接下来我们将要进行一次测试.


1)把编译好的demo.dll文件放到文件夹MetaTrader 4\experts\libraries


2)打开MetaEditor创建一个名为demo.mqh的include文件,用来声明”Hello”函数。


代码如下:


#import “demo.dll”

void Hello(string);

#import

留意我们是如何已经引入了DLL文件,以及我们如何声明”Hello”函数的:必须使用同样的参数类型( string: MT4的字符串类型,对应于C++的char* str )及返回值(void),与DLL中定义的函数相符。

文件将存档于Include文件夹(MetaTrader 4\experts\include).


3)现在,我们创建一个script来测试demo.dll。


我们命名它为”Hello.mq4″ ,必须存档于Scripts文件夹 (MetaTrader 4\experts\scripts).


#include <demo.mqh>

int start()

{


Hello (“Hello World!”);

return(0);

}


留意在代码开始部分,我们如何“包含”demo.mqh文件,使它成为我们代码的一部分。


4)编译该script (F5),装载它(鼠标双击终端的导航窗口)。


你得到什么?一个漂亮的对话窗。


注意:在使用涉及引用外部函数(不管是普通的windows dlls 还是你自己的dlls)的任何代码前,你必须在MetaTrader中打开“Allow DLL imports”功能。


通过 工具 -> 选项 -> 智能交易系统,打开”允许导入动态链接库”功能。


补充说明:


能否把.mqh文件省掉?答案当然是可以的,只需把其内容镶嵌到.mq4文件的开头:


#import “demo.dll”

void Hello(string);

#import

int start()

{


Hello(“Hello World!”);

return(0);

}


demo.dll


俺不是编程高手,而且时间和精力都很有限,因此编程对于我来说最理想的境界是”知其然”,而不必”知其所以然”。当然,如果程序出错,那就要好好研究一下”其所以然”了。所以每次编程都会经历一个预热的学习过程,看看范例–然后温故而知新……MT4自带的DLL范例,就放在在文件夹MetaTrader 4\EXPERTS\SAMPLES中。该范例值得细细研究,是因为它展示了如何使用mq4语言来调用C++语言编写的DLL。而我们需要重点留意的,就是调用DLL函数时所展现的函数参数的传递方式;显然,针对不同类型的变量,都有其不同的传递方式,实现的结果亦各不相同。


1)变量传递。


对于mq4的double/int类型变量,与C++的通讯只需要用到值传递。

在C++里我们要定义一个函数,如func1(double x,int y){……;……;}

mq4里我们必须在头文件里做一个函数声明:func1(double,int),调用的时候以相应的变量值作为参数,如func1(10.56,8)。


对于mq4的String类型,在C++里可以用指针如char *str来代替String类型。

在C++里我们要定义一个函数,如func2(char *str){……;……;}

mq4里我们必须在头文件里做一个函数声明:func2(string),调用的时候以字符串作为参数,如func2(“something”)。


2)数组的传递。


对于mq4的double/int类型数组,C++通过指针来接收相应的参数。

关于数组与指针,在网上查阅了很多论述:其实,在C++中数据名作为函数形参时,等同于指向数组的指针!

于是,下面2个函数是等效的:


double sample1(double*);












//在声明中,描述参数为(指向数组的)指针:double*;

……

double sample1(double aa[])







//在函数中,以aa[](数组)来接收该指针。

{


aa[4]=55.5;

return(aa[4]);

}


double sample2(double []);












//在声明中,描述参数为数组:double [];

……

double sample2(double *aa)









//在函数中,以*aa(指针)来接收该数组。

{


aa[4]=55.5;

return(aa[4]);

}

当然,2个函数的声明其实也是等效的。mq4中没有指针类型,所以传递数组的方式类似sample2。


3)行情数据的传递

mq4提供了ArrayCopyRates函数,用于复制一段走势图上的数据到一个二维数组,并返回复制柱子的总数。其第二维为固定的6个项目,从0到5分别为“时间、开盘价格、最低价格、最高价格、收盘价格、成交量”。

如:



double rates[][6];

int totalRecords = ArrayCopyRates(rates,Symbol(),0);


mq4调用DLL函数的时候,把该数组作为参数,向DLL函数提供二维数组的指针,这也就是就mq4程序实现行情数据传递的默认方式。

如:



ArrayCopyRates(rates);

price=GetRatesItemValue(rates,Bars,0,CLOSE_INDEX);


对应地,我们在C++代码中可以定义一个结构类型RateInfo:

struct RateInfo

{


unsigned int time;



//时间

double open;










//开盘价格

double low;













//最低价格

double high;











//最高价格

double close;









//收盘价格

double volume;






//成交量

};

这里的RateInfo结构定义正好对应mq4里二维数组的第二维,在DLL函数里,结构指针RateInfo*被映射为二维数组double rates[][6]。也就是说,当mq4调用DLL的时候,由操作系统根据内存指针完成了数据的访问,且结构定义中的unsigned int是从double类型转换后得到的。


需要注意的是:mq4数组顺序与DLL数组顺序完全相反。mq4数组顺序是:从Bars-1到0;而传递到DLL后,数组顺序变为0到Bars-1?