0. Не надо придумывать фигню со строками-указателями! :-))
1. Тип указателя должен соответствовать разрядности проекта и ОС, где будет работать. INT нельзя применять на 64 разрядных ОС.
2. Есть специальные типы для указателей и размеров, которые сами переключаются куда надо в зависимоти от конфигурации проекта. Например, SIZE_T или DWORD_PTR.
3. Не надо передавать указатель в MQL. Оставте его внутри библиотеки. Сделайте интерфейс управления им через параметры функции.
size_t это тот же unsigned, размер как у инта ) а DWORD_PTR это дефайн, который тип указателя на тот же unsigned, которого в MQL ессно нету. В итоге как всегда из попытки выпендриться получается клоунада )
А насчет указателей правильно, лучше дескриптор передавать, а указатель держать у себя в укромном месте и брать по дескриптору когда надо.
Прямой ответ на прямой вопрос -- на 64х инта не хватит.
Какое-то мутное описание, но почти уверен что проблемы с выравниванием. В МКЛ оно == 1. Поэтому либо в мкл в ручную выравнивать сложные типы, либо в длл задавать выравнивание == 1. Как выглядит выровненная структура в мкл? Пример:
struct S { char ch; int fill[7]; // заполнитель double d; }; struct S // Так писать структуры правильней { double d; char ch; };
Место заполнителя думаю зависит от процессора (big endian или little endian).
0. Не надо придумывать фигню со строками-указателями! :-))
1. Тип указателя должен соответствовать разрядности проекта и ОС, где будет работать. INT нельзя применять на 64 разрядных ОС.
2. Есть специальные типы для указателей и размеров, которые сами переключаются куда надо в зависимоти от конфигурации проекта. Например, SIZE_T или DWORD_PTR.
3. Не надо передавать указатель в MQL. Оставте его внутри библиотеки. Сделайте интерфейс управления им через параметры функции.
Спасибо за советы :)
Начнём по пунктам.
0. Я конечно понимаю, что фигню придумывать не надо :) Но придётся, если не получится сделать по уму :) Если не через строку - значит, как-то ещё. Если не получится - придётся оставлять так как есть (через инт). Это не лучший вариант, но по крайней мере он в большинстве случаев работает.
1. Я вообще думал, что MetaTrader 4 является 32-битным и в 64-разрядных ОС работает внутри виртуальной машины, которая делает для него соответствующие указатели. Потому и надеялся, что инты сгодятся. DLL тоже 32-битная.
2. Что там использовать внутри DLL - это не проблема.Там я могу использовать что угодно. Проблема в том, как это что-то передать наружу.
3. А вот это самый важный вопрос. Так сделать - наверное, это было бы лучше всего. Но каким образом можно так сделать? Я пока что не догадался.
Вот у меня есть база данных. Есть робот на MQL4. И есть DLL. Робот в начале своей работы хочет подключиться к БД. Он вызывает функцию подключения, которая возвращает указатель на полученный объект подключения. При вызове следующих функций, которые работают с подключением, им надо передать указатель на этот объект. Каким образом можно обойтись без того, чтобы передавать роботу из DLL полученный указатель, а затем передавать его обратно из робота в функции? Если не передавать его роботу - где его тогда хранить? У меня пока что нет идей, где внутри DLL можно было бы хранить указатель на созданный объект. Можете ли вы что-нибудь посоветовать? Я был бы очень благодарен.
size_t это тот же unsigned, размер как у инта ) а DWORD_PTR это дефайн, который тип указателя на тот же unsigned, которого в MQL ессно нету. В итоге как всегда из попытки выпендриться получается клоунада )
А насчет указателей правильно, лучше дескриптор передавать, а указатель держать у себя в укромном месте и брать по дескриптору когда надо.
Не будете ли вы так добры рассказать насчёт дескрипторов и укромных мест подробнее? :) Я бы воспользовался этим способом.
Не будете ли вы так добры рассказать насчёт дескрипторов и укромных мест подробнее? :) Я бы воспользовался этим способом.
Создаем синглтон менеджер который хранит эти самые указатели
class Net; class NetManager { public: typedef boost::shared_ptr<Net> NetPtr; public: NetManager(); ~NetManager(); bool RegisterUser(int userID, size_t inSize, size_t outSize, bool thresholds); bool UnregisterUser(int userID); NetPtr GetNet(int userID); private: std::map<int, NetPtr> m_Nets; CRITICAL_SECTION m_Lock; }; NetManager::NetManager() { InitializeCriticalSection(&m_Lock); } NetManager& GetNetManager() { static NetManager TheManager; return TheManager; } bool NetManager::RegisterUser(int userID, size_t inSize, size_t outSize, bool thresholds) { std::map<int, NetPtr>::const_iterator it = m_Nets.find(userID); assert(it == m_Nets.end()); if (it == m_Nets.end()) { EnterCriticalSection(&m_Lock); NetPtr ptr(new Net(inSize, outSize, thresholds)); m_Nets.insert(std::make_pair(userID, ptr)); LeaveCriticalSection(&m_Lock); return true; } return false; } bool NetManager::UnregisterUser(int userID) { EnterCriticalSection(&m_Lock); m_Nets.erase(userID); LeaveCriticalSection(&m_Lock); return true; } NetManager::NetPtr NetManager::GetNet(int userID) { NetPtr ptr; std::map<int, NetPtr>::const_iterator it = m_Nets.find(userID); assert(it != m_Nets.end()); if (it != m_Nets.end()) { ptr = it->second; } return ptr; } NetManager::~NetManager() { DeleteCriticalSection(&m_Lock); }У меня вот так незатейливо и просто. Еще и решает проблему одновременной работы кучи экспертов на нейронках. Только у меня указатели на сети, у вас свои. Когда MQL коду нужна дллка, он передает дескриптор (userID), по нему дллка из менеджера получает нужный указатель и производит необходимые действия. регистрация например в ините разрегистрация в деините.
Какое-то мутное описание, но почти уверен что проблемы с выравниванием. В МКЛ оно == 1. Поэтому либо в мкл в ручную выравнивать сложные типы, либо в длл задавать выравнивание == 1. Как выглядит выровненная структура в мкл? Пример:
Место заполнителя думаю зависит от процессора (big endian или little endian).
Спасибо за совет :) Однако я не понимаю, где здесь может быть проблема с выравниванием. Внутрь функций DLL из MQL4 передаются только обычные типы данных, хорошо описанные в учебнике (int, double, string), а не какие-то сложные структуры. Ну и этот самый указатель, тоже преобразованный к int. Обратно передаётся только int и string. Где здесь применять выравнивание?
Создаем синглтон менеджер который хранит эти самые указатели
Спасибо за совет :) Однако я не понимаю, где здесь может быть проблема с выравниванием. Внутрь функций DLL из MQL4 передаются только обычные типы данных, хорошо описанные в учебнике (int, double, string), а не какие-то сложные структуры. Ну и этот самый указатель, тоже преобразованный к int. Обратно передаётся только int и string. Где здесь применять выравнивание?
Тогда никаких проблем. А вот так адрес не передается?
#import "lib.dll" // Новый мкл void fn(int &r); #import
#import "lib.dll" // Старый мкл void fn(int r[]); #import
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Привет всем.
Пишу систему для взаимодействия с БД. Конечно же, без DLL никак не получается. Из DLL в роботов, написанных на MQL4, при вызове функции инициализации передаётся указатель на объект, который затем используется в других функциях. Вопрос как раз по передаче этого указателя. Каким образом можно передавать указатель между кодом на C++ и MQL4? Я не нашёл этого в справочниках.
У меня это сделано так. Указатель передаётся туда-обратно как тип int. Внутри функции на C++ после получения указателя на объект он преобразуется в int и передаётся в код на MQL4:
// Создаём объект MqlDll:
Там он хранится до тех пор, пока не понадобится, а потом при вызове функции из DLL, работающей с объектом, передаётся в эту функцию. Внутри int обратно преобразуется в указатель, и выполняются какие-то действия с объектом, на который этот указатель указывает:
// Преобразуем переданный int в указатель на класс:
return dllClass->checkDBVer();
В основном всё работает. Но в некоторых случаях при запуске большого количества роботов, особенно на 64-битных системах, вдруг начинают сыпаться ошибки вроде "вызов функции завершился с ошибкой: критическая ошибка по адресу 0xC921AB223". Я предполагаю, что, возможно, размер указателя больше, чем int. В результате этого в некоторых случаях указатель обрезается при преобразовании туда-обратно и начинает указывать совсем не туда, куда планировалось. Поэтому думаю над использованием какого-нибудь другого типа данных. Но какой тип выбрать?
Пока что я думаю попробовать передавать указатель как тип string. Внутрь DLL он передаётся как char*, поэтому теоретически может вполне сгодится в качестве указателя. Но, может быть, при передаче идёт преобразование в строку - тогда всё будет ещё хуже. Как будет на самом деле - покажут тесты. Если string не покатит - тогда думаю попробовать double. В нём байтов больше, поэтому, возможно, при преобразовании указатели обрезаться не будут. Если и double не пойдёт - тогда придётся мириться с ошибками, устраняя их путём перезапуска терминала вместе с роботами.
Пробовал найти руководство, как правильно это сделать, но не получилось. Официальный учебник рассказывает только про передачу параметров по ссылке. Про передачу указателей, насколько я понял, там не говорится. Никакой статьи по этому вопросу также не нашёл. Поиск по форумам тоже в основном выдаёт результаты не по теме. Хотел написать в вопрос в техническую поддержку MetaQuotes - но не нашёл, как с ними связаться. Есть только ссылка на этот форум.
Может быть, кто-нибудь уже делал подобное? Может у кого-то есть пример, как это сделать правильно - поделитесь, пожалуйста. Также очень жду ответа сотрудников MetaQuotes. Раз у них на сайте указаны только ссылки на этот форум - надеюсь, они его читают.