Пересылка структур через Named Pipes

 

Приветы,

Решил открыть ордер из кода на C#, передав всю информацию об ордере в советник на MQL5, воссоздал в коде C# копию MqlTradeRequest ... и все почти хорошо, но почему-то одно из полей структуры, приходит всегда равным 0 - что это за магия?

Вот так структура описана в MQL5 :

struct OrderData
{
    double SL;
    double TP;
    double Price;
    double Volume;
    double StopLevel;
    ulong Magic;
    ulong Ticket;
    ulong Deviation;
    ulong Expiration;
    ENUM_ORDER_TYPE Type;
    ENUM_ORDER_TYPE_TIME TypeTime;
    ENUM_TRADE_REQUEST_ACTIONS Action; // вот это поле почему-то всегда равно 0
    ENUM_ORDER_TYPE_FILLING TypeFilling;
};

Вот С# :

[StructLayout(LayoutKind.Sequential)] // данные идут последовательно, без процессорной оптимизации
    public struct OrderData
    {
        public double SL { get; set; }
        public double TP { get; set; }
        public double Price { get; set; }
        public double Volume { get; set; }
        public double StopLevel { get; set; }
        public ulong Magic { get; set; }
        public ulong Ticket { get; set; }
        public ulong Deviation { get; set; }
        public ulong Expiration { get; set; }
        public ENUM_ORDER_TYPE Type { get; set; }
        public ENUM_ORDER_TYPE_TIME TypeTime { get; set; }
        public ENUM_TRADE_REQUEST_ACTIONS Action { get; set; }
        public ENUM_ORDER_TYPE_FILLING TypeFilling { get; set; }
    }

Данные передаются в виде Byte Array, ничего С# специфичного не используется. Читаю пайп наиобычнейшим образом, как в одной из статей на сайте :

while(IsStopped() == false)
{
      if (iPipe.Open(Address, FILE_READ | FILE_WRITE | FILE_BIN) != INVALID_HANDLE) break;
      Sleep(250);
}

OrderData orderData;

iPipe.ReadStruct(orderData);

MqlTradeResult result;
MqlTradeRequest query;

query.magic = iMagic;
query.symbol = _Symbol;
 
if (order.Volume > 0)
{
        //query.action = TRADE_ACTION_DEAL; // если вручную ставить здесь - запрос проходит успешно
        query.action = order.Action; // если брать значение, считанное из пайпа - то будет 0 и запрос вернет код 10013 - Неправильный запрос
        query.volume = order.Volume;
        query.price = order.Price;
        query.tp = order.TP;
        query.sl = order.SL;
        query.deviation = order.Deviation;
        query.type = order.Type;
        query.type_filling = order.TypeFilling;
        query.type_time = order.TypeTime;
        
        OrderSend(query, result);
}

Я думал, может это выравнивание значений по размерам полей (процессорная оптимизация - типа такое-то поле занимает не меньше чем столько-то байтов) или есть другие идеи?

Для наглядности, вот какие данные приходят при дебаге :

Error

 

Проверьте размеры структуры через sizeof в MQL5 и в C#.

Наверняка автоматическое выравнивание полей структуры ради производительности в С# сыграло злую шутку.

 
artemiusgreat:

Приветы,

...

Я думал, может это выравнивание значений по размерам полей (процессорная оптимизация - типа такое-то поле занимает не меньше чем столько-то байтов) или есть другие идеи?

....
Сравните размер типов enum в mql и .Net
Документация по MQL5: Основы языка / Типы данных / Целые типы / Перечисления
Документация по MQL5: Основы языка / Типы данных / Целые типы / Перечисления
  • www.mql5.com
Основы языка / Типы данных / Целые типы / Перечисления - Документация по MQL5
 
  1. каждая ENUM и в MQL и в C# занимает 4 байта
  2. общий размер структуры равен 88 байт и в MQL и в C#
  3. если переставить поля структуры таким образом в обоих местах, то ничего не изменится - поле Action все равно 0 : 
public struct OrderData
    {
        public double SL { get; set; }
        public double TP { get; set; }
        public double Price { get; set; }
        public double Volume { get; set; }
        public double StopLevel { get; set; }
        public ulong Magic { get; set; }
        public ulong Ticket { get; set; }
        public ulong Deviation { get; set; }
        public ulong Expiration { get; set; }
        public ENUM_TRADE_REQUEST_ACTIONS Action { get; set; } // попробовал сделать его первым ENUM в списке
        public ENUM_ORDER_TYPE Type { get; set; }
        public ENUM_ORDER_TYPE_TIME TypeTime { get; set; }
        public ENUM_ORDER_TYPE_FILLING TypeFilling { get; set; }
    }

если переставить это поле в начало структуры - то на стороне MQL структура не читается вообще, вечное ожидание ответа сервера на методе iPipe.ReadStruct(trade) :

public struct OrderData
    {
        public ENUM_TRADE_REQUEST_ACTIONS Action { get; set; } // при таком порядке структура не видна клиенту MQL
        public double SL { get; set; }
        public double TP { get; set; }
        public double Price { get; set; }
        public double Volume { get; set; }
        public double StopLevel { get; set; }
        public ulong Magic { get; set; }
        public ulong Ticket { get; set; }
        public ulong Deviation { get; set; }
        public ulong Expiration { get; set; }
        public ENUM_ORDER_TYPE Type { get; set; }
        public ENUM_ORDER_TYPE_TIME TypeTime { get; set; }
        public ENUM_ORDER_TYPE_FILLING TypeFilling { get; set; }
    }

что-то не так с передачей ENUM, наверное придется передавать INT значения

Причина обращения: