no se llama cerrar el registro, se llama cerrar y borrar el archivo.
que es por lo que
estás intentando abrir algo que ya no existe.
Revisando el código de la librería he visto que el fichero se borra no sólo cuando se llama directamente a la función Close() de la clase CMemMapFile, sino también cuando se borra el puntero al objeto de esta clase, porque esta función se llama en el destructor de la clase. Estoy un poco perplejo. Resulta que el método dinámico de creación de objetos de clase no se puede utilizar si la escritura y la lectura de un archivo se utilizan en diferentes contextos de llamada (ámbitos). Por ejemplo, un gráfico del terminal escribe datos en un archivo, el segundo lee datos y borra este archivo. Resulta que la variable de objeto debe mantenerse siempre a nivel global, para que el fichero no se borre a la fuerza. Tampoco está claro si es posible prescindir de especificar el tamaño de los datos leídos. Es decir, conocemos el tamaño de los datos al escribirlos, pero al leerlos en otro gráfico podemos no conocer de antemano el tamaño de los datos, como por ejemplo en el caso de valores de cadena. Probablemente o he entendido algo mal o hay algo más que retocar en la librería.
Error mío. Lo he vuelto a comprobar sin usar el puntero y por tanto sin usar delete. En este caso, al salir del ámbito (desde una función), la variable local del objeto de clase se destruye sin una llamada explícita al destructor.
Queda una duda sobre el tamaño de los datos recibidos en el lado del receptor.
#include <MemMapLib.mqh>
#include <TypeToBytes.mqh>
template <typename T>
class EXCHANGE_DATA
{
private:
CMemMapFile* FileMemory;
public:
// Asigna memoria de la longitud especificada para los datos
EXCHANGE_DATA( constint Amount, constbool ModeCreate = false, string FileName = "Local\\test" )
{
// FileName += _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();
deletethis.FileMemory;
}
// Escribe datos en la memoriavoid DataSave( const T &Data[], constbool FromBegin = true ) const
{
constint Size = ::ArraySize(Data) * sizeof(T);
uchar Bytes[];
_ArrayCopy(Bytes, _R(Size).Bytes); // Registrada la cantidad
_ArrayCopy(Bytes, _R(Data).Bytes, sizeof(int)); // Grabación de los datosif (FromBegin)
this.FileMemory.Seek(0, SEEK_SET);
this.FileMemory.Write(Bytes, ::ArraySize(Bytes)); // Volcado de todo en la memoriareturn;
}
// Lee datos de la memoriaint DataLoad( T &Data[], constbool FromBegin = true ) const
{
if (FromBegin)
this.FileMemory.Seek(0, SEEK_SET);
uchar Bytes[];
this.FileMemory.Read(Bytes, sizeof(int)); // Leer la cantidad de datos de la memoria this.FileMemory.Read(Bytes, _R(Bytes)[0]); // Obtener los datos propiamente dichos
_ArrayCopy(Data, Bytes); // Volcado de los datos en un arrayreturn(::ArraySize(Data));
}
};
La librería tiene un pequeño error en el método CMemMapFile::Open. Debería devolver el manejador del fichero (tipo HANDLE64), pero en su lugar devuelve 0 o un código de error.
Además, los métodos de lectura y escritura CMemMapApi::Write y CMemMapApi::Read por alguna razón duplican la recopilación de datos (¡y los bytes se repiten en bucle!), y además el fichero se sobreescribe/lee en su totalidad, aunque sólo se necesite un trozo especificado.
En general, he hecho que se vean normales, las cosas innecesarias están comentadas :
//------------------------------------------------------------------ Writeint CMemMapApi::Write(HANDLE64 hmem, constuchar &buf[], DWORD pos, int sz, DWORD &err) // escribir el número especificado de bytes en la memoria
{
if (hmem==NULL) return(-1);
PBYTE64 view=ViewFile(hmem, err); if (view==0 || err!=0) return(-1); // si no está abierto
DWORD size=GetSize(hmem, err); if (pos+sz>size) { UnViewFile(view); return(-2); }; // si el tamaño es menor, salir/*
uchar src[]; ArrayResize(src, size); memcpyX(src, view, size); // tomó bytebuffer
for(int i=0; i<sz; i++) src[pos+i+HEAD_MEM]=buf[i]; // escribir en memoria
memcpyX(view, src, size); // copiar de vuelta
*/
memcpyX(view+HEAD_MEM+pos, buf, sz);
UnViewFile(view); // cerrar la vistareturn(0); // devuelto OK.
}
//------------------------------------------------------------------ Readint CMemMapApi::Read(HANDLE64 hmem, uchar &buf[], DWORD pos, int sz, DWORD &err) // leer de la memoria el número especificado de bytes
{
if (hmem==NULL) return(-1);
PBYTE64 view=ViewFile(hmem, err); if (view==0 || err!=0) return(-1); // si no está abierto
DWORD size=GetSize(hmem, err); // tengo el tamaño/*
uchar src[]; ArrayResize(src, tamaño); memcpyX(src, vista, tamaño); // tomó bytebuffer
ArrayResize(buf, sz);
int i=0; for(i=0; i<sz && pos+i<size; i++) buf[i]=src[pos+i+HEAD_MEM]; // lee bytes
*/
sz= fmin(sz, size-pos);
ArrayResize(buf, sz);
memcpyX(buf, view+HEAD_MEM+pos, sz);
UnViewFile(view); // cerrar la vistareturn sz; // número de bytes copiados
}
Para hacer que la primera función compile, necesitas establecer const para los arrays en las funciones memcpyX y memcpy, que el autor no se molestó en establecer.
no se llama cerrar el registro, se llama cerrar y borrar el archivo.
que es por lo que
estás intentando abrir algo que ya no existe.Revisando el código de la librería he visto que el fichero se borra no sólo cuando se llama directamente a la función Close() de la clase CMemMapFile, sino también cuando se borra el puntero al objeto de esta clase, porque esta función se llama en el destructor de la clase. Estoy un poco perplejo. Resulta que el método dinámico de creación de objetos de clase no se puede utilizar si la escritura y la lectura de un archivo se utilizan en diferentes contextos de llamada (ámbitos). Por ejemplo, un gráfico del terminal escribe datos en un archivo, el segundo lee datos y borra este archivo. Resulta que la variable de objeto debe mantenerse siempre a nivel global, para que el fichero no se borre a la fuerza. Tampoco está claro si es posible prescindir de especificar el tamaño de los datos leídos. Es decir, conocemos el tamaño de los datos al escribirlos, pero al leerlos en otro gráfico podemos no conocer de antemano el tamaño de los datos, como por ejemplo en el caso de valores de cadena. Probablemente o he entendido algo mal o hay algo más que retocar en la librería.
Error mío. Lo he vuelto a comprobar sin usar el puntero y por tanto sin usar delete. En este caso, al salir del ámbito (desde una función), la variable local del objeto de clase se destruye sin una llamada explícita al destructor.
Queda una duda sobre el tamaño de los datos recibidos en el lado del receptor.
¡Gracias al autor por la biblioteca!
Hice funciones para transferir cualquier dato. El script de abajo muestra su trabajo en el ejemplo de ticks
Resultado
¡Super! Por analogía con su código he simplificado el uso de la biblioteca para mí.
Foro sobre trading, sistemas automatizados de trading y prueba de estrategias de trading
NamedPipes para metatrader 4
fxsaber, 2017.11.30 14:18
Exchange_Data.mqh
PriceGiver.mq4
PriceTaker.mq4
Ejecutar PriceGiver.ex4 y PriceTaker.ex4.
Resultado
La librería tiene un pequeño error en el método CMemMapFile::Open. Debería devolver el manejador del fichero (tipo HANDLE64), pero en su lugar devuelve 0 o un código de error.
Además, los métodos de lectura y escritura CMemMapApi::Write y CMemMapApi::Read por alguna razón duplican la recopilación de datos (¡y los bytes se repiten en bucle!), y además el fichero se sobreescribe/lee en su totalidad, aunque sólo se necesite un trozo especificado.
En general, he hecho que se vean normales, las cosas innecesarias están comentadas :
Para hacer que la primera función compile, necesitas establecer const para los arrays en las funciones memcpyX y memcpy, que el autor no se molestó en establecer.Error al copiar tamaños grandes, debido a que se pasaba cero en dwMaximumSizeHigh
Arreglado así:
Este tamaño - 6 mb, se transfiere sin problemas:
Corregido así:
Pasar correctamente los 4 bytes altos del tamaño de 8 bytes allí.
Ok, ahora tenemos todos los raites en el programa C# y podemos analizar todo lo que necesitamos usando LINQ.
Pero hay una pregunta, cómo organizar el mecanismo de comandos entre el terminal y la aplicación.
Desde el terminal: nueva vela, nuevos raites - tomar el archivo
Desde la aplicación: cálculo completado, tomar el resultado (dibujar en el gráfico, abrir una operación).
¿Alguien tiene experiencia en este tipo de implementación de la interacción entre el terminal y el código?
Ok, ahora tenemos todos los raites en un programa C# y podemos usar LINQ para analizarlo todo perfectamente.
Pero hay una pregunta, cómo organizar el mecanismo de comandos entre el terminal y la aplicación.
Desde el terminal: nueva vela, nuevas tarifas - obtener el archivo
Desde la aplicación: cálculo finalizado, tomar el resultado (dibujarlo en el gráfico, abrir una operación).
¿Alguien tiene experiencia con este tipo de aplicación de la interacción entre el terminal y el código?
Por favor, aconséjeme qué hacer en esta situación.
1. Abrí un nuevo archivo en memoria con 100 bytes.
2. Escribí 100 bytes en él.
3. Leí 100 bytes en otro Asesor Experto. Todo va bien.
4. Ahora, ¿cómo escribir 50 o 200 bytes en el mismo archivo?