Передача структуры в dll C++ - страница 2

 
AndreyKrivcov:

Тест из MT5


во первых вы очевидно пашете память - "USDCHF"L это уже 12 байт а вы 10 отвели.   Далее все функции должны быть __stdcall . Указатели нельзя передавать ни внутрь DLL ни оттуда, все строки должны быть как массивы wchar_t
 

struct Quotes

  {

   char              Symb[16];

   double            bid;

   double            ask;

   double            last;

   double            open;

   double            high;

   double            low;

   double            close;

   long              volume;

   long              tickVolume;

   int               timeFrame;

   unsigned long     DT;

  };

//+------------------------------------------------------------------+

//|                                                                  |

//+------------------------------------------------------------------+

struct TOrders_ans

  {

   char              Symb[16];

   double            SL,TP,Order;

   int               lot;

   int               filler;

  };


N 0 14:51:05.120 test_dll (EURUSD,M30) Cpp_callRobot returned true

OE 0 14:51:05.121 test_dll (EURUSD,M30) SoS  data || SL: 2.0 || TP: 3.0 || Order: 1.0 || lot: 0

MI 0 14:51:05.121 test_dll (EURUSD,M30) SoS  data || SL: 3.0 || TP: 4.0 || Order: 2.0 || lot: 1

KM 0 14:51:05.121 test_dll (EURUSD,M30) SoS  data || SL: 4.0 || TP: 5.0 || Order: 3.0 || lot: 2

 

orders[i].Symb[0]='S';

orders[i].Symb[1]='o';

orders[i].Symb[2]='S';

orders[i].Symb[3]=' ';

orders[i].Symb[4]='\0';

 

Мой вариант для MT5(64 бита).

Структуры в VS под x64 выравниваются к размеру указателя, т.е. 8 байт, а в MQL выравнивание всегда 1 байт. Поэтому в MQL5 структурах добавлены вставки int _align.

.h

#pragma once
#include <string>

#define _TO_MQL_ extern "C" __declspec(dllexport)

struct Quotes
{
        char Symb[16];
        double bid;
        double ask;
        double last;
        double open;
        double high;
        double low;
        double close;
        __int64 volume;
        __int64 tickVolume;
        int timeFrame;
        __int64 DT;
};

typedef struct QuotesArr
{
        unsigned int size;
        Quotes quote_data[3];
};

typedef struct TOrders_ans
{
        char Symb[16];
        int lot;
        double SL;
        double TP;
        double Order;
};

_TO_MQL_ int __stdcall Cpp_callRobot(QuotesArr * arr, int row, TOrders_ans *orders, int *orders_row);

.cpp

#include "Header.h"
#include<io.h>
#include<fstream>
#include<ctime>
#include <Windows.h>

#include <direct.h>

//#pragma hdstop
//#pragma argsused


std::string path = "C:\\Users\\Андрей\\Desktop\\Test Mql5.txt";

BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
        return(TRUE);
}

_TO_MQL_ int __stdcall Cpp_callRobot(QuotesArr * arr, int row, TOrders_ans *orders, int *orders_row)
{
        std::ofstream out;
        if (_access(path.c_str(), 0) == -1)
                out = std::ofstream(path.c_str());
        else
                out = std::ofstream(path.c_str(), std::ios::app);
        out << "Cpp_callRobot" << std::endl;

        bool ans = false;
        if (arr != nullptr)
        {
                ans = true;

                for (int i = 0; i < row; i++)
                {
                        out << (int)arr[i].size << std::endl;
                        
                                                for (int j = 0; j < (int)arr[i].size; j++)
                                                {
                        
                                                        out << "i =" << i << " | j = " << j << std::endl;

                                                        std::string symb(arr[i].quote_data[j].Symb);

                                                        std::string S = symb + ";" + std::to_string(arr[i].quote_data[j].bid) + ";" + std::to_string(arr[i].quote_data[j].ask) + ";" +
                                                                std::to_string(arr[i].quote_data[j].last) + ";" + std::to_string(arr[i].quote_data[j].open) + ";" + std::to_string(arr[i].quote_data[j].high) + ";" +
                                                                std::to_string(arr[i].quote_data[j].low) + ";" + std::to_string(arr[i].quote_data[j].close) + std::to_string(arr[i].quote_data[j].volume) + ";" +
                                                                std::to_string(arr[i].quote_data[j].tickVolume) + ";" + std::to_string(arr[i].quote_data[j].timeFrame) + ";" + std::to_string(arr[i].quote_data[j].DT);
                                                        out << S << std::endl;
                                                        //MessageBoxA(0, (LPCSTR)S.c_str(), NULL, 0);
                                }
                }

                *orders_row = 2;
                for (int i = 0; i < 2; i++)
                {
                        strcpy(orders[i].Symb, "Symb_");
                        orders[i].lot = i;
                        orders[i].Order = i + 1;
                        orders[i].SL = i + 2;
                        orders[i].TP = i + 3;
                }
        }
        out.close();
        return ans;
}

