English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
Veri Değişimi Nasıl Yapılır? 10 Dakikada MQL5 için bir DLL

Veri Değişimi Nasıl Yapılır? 10 Dakikada MQL5 için bir DLL

MetaTrader 5Örnekler | 10 Aralık 2021, 17:06
100 0
MetaQuotes
Renat Fatkhullin

Aslına bakılırsa, basit bir DLL kitaplığının nasıl yazılacağını ve farklı sistemleri bağlamanın özelliklerinin neler olduğunu tam olarak hatırlayan çok fazla geliştirici yoktur.

Birkaç örnek kullanarak, basit DLL oluşturma işleminin tamamını 10 dakikada göstermeye çalışacağım ve ayrıca bağlayıcı uygulamamızın bazı teknik ayrıntılarını ele alacağım. Visual Studio 2005/2008'i kullanacağız; Express sürümleri ücretsizdir ve Microsoft web sitesinden indirilebilir.

1. Visual Studio 2005/2008'de C++'da DLL projesi oluşturma

'Dosya -> Yeni' menüsünü kullanarak Win32 Uygulama Sihirbazını çalıştırın, proje türünü 'Visual C++' olarak seçin, 'Win32 Konsol Uygulaması' şablonunu seçin ve proje adını belirtin (örneğin, 'MQL5DLLSamples'). 'Konum' projesini saklamak için önerilen varsayılan dizin yerine bir kök dizin seçin, 'Çözüm için dizin oluştur' onay kutusunu devre dışı bırakın ve 'Tamam'a tıklayın:

Şek. 1. Win32 Uygulama Sihirbazı, DLL projesi oluşturma

Bir sonraki adımda, ayarlar sayfasına gitmek için 'İleri' düğmesine basın:

Şek. 2. Win32 Uygulama Sihirbazı, proje ayarları

Son sayfada, 'DLL' uygulama türünü seçin, diğer alanları olduğu gibi boş bırakın ve 'Bitir' düğmesine tıklayın. Otomatik olarak eklenen tanıtım kodunu kaldırmak istemiyorsanız 'Sembolleri dışa aktar' seçeneğini ayarlamayın:

Şek. 3. Win32 Uygulama Sihirbazı, Uygulama ayarları

Sonuç olarak boş bir projeniz olacak:

Şek. 4. Wizard tarafından hazırlanan boş DLL projesi

Testi basitleştirmek için, 'Çıktı Dizini' seçeneklerinde DLL dosyalarının çıktısını doğrudan istemci terminalinin '...\MQL5\Libraries' konumuna belirtmek daha iyidir; ayrıca, bu, size fazlasıyla zaman kazandıracaktır:

Şek. 5. DLL çıktı dizini


2. İşlev Eklemeye Hazırlanma

Dışa aktarılan işlevleri rahat ve kolay bir şekilde tanımlayabilmeniz için stdafx.h dosyasının sonuna '_DLLAPI' makrosunu ekleyin:

//+------------------------------------------------------------------+
//|                                                 MQL5 DLL Samples |
//|                   Copyright 2001-2010, MetaQuotes Software Corp. |
//|                                        https://www.metaquotes.net |
//+------------------------------------------------------------------+
#pragma once

#include "targetver.h"

#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers
#include <windows.h>

//---
#define _DLLAPI extern "C" __declspec(dllexport)
//+------------------------------------------------------------------+

MQL5'teki DLL içe aktarılan işlev çağrıları stdcall ve cdecl çağırma kuralını içermelidir. stdcall ve cdecl, bir yığından parametre çıkarma yöntemlerinde farklılık gösterse de, MQL5 çalışma zamanı ortamı, DLL çağrılarının özel paketinden dolayı her iki sürümü de güvenle kullanabilir.

C++ derleyicisi varsayılan olarak __cdecl çağrısını kullanır, ancak dışa aktarılan işlevler için __stdcall modunun açıkça belirtilmesini öneririm.

Doğru yazılmış bir dışa aktarma işlevi aşağıdaki forma sahip olmalıdır:

_DLLAPI int __stdcall fnCalculateSpeed(int &res1,double &res2)
  {
   return(0);
  }

Bir MQL5 programında işlev aşağıdaki gibi tanımlanmalı ve çağrılmalıdır:

#import "MQL5DLLSamples.dll"
int  fnCalculateSpeed(int &res1,double &res2);
#import

//--- call
   speed=fnCalculateSpeed(res_int,res_double);

Proje derlemesinden sonra, bu stdcall, dışa aktarma tablosunda _fnCalculateSpeed@8 olarak görüntülenecektir; burada derleyici yığın aracılığıyla iletilen bir alt çizgi ve bayt sayısı ekler. Böyle bir tasarım, çağıranın yığına yerleştirilmesi gereken tam olarak kaç veri olduğunu (ancak türünü değil!) bilmesi nedeniyle DLL işlev çağrılarının güvenliğinin daha iyi kontrol edilmesine olanak tanır.

Parametre bloğunun son boyutunda DLL işlevi içe aktarma açıklamasında bir hata varsa işlev çağrılmayacak ve günlükte yeni mesaj görünecektir: ''MQL5DLLSamples.dll' içinde 'fnCrashTestParametersStdCall' bulunamıyor. Bu gibi durumlarda, hem işlev prototipindeki hem de DLL kaynağındaki tüm parametrelerin dikkatlice kontrol edilmesi gerekir.

Dışa aktarma tablosunun tam işlev adını içermemesi durumunda uyumluluk için tasarımsız basitleştirilmiş açıklama araması kullanılır. fnCalculateSpeed gibi adlar, işlevler __cdecl biçiminde tanımlanırsa oluşturulur.
_DLLAPI int fnCalculateSpeed(int &res1,double &res2)
  {
   return(0);
  }


3. Parametre İletme ve Veri Değişimi Yöntemleri

İletilen parametrelerin birkaç çeşidini ele alalım:

  1. Basit değişkenleri alma ve iletme
    Basit değişkenlerin durumu kolaydır; değere göre veya & öğesi kullanılarak referansa göre iletilebilirler.
    _DLLAPI int __stdcall fnCalculateSpeed(int &res1,double &res2)
      {
       int    res_int=0;
       double res_double=0.0;
       int    start=GetTickCount();
    //--- simple math calculations
       for(int i=0;i<=10000000;i++)
         {
          res_int+=i*i;
          res_int++;
          res_double+=i*i;
          res_double++;
         }
    //--- set calculation results
       res1=res_int;
       res2=res_double;
    //--- return calculation time 
       return(GetTickCount()-start);
      }
        
    MQL5'ten çağrı:
    #import "MQL5DLLSamples.dll"
    int  fnCalculateSpeed(int &res1,double &res2);
    #import
    
    //--- calling the function for calculations
       int    speed=0;
       int    res_int=0;
       double res_double=0.0;
    
       speed=fnCalculateSpeed(res_int,res_double);
       Print("Time ",speed," msec, int: ",res_int," double: ",res_double);
    
    Çıktı:
    MQL5DLL Test (GBPUSD,M1) 19:56:42 Time  16  msec, int:  -752584127  double:  17247836076609
  2. Öğeleri dolduran bir diziyi alma ve iletme

    Diğer MQL5 programlarından farklı olarak, dizi geçişi, ebatlar ve boyutlar hakkında özel bilgilere erişim olmadan veri arabelleğine doğrudan referans yoluyla gerçekleştirilir. Bu nedenle dizi ebatı ve boyutu ayrı ayrı iletilmelidir.

    _DLLAPI void __stdcall fnFillArray(int *arr,const int arr_size)
      {
    //--- check for the input parameters
       if(arr==NULL || arr_size<1) return;
    //--- fill array with values
       for(int i=0;i<arr_size;i++) arr[i]=i;
      }
        
    MQL5'ten çağrı:
    #import "MQL5DLLSamples.dll"
    void fnFillArray(int &arr[],int arr_size);
    #import
    
    //--- call for the array filling
       int    arr[];
       string result="Array: "; 
       ArrayResize(arr,10);
       
       fnFillArray(arr,ArraySize(arr));
       for(int i=0;i<ArraySize(arr);i++) result=result+IntegerToString(arr[i])+" ";
       Print(result);
    
    Çıktı:
    MQL5DLL Test (GBPUSD,M1) 20:31:12 Array: 0 1 2 3 4 5 6 7 8 9 
  3. Dizeleri iletme ve değiştirme
    Unicode dizeleri, herhangi bir ek bilgi aktarılmadan arabellek adreslerine doğrudan referanslar kullanılarak iletilir.
    _DLLAPI void fnReplaceString(wchar_t *text,wchar_t *from,wchar_t *to)
      {
       wchar_t *cp;
    //--- parameters check
       if(text==NULL || from==NULL || to==NULL) return;
       if(wcslen(from)!=wcslen(to))             return;
    //--- search for substring
       if((cp=wcsstr(text,from))==NULL)         return;
    //--- replace it
       memcpy(cp,to,wcslen(to)*sizeof(wchar_t));
      }
    
    MQL5'ten çağrı:
    #import "MQL5DLLSamples.dll"
    void fnReplaceString(string text,string from,string to);
    #import
    
    //--- modify the string
       string text="A quick brown fox jumps over the lazy dog"; 
       
       fnReplaceString(text,"fox","cat");
       Print("Replace: ",text);
    Sonuç:
    MQL5DLL Test (GBPUSD,M1) 19:56:42 Replace:  A quick brown fox jumps over the lazy dog
    Çizginin değişmediği ortaya çıktı! Bu, yeni başlayanların, onlara başvurmak yerine nesnelerin kopyalarını (bir dize bir nesnedir) ilettikleri zaman yaptıkları yaygın bir hatadır. DLL'de değiştirilen 'metin' dizesinin kopyası otomatik olarak oluşturuldu ve ardından orijinali etkilemeden otomatik olarak kaldırıldı.

    Bu durumu düzeltmek için bir dizeyi referans olarak iletmek gerekir. Bunu yapmak için, "metin" parametresine & öğesini ekleyerek içe aktarma bloğunu değiştirmeniz yeterlidir:
    #import "MQL5DLLSamples.dll"
    void fnReplaceString(string &text,string from,string to);
    #import
    Derleme işleminden ve başladıktan sonra doğru sonucu elde edeceğiz:
    MQL5DLL Test (GBPUSD,M1) 19:58:31 Replace:  A quick brown cat jumps over the lazy dog

4. DLL işlevlerinde istisnaları yakalama

Terminal çökmelerini önlemek için her DLL çağrısı, İşlenmeyen Özel Durum Paketi ile otomatik olarak korunur. Bu mekanizma, standart hataların çoğundan (bellek erişim hataları, sıfıra bölme vb.) korunmaya olanak tanır

Mekanizmanın nasıl çalıştığını görmek için aşağıdaki kodu oluşturalım:

_DLLAPI void __stdcall fnCrashTest(int *arr)
  {
//--- wait for receipt of a zero reference to call the exception
   *arr=0;
  }

ve onu istemci terminalinden çağıralım:

#import "MQL5DLLSamples.dll"
void fnCrashTest(int arr);
#import

//--- call for the crash (the execution environment will catch the exception and prevent the client terminal crush)
   fnCrashTest(NULL);
   Print("You won't see this text!");
//---

Sonuç olarak, sıfır adrese yazmaya ve bir istisna oluşturmaya çalışacaktır. İstemci terminali onu yakalayacak, günlüğe kaydedecek ve çalışmasına devam edecektir:

MQL5DLL Test (GBPUSD,M1) 20:31:12 Access violation write to 0x00000000

5. DLL çağrıları paketi ve çağrılarda hız kaybı

Yukarıda açıklandığı gibi, güvenliği sağlamak için her DLL işlevi çağrısı özel bir pakete sarılır. Bu bağlayıcı, temel kodu maskeler, yığının yerini alır, stdcall / cdecl anlaşmalarını destekler ve çağrılan işlevler içindeki istisnaları izler.

Bu iş hacmi, işlev çağırmada önemli bir gecikmeye yol açmaz.

6. Son oluşturma

Yukarıdaki tüm DLL işlevleri örneklerini 'MQL5DLLSamples.cpp' dosyasında ve MQL5 örneklerini 'MQL5DLL Test.mq5' script dosyasında toplayalım. Visual Studio 2008 için son proje ve MQL5'teki script dosyası makaleye eklenmiştir.

//+------------------------------------------------------------------+
//|                                                 MQL5 DLL Samples |
//|                   Copyright 2001-2010, MetaQuotes Software Corp. |
//|                                        https://www.metaquotes.net |
//+------------------------------------------------------------------+
#include "stdafx.h"

//+------------------------------------------------------------------+
//| Passing and receving of simple variables                         |
//+------------------------------------------------------------------+
_DLLAPI int __stdcall fnCalculateSpeed(int &res1,double &res2)
  {
   int    res_int=0;
   double res_double=0.0;
   int    start=GetTickCount();
//--- simple math calculations
   for(int i=0;i<=10000000;i++)
     {
      res_int+=i*i;
      res_int++;
      res_double+=i*i;
      res_double++;
     }
//--- set calculation results
   res1=res_int;
   res2=res_double;
//--- return calculation time
   return(GetTickCount()-start);
  }
//+------------------------------------------------------------------+
//| Filling the array with values                                    |
//+------------------------------------------------------------------+
_DLLAPI void __stdcall fnFillArray(int *arr,const int arr_size)
  {
//--- check input variables
   if(arr==NULL || arr_size<1) return;
//--- fill array with values
   for(int i=0;i<arr_size;i++) arr[i]=i;
  }
//+------------------------------------------------------------------+
//| The substring replacement of the text string                     |
//| the string is passed as direct reference to the string content   |
//+------------------------------------------------------------------+
_DLLAPI void fnReplaceString(wchar_t *text,wchar_t *from,wchar_t *to)
  {
   wchar_t *cp;
//--- parameters checking
   if(text==NULL || from==NULL || to==NULL) return;
   if(wcslen(from)!=wcslen(to))             return;
//--- search for substring
   if((cp=wcsstr(text,from))==NULL)         return;
//--- replace it 
   memcpy(cp,to,wcslen(to)*sizeof(wchar_t));
  }
//+------------------------------------------------------------------+
//| Call for the crush                                               |
//+------------------------------------------------------------------+
_DLLAPI void __stdcall fnCrashTest(int *arr)
  {
//--- wait for receipt of a zero reference to call the exception
   *arr=0;
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                 MQL5DLL Test.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//---
#import "MQL5DLLSamples.dll"
int  fnCalculateSpeed(int &res1,double &res2);
void fnFillArray(int &arr[],int arr_size);
void fnReplaceString(string text,string from,string to);
void fnCrashTest(int arr);
#import

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- calling the function for calculations
   int    speed=0;
   int    res_int=0;
   double res_double=0.0;

   speed=fnCalculateSpeed(res_int,res_double);
   Print("Time ",speed," msec, int: ",res_int," double: ",res_double);
//--- call for the array filling
   int    arr[];
   string result="Array: "; 
   ArrayResize(arr,10);
   
   fnFillArray(arr,ArraySize(arr));
   for(int i=0;i<ArraySize(arr);i++) result=result+IntegerToString(arr[i])+" ";
   Print(result);
//--- modifying the string
   string text="A quick brown fox jumps over the lazy dog"; 
   
   fnReplaceString(text,"fox","cat");
   Print("Replace: ",text);
//--- and finally call a crash
//--- (the execution environment will catch the exception and prevent the client terminal crush)
   fnCrashTest(NULL);
   Print("You won't see this text!");
//---
  }
//+------------------------------------------------------------------+

Gösterdiğiniz ilgi için teşekkürler! Tüm sorularınızı yanıtlamaya hazırım.

MetaQuotes Ltd tarafından Rusçadan çevrilmiştir.
Orijinal makale: https://www.mql5.com/ru/articles/18

Ekli dosyalar |
mql5dll_test.mq5 (1.83 KB)
mql5dllsamples.zip (4.62 KB)
Göstergeler Arası Veri Değişimi: Bu Kolaydır Göstergeler Arası Veri Değişimi: Bu Kolaydır
Bir grafiğe eklenmiş göstergelerin verilerine erişim sağlayacak ve şu özelliklere sahip olacak şöyle bir ortam oluşturmak istiyoruz: Veri kopyalama olmaması, kullanmamız gerekirse mevcut yöntemlerin kodunun minimum düzeyde değiştirilmesi, MQL kodunun tercih edilebilir olması (elbette DLL kullanmak zorundayız, ancak yalnızca bir düzine C++ kodu dizesi kullanacağız). Makalede, MetaTrader terminali için diğer MQL programlarından gösterge arabelleklerine erişmek için araçlar sağlayacak bir program ortamı geliştirmek için kolay bir yöntem açıklanmaktadır.
Fiyat Histogramı (Piyasa Profili) ve MQL5'te uygulanması Fiyat Histogramı (Piyasa Profili) ve MQL5'te uygulanması
Piyasa Profili, gerçekten parlak bir düşünür olan Peter Steidlmayer tarafından geliştirildi. Tamamen farklı model kümelerine yol açan "yatay" ve "dikey" piyasa hareketleri hakkındaki bilgilerin alternatif temsilini kullanmayı önerdi. Piyasanın altında yatan bir nabzın ya da denge ve dengesizlik döngüsü adı verilen temel bir modelin olduğunu varsaydı. Bu makalede, Piyasa Profilinin basitleştirilmiş bir modeli olan Fiyat Histogramını ele alacak ve MQL5'te uygulanmasını anlatacağım.
MQL5'te Gösterge Emisyonlarının Çizimi MQL5'te Gösterge Emisyonlarının Çizimi
Bu makalede, piyasa araştırmasına yeni bir yaklaşım olan göstergelerin emisyonunu ele alacağız. Emisyon hesaplaması, farklı göstergelerin kesişimine dayanmaktadır: Her tick'ten sonra farklı renk ve şekillerde daha fazla nokta belirir. Bulutsular, bulutlar, parçalar, çizgiler, kavisler vb. gibi çok sayıda küme oluştururlar. Bu şekiller, piyasa fiyatlarının hareketini etkileyen görünmez kavisleri ve güçleri tespit etmeye yardımcı olur.
MQL5.community kanallarını ve grup sohbetlerini kullanın MQL5.community kanallarını ve grup sohbetlerini kullanın
MQL5.com web sitesi dünyanın her yerinden yatırımcıları bir araya getirir. Kullanıcılar makaleler yayınlar, ücretsiz kodlar paylaşır, Mağazada ürünler satar, Freelance siparişleri gerçekleştirir ve ticaret sinyallerini kopyalar. Diğer kullanıcılarla Forumdan, yatırımcı sohbetlerinden ve MetaTrader kanallarından iletişim kurabilirsiniz.