Bibliotheken: Abbildungsdateien ohne DLL - Seite 11

 
o_o:

Es heißt nicht "Schließen des Datensatzes", sondern "Schließen und Löschen der Datei ".

Das ist der Grund

Sie versuchen, etwas zu öffnen, das nicht mehr existiert.

Beim Durchsehen des Bibliothekscodes habe ich gesehen, dass die Datei nicht nur gelöscht wird, wenn die Funktion Close() der Klasse CMemMapFile direkt aufgerufen wird, sondern auch, wenn der Zeiger auf das Objekt dieser Klasse gelöscht wird, da diese Funktion im Destruktor der Klasse aufgerufen wird. Ich bin ein wenig ratlos. Es stellt sich heraus, dass die dynamische Methode zur Erstellung von Klassenobjekten nicht verwendet werden kann, wenn das Schreiben und Lesen einer Datei in unterschiedlichen Aufrufkontexten (Scopes) verwendet wird. Zum Beispiel schreibt ein Diagramm des Terminals Daten in eine Datei, das zweite liest Daten und löscht diese Datei. Es stellt sich heraus, dass die Objektvariable immer auf der globalen Ebene gehalten werden sollte, damit die Datei nicht zwangsweise gelöscht wird. Es ist auch nicht klar, ob es möglich ist, auf die Angabe der Größe der gelesenen Daten zu verzichten. Das heißt, wir kennen die Größe der Daten, wenn wir sie schreiben, aber wenn wir sie auf einem anderen Diagramm lesen, kennen wir die Größe der Daten möglicherweise nicht im Voraus, wie zum Beispiel im Fall von String-Werten. Wahrscheinlich habe ich entweder etwas falsch verstanden oder es gibt noch etwas in der Bibliothek zu optimieren.

Mein Fehler. Ich habe es noch einmal überprüft, ohne den Zeiger zu verwenden und daher auch ohne delete. In diesem Fall wird die lokale Variable des Klassenobjekts beim Verlassen des Geltungsbereichs (aus einer Funktion) ohne expliziten Aufruf des Destruktors zerstört.

Es bleibt noch die Frage nach der Größe der empfangenen Daten auf der Seite des Empfängers.

 
fxsaber:

Vielen Dank an den Autor für die Bibliothek!

Ich habe Funktionen für die Übertragung beliebiger Daten erstellt. Das folgende Skript zeigt ihre Arbeit am Beispiel von Zecken


Ergebnis


Super! In Analogie zu Ihrem Code habe ich mir die Verwendung der Bibliothek vereinfacht.

 
Beispiel einer Kursübertragung für MT4

Forum zum Thema Handel, automatisierte Handelssysteme und Testen von Handelsstrategien

NamedPipes für metatrader 4

fxsaber, 2017.11.30 14:18

Exchange_Data.mqh

#include <MemMapLib.mqh>
#include <TypeToBytes.mqh>

template <typename T>
class EXCHANGE_DATA
{
private:
  CMemMapFile* FileMemory;

public:  
  // Weist Speicher der angegebenen Länge für die Daten zu 
  EXCHANGE_DATA( const int Amount, const bool ModeCreate = false, string FileName = "Local\\test" )
  {
// Dateiname += _Symbol;
    
    this.FileMemory = new CMemMapFile;
      
    if (this.FileMemory.Open(FileName, sizeof(T) * Amount + sizeof(int) + HEAD_MEM, ModeCreate ? modeCreate : modeOpen) != 0)
    {
      Alert("FileMemory.Open - ERROR!");
      
      delete &this;
    }
  }
  
  ~EXCHANGE_DATA( void )
  {
    this.FileMemory.Close();
    
    delete this.FileMemory;
  }

  // Schreibt Daten in den Speicher
  void DataSave( const T &Data[], const bool FromBegin = true  ) const
  {
    const int Size = ::ArraySize(Data) * sizeof(T);
    uchar Bytes[];
    
    _ArrayCopy(Bytes, _R(Size).Bytes);              // Aufzeichnung der Menge 
    _ArrayCopy(Bytes, _R(Data).Bytes, sizeof(int)); // Aufzeichnung der Daten
  
        if (FromBegin)
          this.FileMemory.Seek(0, SEEK_SET);
  
        this.FileMemory.Write(Bytes, ::ArraySize(Bytes)); // Alles in den Speicher entladen
    
    return;
  }
  
  // Liest Daten aus dem Speicher
  int DataLoad( T &Data[], const bool FromBegin = true ) const
  {
        if (FromBegin)
          this.FileMemory.Seek(0, SEEK_SET);
  
        uchar Bytes[];
          
        this.FileMemory.Read(Bytes, sizeof(int));  // Lesen der Datenmenge aus dem Speicher 
        this.FileMemory.Read(Bytes, _R(Bytes)[0]); // Ich habe die Daten selbst
  
        _ArrayCopy(Data, Bytes);              // Dumped die Daten in ein Array
    
    return(::ArraySize(Data));
  }  
};


PriceGiver.mq4

#property strict

#include "Exchange_Data.mqh"

#define  AMOUNT 100

EXCHANGE_DATA<MqlTick> ExchangeTicks(AMOUNT, true);

const bool Init = EventSetMillisecondTimer(100);

void OnTimer( void )
{
  static MqlTick Ticks[1];
  
  if (SymbolInfoTick(_Symbol, Ticks[0]))
    ExchangeTicks.DataSave(Ticks);
}


PriceTaker.mq4

#property strict

#include "Exchange_Data.mqh"

#define  AMOUNT 100

EXCHANGE_DATA<MqlTick> ExchangeTicks(AMOUNT);

const bool Init = EventSetMillisecondTimer(100);

#define  TOSTRING(A) (#A + " = " + (string)(A) + " ")

void OnTimer( void )
{  
  static MqlTick PrevTick = {0};  
  MqlTick Ticks[];
  
  if ((ExchangeTicks.DataLoad(Ticks) > 0) &&
      ((Ticks[0].bid != PrevTick.bid) || (Ticks[0].ask != PrevTick.ask)))
  {
    Print(TOSTRING(Ticks[0].time) + TOSTRING(Ticks[0].bid) + TOSTRING(Ticks[0].ask));
    
    PrevTick = Ticks[0];
  }
}


Führen Sie PriceGiver.ex4 und PriceTaker.ex4 aus.


Ergebnis

2017.11.30 15:13:55.101 Expert PriceGiver EURUSD,M1: removed
2017.11.30 15:13:55.091 PriceGiver EURUSD,M1: uninit reason 1
2017.11.30 15:13:51.006 Expert PriceTaker GBPAUD,M1: removed
2017.11.30 15:13:50.996 PriceTaker GBPAUD,M1: uninit reason 1
2017.11.30 15:13:49.168 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:41 Ticks[0].bid = 1.18483 Ticks[0].ask = 1.18487 
2017.11.30 15:13:48.838 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:41 Ticks[0].bid = 1.18484 Ticks[0].ask = 1.18489 
2017.11.30 15:13:48.186 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:40 Ticks[0].bid = 1.18483 Ticks[0].ask = 1.18487 
2017.11.30 15:13:47.751 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:40 Ticks[0].bid = 1.18484 Ticks[0].ask = 1.18488 
2017.11.30 15:13:42.178 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:34 Ticks[0].bid = 1.18485 Ticks[0].ask = 1.18489 
2017.11.30 15:13:41.633 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:34 Ticks[0].bid = 1.18484 Ticks[0].ask = 1.18488 
2017.11.30 15:13:37.588 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:30 Ticks[0].bid = 1.18483 Ticks[0].ask = 1.18487 
2017.11.30 15:13:36.175 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:28 Ticks[0].bid = 1.18481 Ticks[0].ask = 1.18485 
2017.11.30 15:13:30.717 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:23 Ticks[0].bid = 1.18482 Ticks[0].ask = 1.18486 
2017.11.30 15:13:29.514 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:22 Ticks[0].bid = 1.18483 Ticks[0].ask = 1.18487 
2017.11.30 15:13:27.324 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:19 Ticks[0].bid = 1.1848 Ticks[0].ask = 1.18484 
2017.11.30 15:13:26.994 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:19 Ticks[0].bid = 1.18482 Ticks[0].ask = 1.18486 
2017.11.30 15:13:26.012 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:18 Ticks[0].bid = 1.18481 Ticks[0].ask = 1.18485 
2017.11.30 15:13:25.584 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:18 Ticks[0].bid = 1.18482 Ticks[0].ask = 1.18486 
2017.11.30 15:13:25.254 PriceTaker GBPAUD,M1: Ticks[0].time = 2017.11.30 15:13:16 Ticks[0].bid = 1.18481 Ticks[0].ask = 1.18485 
2017.11.30 15:13:25.147 PriceTaker GBPAUD,M1: initialized
2017.11.30 15:13:24.049 Expert Sparring\PriceTaker GBPAUD,M1: loaded successfully
2017.11.30 15:13:21.157 PriceGiver EURUSD,M1: initialized
2017.11.30 15:13:19.617 Expert Sparring\PriceGiver EURUSD,M1: loaded successfully
 

Die Bibliothek hat einen kleinen Fehler in der Methode CMemMapFile::Open, die eigentlich das Dateihandle (Typ HANDLE64) zurückgeben sollte, aber stattdessen 0 oder einen Fehlercode zurückgibt.

Außerdem werden bei den Lese- und Schreibmethoden CMemMapApi::Write und CMemMapApi::Read aus irgendeinem Grund Daten doppelt kopiert (und Bytes werden durchgeschleift!), und außerdem wird die Datei komplett überschrieben/gelesen, obwohl nur ein bestimmter Teil benötigt wird.

Im Allgemeinen habe ich sie normal aussehen lassen, das unnötige Zeug ist auskommentiert:

//------------------------------------------------------------------ Write
int CMemMapApi::Write(HANDLE64 hmem, const uchar &buf[], DWORD pos, int sz, DWORD &err) // Schreiben der angegebenen Anzahl von Bytes in den Speicher
{
  if (hmem==NULL) return(-1);
  PBYTE64 view=ViewFile(hmem, err);  if (view==0 || err!=0) return(-1); // wenn nicht geöffnet
  DWORD size=GetSize(hmem, err);  if (pos+sz>size) { UnViewFile(view);  return(-2); }; // wenn die Größe kleiner ist, beenden
  /* 
 uchar src[]; ArrayResize(src, size); memcpyX(src, view, size); // nahm Bytebuffer
 for(int i=0; i<sz; i++) src[pos+i+HEAD_MEM]=buf[i]; // in den Speicher schreiben
 memcpyX(view, src, size); // zurück kopieren
 */    
  memcpyX(view+HEAD_MEM+pos, buf, sz);  
  UnViewFile(view); // Schließen der Ansicht
  return(0); // OK zurückgegeben.
}
//------------------------------------------------------------------ Read
int CMemMapApi::Read(HANDLE64 hmem, uchar &buf[], DWORD pos, int sz, DWORD &err) // Lesen der angegebenen Anzahl von Bytes aus dem Speicher
{
  if (hmem==NULL) return(-1);
  PBYTE64 view=ViewFile(hmem, err);  if (view==0 || err!=0) return(-1); // wenn nicht geöffnet
  DWORD size=GetSize(hmem, err); // hat die Größe
  /* 
 uchar src[]; ArrayResize(src, size); memcpyX(src, view, size); // nahm Bytebuffer
 ArrayResize(buf, sz);
 int i=0; for(i=0; i<sz && pos+i<size; i++) buf[i]=src[pos+i+HEAD_MEM]; // Bytes lesen
 */    
  sz= fmin(sz, size-pos);
  ArrayResize(buf, sz);
  memcpyX(buf, view+HEAD_MEM+pos, sz);
  UnViewFile(view); // Schließen der Ansicht
  return sz; // Anzahl der kopierten Bytes
}
Damit die erste Funktion kompiliert werden kann, müssen Sie const für Arrays in den Funktionen memcpyX und memcpy setzen, was der Autor nicht getan hat.
 

Fehler beim Kopieren großer Größen, da in dwMaximumSizeHigh eine Null übergeben wurde

        if (mode==modeCreate) 
           hmem=CreateFileMappingWX(INVALID_HANDLE_VALUE64, NULL, PAGE_READWRITE, 0, size + HEAD_MEM, path); // Erstellen eines Speicherobjekts

Ich habe es folgendermaßen korrigiert:

if (mode==modeCreate) 
           hmem=CreateFileMappingWX(INVALID_HANDLE_VALUE64, NULL, PAGE_READWRITE, size + HEAD_MEM, size + HEAD_MEM, path); // Erstellen eines Speicherobjekts


Diese Größe - 6 mb, wird ohne Probleme übertragen:

void OnStart()
{
   int bars = Bars(_Symbol, _Period);
   MqlRates rates[]; 
   ArraySetAsSeries(rates, true); 
   CopyRates(NULL, 0, 0, bars, rates); 

   int size = ArraySize(rates) * sizeof(MqlRates);
   
   uchar data[];
   _ArrayCopy(data, rates);
   
   CMemMapFile *hmem = new CMemMapFile();
   hmem.Open("test", size, modeCreate);
   hmem.Write(data, size);
   hmem.Close(); 
   delete hmem;

   Print(size);
}


 
pushdib:

Korrigieren Sie es so:

Übergeben Sie die oberen 4 Bytes der 8-Byte-Größe ordnungsgemäß.

 

Ok, jetzt haben wir alle Raites im C#-Programm und können alles, was wir brauchen, mit LINQ analysieren.

Aber es stellt sich die Frage, wie wir den Mechanismus der Befehle zwischen dem Terminal und der Anwendung organisieren.

Vom Terminal: neue Kerze, neue Raite - Datei übernehmen

Von der Anwendung: Berechnung abgeschlossen, das Ergebnis übernehmen (auf dem Chart zeichnen, ein Geschäft öffnen).


Hat jemand Erfahrung mit einer solchen Implementierung der Interaktion zwischen Terminal und Code?

 
pushdib:

Ok, jetzt haben wir alle Raites in einem C#-Programm und können LINQ verwenden, um alles perfekt zu analysieren.

Aber es stellt sich die Frage, wie wir den Mechanismus der Befehle zwischen dem Terminal und der Anwendung organisieren können.

Vom Terminal aus: neue Kerze, neue Raten - die Datei holen

Von der Anwendung: Berechnung abgeschlossen, Ergebnis übernehmen (auf dem Chart zeichnen, ein Geschäft öffnen).


Hat jemand Erfahrung mit einer solchen Umsetzung der Interaktion zwischen Terminal und Code?

Ich habe es alle durch Pip - funktioniert wie am Schnürchen.
 
Das ist einfach genial, danke für die Mühe! -)). Ich musste gleichzeitig lernen, wie man mit Binärdateien arbeitet, aber das war es wert.
 

Bitte beraten Sie mich, was in dieser Situation zu tun ist.

1. ich habe eine neue Datei im Speicher mit 100 Bytes geöffnet.

2. Ich habe 100 Bytes in die Datei geschrieben.

3. Ich habe 100 Bytes in einem anderen Expert Advisor gelesen. Alles ist in Ordnung.

4. Wie kann ich nun 50 oder 200 Bytes in dieselbe Datei schreiben?