.mq5

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
struct Quotes
  {
   char              Symb[16];
   double            bid;
   double            ask;
   double            last;
   double            open;
   double            high;
   double            low;
   double            close;
   long              volume;
   long              tickVolume;
   int               timeFrame;
#ifdef __MQL5__   
   int               _align;
#endif
   unsigned long     DT;
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
struct QuotesArr
  {
   unsigned int      size;
#ifdef __MQL5__      
   int               _align;
#endif
   Quotes            quote_data[3];
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
struct TOrders_ans
  {
   char              Symb[16];
   int               lot;
#ifdef __MQL5__      
   int               _align;
#endif
   double            SL;
   double            TP;
   double            Order;
  };

#import "TestDLL.dll"
int Cpp_callRobot(QuotesArr &arr[],int row,TOrders_ans &orders[],int &orders_row);
#import
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   string Symb=_Symbol;

   QuotesArr arr[2]={};
   TOrders_ans orders[2]={};

//---
   int total= ArraySize(arr);
   for(int i=0;i<total;i++)
     {

      // ArrayResize(arr[i].quote_data,3,3);//cannot be used for static allocated array
      int total2=ArraySize(arr[i].quote_data);
      arr[i].size=total2;

      for(int j=0;j<total2;j++)
        {
         MqlTick tickData[];
         if(i==1)
            Symb="Si-3.18";

         if(CopyTicks(Symb,tickData)>0)
           {
            StringToCharArray(Symb,arr[i].quote_data[j].Symb,0,StringLen(Symb));
            arr[i].quote_data[j].DT=tickData[0].time;
            arr[i].quote_data[j].ask = tickData[0].ask;
            arr[i].quote_data[j].bid = tickData[0].bid;
            arr[i].quote_data[j].timeFrame=1;
            arr[i].quote_data[j].volume=(long)tickData[0].volume;
            arr[i].quote_data[j].last=tickData[0].last;
           }

         MqlRates rates[1]={};
         if(CopyRates(Symb,PERIOD_CURRENT,0,1,rates)==1)
           {
            arr[i].quote_data[j].tickVolume=rates[0].tick_volume;
            arr[i].quote_data[j].close=rates[0].close;
            arr[i].quote_data[j].open=rates[0].open;
            arr[i].quote_data[j].high=rates[0].high;
            arr[i].quote_data[j].low=rates[0].low;
           }
        }
     }

   int orders_row=0;
   int res=Cpp_callRobot(arr,total,orders,orders_row);
   if(res!=0)
     {
      Print("Cpp_callRobot returned true ",orders_row);
      for(int i=0; i<orders_row; i++)
        {
         string S=CharArrayToString(orders[i].Symb);
         printf("%s data || SL: %.5f || TP: %.5f || Order: %.5f || lot: %.2f",S,orders[i].SL,orders[i].TP,orders[i].Order,orders[i].lot);
        }
     }
  }
//+------------------------------------------------------------------+
 
Andrey Voytenko:

Структуры в VS под x64 выравниваются к размеру указателя, т.е. 8 байт, а в MQL выравнивание всегда 1 байт. Поэтому в MQL5 структурах добавлены вставки int _align.

А зачем излишне усложнять вставками, если даже в MQL документации сказано что в .cpp необходимо использовать директиву
Документация по MQL5: Основы языка / Типы данных / Структуры, классы и интерфейсы
Документация по MQL5: Основы языка / Типы данных / Структуры, классы и интерфейсы
  • www.mql5.com
Структура является набором элементов произвольного типа (кроме типа void). Таким образом, структура объединяет логически связанные данные разных типов. Объявление структуры Имя структуры нельзя использовать в качестве идентификатора (имени переменной или функции). Следует иметь ввиду, что в MQL5 элементы структуры следуют непосредственно друг...
 
A100:
А зачем излишне усложнять вставками, если даже в MQL документации сказано что в .cpp необходимо использовать директиву #pragma pack(1)

Да, вы правы. Можно и не усложнять.

 
A100:
А зачем излишне усложнять вставками, если даже в MQL документации сказано что в .cpp необходимо использовать директиву
для скорости на стороне длл?
 
Комбинатор:
для скорости на стороне длл?

Для простоты. На скорость думаю влияет слабо 

 
Комбинатор:
для скорости на стороне длл?

Этот приём со вставками используется для работы с Windows API. Т.к. эти DLL скомпилированы без директивы #pragma pack(1).

 
A100:

Для простоты. На скорость думаю влияет слабо 

тем не менее подавляющее большинство кодеров предпочитают оптимизировать структуры чтобы в них не было дырок не убирая выравнивание, чем использовать pragma pack 1
 
Комбинатор:
тем не менее подавляющее большинство кодеров предпочитают оптимизировать структуры чтобы в них не было дырок не убирая выравнивание, чем использовать pragma pack 1

Получаете еще большее усложнение кода (добавляется _WIN64)

#ifdef _WIN64
#define ALIGN (8-2)
#else
#define ALING (4-2)
#endif
Причина обращения: