Скачать MetaTrader 5

Помогите разобраться с импортом массива типа double из DLL ?

Авторизуйтесь или зарегистрируйтесь, чтобы добавить комментарий
Сервис Фриланс: безопасный способ заказать робота. Попробуй сам!
DmitryAE
39
DmitryAE 2015.08.13 17:38 

Здравствуйте.


Не могу никак разобраться, пол дня уже потратил.


Есть dll в которую отправляется массив с ценами(Price);

ShiftedSmaNormilised(Price,100,100);

но при попытке получать результат (массив с ценами типа doble):

ZzzZ=ShiftedSmaNormilised(Price,100,100);

выдает ошибку:

'ZzzZ' - parameter conversion not allowed

другой вариант:


ZzzZY[]=ShiftedSmaNormilised(Price,100,100);


']' - expression expected   (типа требует что-бы поэлементно все было заполнено).


Как массив целиком получить из DLL в переменную типа:

ZzzZY[]


Или переменную какого-то другого типа, но только весь массив сразу, что-бы потом, при необходимости,можно было чкопировать из нее данные в переменную типа xxxxx[] и отобразить линию индикатора


?

Еще один вопрос как получить из функции не 1, а несколько параметров ?

т.е. функция возвращает несколько результатов (например фильтрованную цену, и еще два два параметра, типа int (т.е. обычные целые числа в количестве 1 +1)


т.е. что-то типа ?

(zz,dd,yy)=ShiftedSmaNormilised(Price,100,100);


Можно ли как-то это сделать ?


Спасибо за поддержку !
Ihor Herasko
9064
Ihor Herasko 2015.08.13 18:54  

На оба вопроса ответ один: передавать в функцию указатель на массив (переменные), а в самой DLL производить заполнение этого массива (переменных):

MQL:

#import "dll"
   void GetArrayData(double &array[], int arraySize);
#import


void OnStart()
{
   double array[4];
   ArrayInitialize(array, 0);
   GetArrayData(array, 4);
   
   for (int i = 0; i < 4; i++)
      Print("Элемент ", i, " = ", array[i]);
}

C++:

extern "C" void __declspec(dllexport) __stdcall GetArrayData(double *dArray, int arraySize)
{
        for (int i = 0; i < arraySize; i++)
        {
                *dArray = 10.0;
                dArray++;
        }
}

 Это только пример и далеко не универсальный. Зная конкретную задачу, можно найти более изящный способ.

Допустим, если массив нужно всего лишь скопировать из DLL в MQL-программу, а не вычислять, как в предыдущем примере, то можно обернуть статический массив в структуру и передать в DLL ссылку на структуру, где произвести простое присвоение.

DmitryAE
39
DmitryAE 2015.08.13 19:25  
Игорь Герасько:

Для обоих вопросов ответ один: передавать в функцию ссылку на массив (переменные), а в самой DLL производить заполнение этого массива (переменных):

MQL:

C++:

 Это только пример и далеко не универсальный. Зная конкретную задачу, можно найти более изящный способ.

Спасибо за Ваш ответ.


Попробовал сначала вывести в журнал результат работы dll функции, но даже в журнал ничего не передается.

Подскажите, если можете,  в чем проблема ? Ниже по в сообщении код индикатора.


//+------------------------------------------------------------------+
//|                                                    ShiftedMA.mq5 |
//|                        Copyright 2015, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1
//--- plot NormedShiftMinus
#property indicator_label1  "NormedPriceBuffer"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDodgerBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

input int MAPeriod = 100;
input int MAShift;

#import "ShiftedSmaNormilised.dll"

double  ShiftedSmaNormilised(double &Data[],
           int period,
           int Shift
           );
#import


double         NormedPriceBuffer[];
double         Price[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
void OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(1,NormedPriceBuffer,INDICATOR_DATA);
   
//---
   
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+

int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])

{

CopyOpen(Symbol(),0,0,10000,Price);


ShiftedSmaNormilised(Price,100,100);

ArrayCopy(NormedPriceBuffer,Price);

for (int i = 0; i < 200; i++)
      Print("Элемент ", i, " = ", NormedPriceBuffer[i]);


return(INIT_SUCCEEDED);;
}
//+------------------------------------------------------------------+

Функция специально вызывается так, что результат работы функции грузится во входной параметр (т.е. в "Price"), т.к. если использую что-то типа

xxx= ShiftedSmaNormilised(Price,100,100);

выдается ошибка - 'xxx' - invalid array access.


p.s. Компилятор DLL настроен на stdcall  (кто не знает - ключ /Gz при запуске компилятора определяет тип вызова функций (особенно актуально для софт в котором используется сторонний компилятор Microsoft).


Прошу предложить какое-то решение, если есть возможность.

Спасибо.

Ivan Vorontsov
157
Ivan Vorontsov 2015.08.13 20:56  
Если dll твоя, добавь в неё логирование запросов в текстовый файл. Хотя бы будут идеи куда копать, в сторону dll или советника. Но всё выглядит правильно на первый взгляд.
Ihor Herasko
9064
Ihor Herasko 2015.08.14 09:41  

Приведите, пожалуйста, код функции ShiftedSmaNormilised из DLL. И, кстати, зачем используется копирование данных из Price в NormedPriceBuffer, если можно напрямую распечатать значения Price?

Также вызывает вопросы фраза:

DmitryAE:

но даже в журнал ничего не передается.

 Нули то там должны быть. Или действительно ничего?

DmitryAE
39
DmitryAE 2015.08.15 09:52  

Спасибо за помощь.


Код в прикрепленном файле.


p.s. В метатрейдере 4 делалася враппер который "портировал" вызовы метатрейдера в формате stdcall в формат вызовов библиотеки:


[b]library[/b] mywrapper;

[color=SeaGreen]// here we declare the import from our original dll[/color]
[b]function[/b] foo(bar: double; baz: double): double; cdecl; external 'originaldll.dll';

[color=SeaGreen]// here we wrap a stdcall function around it[/color]
[b]function[/b] wrap_foo(bar: double; baz: double): double; stdcall;
[b]begin[/b]
    result := foo(bar, baz);
[b]end;[/b]

[b]exports[/b]
    wrap_foo;

[b]begin
end.[/b]


Формат функций библиотеки задавался словом - cdecl (см в коде выше в сообщении, хотя не факт, т.к. в примере с сайта MQL5 (см.ниже) эти библиотеки с  declspec );


А в Метатрейдере 5 такой врапер выглядит проще без указания ковенции вызова функций:

#property library
#property copyright "Copyright 2015, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| My function                                                      |
//+------------------------------------------------------------------+
// int MyCalculator(int value,int value2) export
//   {
//    return(value+value2);
//   }
//+------------------------------------------------------------------+
#import "ShiftedSmaNormilised.dll"
int  ShiftedSmaNormilised(double &Data[],
           int period,
           int Shift
           );
#import 


Есть ли возможность указать в Метатрейдере 5 конвенцию вывозова функций ? С помощью враппера все должно существенно упростится, но враппер так-же не работает в данный момент используя представленные в этой ветке коды.

Вот еще приводят пример врапера на C++

/*---------------------------------------------------------------------------
** Libraries + *.lib + *.def:
** libeng.lib** libmx.lib
** libmex.lib** project_name.def
*/
#include <windows.h>#include <memory.h>#include "engine.h"
//---------------------------------------------------------------------------
extern "C" __declspec(dllexport)<variable_type>__stdcall Funcion(<type><name>);
//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst,unsigned long reason,void *lpReserved)
  {
   /*    
** reason for DLL call    
*/
   switch(reason)
     {
      case DLL_PROCESS_ATTACH:
         /*            
** DLL uploaded into the address space of the process            
*/
         break;
      case DLL_PROCESS_DETACH:
         /*            
**DLL loaded from the address space of the process            
*/
         break;
     }
   return TRUE;
  }
//---------------------------------------------------------------------------
bool __stdcall Funcion(<type><name>)
  {
   ……
  }
//---------------------------------------------------------------------------


https://www.mql5.com/en/articles/1567

По коду враппера на C++ похоже что что dll использует declspec.

p.s. Нужно не распечатать, а нарисовать линию, для этого в буфер линии индикатора нужно данные скопировать или ???

Interaction between MеtaTrader 4 and MATLAB Engine (Virtual MATLAB Machine)
Interaction between MеtaTrader 4 and MATLAB Engine (Virtual MATLAB Machine)
  • 2009.07.13
  • Andrey Emelyanov
  • www.mql5.com
The article contains considerations regarding creation of a DLL library - wrapper that will enable the interaction of MetaTrader 4 and the MATLAB mathematical desktop package. It describes "pitfalls" and ways to overcome them. The article is intended for prepared C/C++ programmers that use the Borland C++ Builder 6 compiler.
Файлы:
DmitryAE
39
DmitryAE 2015.08.15 14:22  

Оказалось что Метатрейдер может сам компилировать DLL из C++ файла, но происходит какие-то ошибка:




Как видно на скриншоте, файлы все лежат в нужной папаке, но Метатрейдер их не находит. Подскажите как исправить ?


Спасибо.

Ihor Herasko
9064
Ihor Herasko 2015.08.15 21:46  
DmitryAE:

Код в прикрепленном файле.

1. Используйте обертку импортируемых функций именно в таком стиле, как показано в примерах для работы терминала с DLL,  т. е. через: __declspec(dllexport) <тип функции> __stdcall. Затем каждую импортируемую функцию стоит указать в def-файле.

2. Параметры функции ShiftedSmaNormilised, относящиеся к массивам, лучше оформить как указатели, а не как ссылку.

3. Не передавайте далее полученные указатели/ссылки напрямую. Лучше использовать копии. Тогда и проблем будет меньше. 

p.s. Нужно не распечатать, а нарисовать линию, для этого в буфер линии индикатора нужно данные скопировать или ???

Наличие в буфере индикатора нужных данных как раз и приводит к появлению линии/стрелки/зигзага и т. д..

Ihor Herasko
9064
Ihor Herasko 2015.08.15 21:50  
DmitryAE:

Оказалось что Метатрейдер может сам компилировать DLL из C++ файла, но происходит какие-то ошибка

Нет, не может. Можно наоборот: указать в VS путь к компилятору MQL и компилировать программы MQL прямо в студии.

 Как видно на скриншоте, файлы все лежат в нужной папаке, но Метатрейдер их не находит. Подскажите как исправить ?

Для МТ включаемые файлы имеют расширение mqh, а не h. Но даже переименование файлов не поможет - не будет МТ компилировать C++ код.

A100
3939
A100 2015.08.15 22:13  
Игорь Герасько:

Для МТ включаемые файлы имеют расширение mqh, а не h. Но даже переименование файлов не поможет - не будет МТ компилировать C++ код.

Уже компилирует, иначе откуда тогда: fatal error С1083 - взялась бы?
DmitryAE
39
DmitryAE 2015.08.16 07:36  
A100:
Уже компилирует, иначе откуда тогда: fatal error С1083 - взялась бы?

Еще одна, imho, полезная ссылка по таким dllкам и Метатрейдеру:

https://www.mql5.com/ru/forum/991

Лабовские длл используют declspec


Сегодня буду перекомпилировать код в студии (заставить Лаб, что-бы он сам откомпилировал отредактированный сpp с h файлоv не получилось), поправлю declspec на stdcall посмотрю что получится... напишу о результате. В отличии от студии, Лаб компилирует без каких-либо ошибок... поэтому в нем пробовал изначально, но как скомпилировать из CPP в лабе не нашел...


Уже компилирует, иначе откуда тогда: fatal error С1083 - взялась бы?

Студия не компилирует в отличии от лаба, т.к. в ней настройки компилятора другие и не редактируются - добавлять можно, но редактировать которые по умолчанию в студии не получается (они не активными выглядят). По умолчанию в Лабе вот такие (есть bat файл с настройками в Лабе)

-MD -c -Zp8 -GR -W3 -EHsc- -Zc:wchar_t- -nologo -I"C:\MLab\extern\include\win64" -DMSVC -DIBMPC /D_SECURE_SCL=0 /D_CRT_SECURE_NO_DEPRECATE

А в студии вот такие (по умолчанию и не редактируются):

/Zi /nologo /W3 /WX- /O2 /Oi /GL /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "MATLABDLL160815_EXPORTS" /D "_WINDLL" /D "_UNICODE" /D "UNICODE" /Gm- /EHsc /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Fp"x64\Release\matlabdll160815.pch" /Fa"x64\Release\" /Fo"x64\Release\" /Fd"x64\Release\vc100.pdb" /Gd /errorReport:queue 


Есть образец врапера:

/*---------------------------------------------------------------------------
** Libraries + *.lib + *.def:
** libeng.lib** libmx.lib
** libmex.lib** project_name.def
*/
#include <windows.h>#include <memory.h>#include "engine.h"
//---------------------------------------------------------------------------
extern "C" __declspec(dllexport)<variable_type>__stdcall Funcion(<type><name>);
//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst,unsigned long reason,void *lpReserved)
  {
   /*    
** reason for DLL call    
*/
   switch(reason)
     {
      case DLL_PROCESS_ATTACH:
         /*            
** DLL uploaded into the address space of the process            
*/
         break;
      case DLL_PROCESS_DETACH:
         /*            
**DLL loaded from the address space of the process            
*/
         break;
     }
   return TRUE;
  }
//---------------------------------------------------------------------------
bool __stdcall Funcion(<type><name>)
  {
   ……
  }
//---------------------------------------------------------------------------


https://www.mql5.com/es/articles/1567

Некто не в курсе как его адаптировать для моей задачи ? ( непонятно какой должен быть код на месте многоточия)

И правильно ли вот это:

extern "C" __declspec(dllexport)<variable_type>__stdcall Funcion(<type><name>);


?

Наверное правильно:

extern "C" __stdcall(dllexport)<variable_type>__declspec Funcion(<type><name>);

?

Всем большое спасибо за помощь.


p.s. в stdcall откломпилировал ! :-) В Лабе.


Скрипт не работает, депендс показывает вот что:


И в интернете пишут, что эти две библиотке только для виндовс 8 ! Кто-нибудь сталкивался с таким ?

Эту ситацию как в метатредере называют DLL Hell... Лаб отличился не меньше imho...

Matlab Dll c++ VS2008 MT5 windows 7 не работает
Matlab Dll c++ VS2008 MT5 windows 7 не работает
  • www.mql5.com
Иду в метатрейдер запускаю редактор. - - Категория: общее обсуждение
Авторизуйтесь или зарегистрируйтесь, чтобы добавить комментарий