На оба вопроса ответ один: передавать в функцию указатель на массив (переменные), а в самой 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 ссылку на структуру, где произвести простое присвоение.
Для обоих вопросов ответ один: передавать в функцию ссылку на массив (переменные), а в самой 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).
Прошу предложить какое-то решение, если есть возможность.
Спасибо.
Приведите, пожалуйста, код функции ShiftedSmaNormilised из DLL. И, кстати, зачем используется копирование данных из Price в NormedPriceBuffer, если можно напрямую распечатать значения Price?
Также вызывает вопросы фраза:
но даже в журнал ничего не передается.
Нули то там должны быть. Или действительно ничего?
Спасибо за помощь.
Код в прикрепленном файле.
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. Нужно не распечатать, а нарисовать линию, для этого в буфер линии индикатора нужно данные скопировать или ???
- 2009.07.13
- Andrey Emelyanov
- www.mql5.com
Код в прикрепленном файле.
1. Используйте обертку импортируемых функций именно в таком стиле, как показано в примерах для работы терминала с DLL, т. е. через: __declspec(dllexport) <тип функции> __stdcall. Затем каждую импортируемую функцию стоит указать в def-файле.
2. Параметры функции ShiftedSmaNormilised, относящиеся к массивам, лучше оформить как указатели, а не как ссылку.
3. Не передавайте далее полученные указатели/ссылки напрямую. Лучше использовать копии. Тогда и проблем будет меньше.
p.s. Нужно не распечатать, а нарисовать линию, для этого в буфер линии индикатора нужно данные скопировать или ???
Наличие в буфере индикатора нужных данных как раз и приводит к появлению линии/стрелки/зигзага и т. д..
Оказалось что Метатрейдер может сам компилировать DLL из C++ файла, но происходит какие-то ошибка
Нет, не может. Можно наоборот: указать в VS путь к компилятору MQL и компилировать программы MQL прямо в студии.
Как видно на скриншоте, файлы все лежат в нужной папаке, но Метатрейдер их не находит. Подскажите как исправить ?
Для МТ включаемые файлы имеют расширение mqh, а не h. Но даже переименование файлов не поможет - не будет МТ компилировать C++ код.
Для МТ включаемые файлы имеют расширение mqh, а не h. Но даже переименование файлов не поможет - не будет МТ компилировать C++ код.
Уже компилирует, иначе откуда тогда: 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...
- www.mql5.com
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Здравствуйте.
Не могу никак разобраться, пол дня уже потратил.
Есть 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);
Можно ли как-то это сделать ?
Спасибо за поддержку !