- Получение общего списка свойств терминала и программы
- Номер сборки терминала
- Тип и лицензия программы
- Режимы работы терминала и программы
- Разрешения
- Проверка сетевых подключений
- Вычислительные ресурсы: память, диск, процессор
- Характеристики экрана
- Строковые свойства терминала и программы
- Настраиваемые свойства: лимит баров и язык интерфейса
- Привязка программы к свойствам среды исполнения
- Проверка состояния клавиатуры
- Проверка статуса и причины остановки MQL-программы
- Программное закрытие терминала и код возврата
- Обработка ошибок времени исполнения программы
- Пользовательские ошибки
- Управление отладкой
- Предопределенные переменные
- Предопределенные константы языка MQL5
Получение общего списка свойств терминала и программы
Имеющиеся встроенные функции получения свойств среды используют обобщенный подход: свойства каждого конкретного типа объединены в отдельную функцию с единственным аргументом, задающим запрашиваемое свойство. Для идентификации свойств определены перечисления: каждый элемент описывает одно свойство.
Как мы увидим далее, данный подход часто применяется в MQL5 API и в других, в том числе прикладных областях. В частности, похожие наборы функций используются для получения свойств торгового счета и финансового инструмента.
Для описания среды достаточно свойств трех простых типов: int, double, string. При этом с помощью значений int представлены не только целочисленные свойства, но и логические флаги (в частности, разрешения/запреты, наличие сетевого соединения и т.д.), а также прочие встроенные перечисления (например, типы MQL-программ и типы лицензий).
С учетом условного деления на свойства терминала и свойства конкретной MQL-программы, существуют следующие функции, описывающие среду.
int MQLInfoInteger(ENUM_MQL_INFO_INTEGER p)
int TerminalInfoInteger(ENUM_TERMINAL_INFO_INTEGER p)
double TerminalInfoDouble(ENUM_TERMINAL_INFO_DOUBLE p)
string MQLInfoString(ENUM_MQL_INFO_STRING p)
string TerminalInfoString(ENUM_TERMINAL_INFO_STRING p)
Данные прототипы задают соответствие типов значений и перечислений. Например, "терминальные" свойства типа int сведены в ENUM_TERMINAL_INFO_INTEGER, а его же свойства типа double перечислены в ENUM_TERMINAL_INFO_DOUBLE, и т.д. Список доступных перечислений и их элементов можно найти в документации, в разделах, посвященных свойствам терминала и MQL-программы.
В следующих разделах мы рассмотрим все свойства, группируя их по назначению. Здесь же обратимся к задаче получения общего списка всех существующих свойств и их значений. Это часто бывает необходимо для выявления "узких мест" или особенностей работы MQL-программ на конкретных экземплярах терминала. Довольно распространена ситуация, когда на одном компьютере MQL-программа работает, а на другом — не работает совсем или работает с отклонениями.
Перечень свойств постоянно пополняется по мере развития платформы, поэтому желательно делать их запрос не на основе жестко вшитого в исходный код списка, а автоматически.
В разделе Перечисления мы создали шаблонную функцию EnumToArray для получения полного списка элементов перечисления (файл EnumToArray.mqh). Также в том разделе был представлен скрипт ConversionEnum.mq5, использующий указанный заголовочный файл. В скрипте была реализована вспомогательная функция process, которая получала массив с кодами элементов перечисления и выводила их в журнал. Мы возьмем эти наработки в качестве отправной точки для дальнейшего усовершенствования.
Нам необходимо модифицировать функцию process таким образом, чтобы не только получить перечень элементов конкретного перечисления, но и запросить соответствующие свойства с помощью одной из встроенных функций свойств.
Дадим новой версии скрипта имя Environment.mq5.
Поскольку свойства среды рассредоточены по нескольким разным функциям (в данном случае, пяти), необходимо научиться передавать в новую версию функции process указатель на требуемую встроенную функцию (см. раздел Указатели на функции (typedef)). Однако MQL5 не позволяет присвоить указателю на функцию адрес встроенной функции. Это можно сделать только с прикладной функцией, реализованной на MQL5. Поэтому мы создадим функции-обертки. Например:
int _MQLInfoInteger(const ENUM_MQL_INFO_INTEGER p)
|
Выше показан "двойник" для MQLInfoInteger (очевидно, он должен иметь отличное, но — желательно, похожее имя). Остальные функции "упаковываются" аналогичным образом. Всего их получится пять.
Если в старой версии process был только один параметр шаблона, задающий перечисление, то в новой нам необходимо также передать тип возвращаемого значения (поскольку MQL5 не "понимает" слов в названии перечислений): хоть в имени ENUM_MQL_INFO_INTEGER и присутствует окончание "INTEGER", компилятор не способен увязать его с типом int).
Однако помимо увязки типов возвращаемого значения и перечисления нам требуется каким-то образом передать в функцию process указатель на соответствующую функцию-обертку (одну из пяти, определенных нами ранее). Ведь компилятор не умеет сам определять по аргументу, например, типа ENUM_MQL_INFO_INTEGER, что нужно вызвать MQLInfoInteger.
Для решения данной проблемы была создана специальная шаблонная структура, соединяющая в себе все три фактора воедино.
template<typename E,typename R>
|
Два параметра шаблона позволяют определить тип указателя функции (FuncPtr) с требуемым сочетанием результата и входного параметра. В экземпляре структуры имеется поле f для указателя этого, только что определенного типа.
Теперь новая версия функции process может быть описана следующим образом.
template<typename E,typename R>
|
Входной параметр является структурой Binding и содержит в себе указатель конкретной функции получения свойств (это поле заполнит вызывающий код).
Данная версия алгоритма выводит в журнал порядковый номер, идентификатор свойства и его значение. Еще раз обратим внимание на то, что первое число в каждой записи будет содержать порядковый номер элемента в перечислении, а не значение (значения могут быть назначены элементам с пропусками). При необходимости вы можете добавить вывод переменной e "в чистом виде" внутри инструкции PrintFormat.
Кроме того вы можете модифицировать process, чтобы она собирала в массив (или другой контейнер, такой как карта (map)) получаемые значения свойств и возвращала их "наружу".
Было бы потенциальной ошибкой обращаться к указателю функции непосредственно в инструкции PrintFormat вместе с анализом кода ошибки _LastError. Дело в том, что последовательность вычисления аргументов функции (см. раздел Параметры и аргументы) и операндов в выражении (см. раздел Базовые понятия) в данном случае не определена. Поэтому при вызове указателя в той же строке, где считывается _LastError, компилятор может решить выполнить второе раньше первого. В результате мы увидим нерелевантный код ошибки (например, с предыдущего вызова функции).
Но и это еще не всё. Встроенная переменная _LastError может изменить свое значение практически в любом месте вычисления выражения, если какая-либо операция выполнится с ошибкой. В частности, функция EnumToString может потенциально взвести код ошибки, если в качестве аргумента передано значение, отсутствующее в перечислении. В данном фрагменте мы защищены от этой проблемы, потому что наша функция EnumToArray возвращает массив только с проверенными (правильными) элементами перечисления. Однако в общем случае в любой "сложносочиненной" инструкции может оказаться много мест, где _LastError будет изменена. В связи с этим желательно зафиксировать код ошибки сразу после интересующего нас действия (здесь это вызов функции по указателю), сохранив его в промежуточную переменную snapshot.
Но вернемся к основной задаче. Мы можем, наконец, организовать вызов новой функции process для получения различных свойств программного окружения.
void OnStart()
|
Ниже приведен фрагмент сгенерированных записей в журнале.
ENUM_MQL_INFO_INTEGER Count=15
|
Эти и другие свойства будут описаны в следующих разделах.
Стоит отметить, что некоторые свойства унаследованы с прошлых этапов развития платформы и оставлены только для совместимости. В частности, свойство TERMINAL_X64 в TerminalInfoInteger возвращает признак того, является ли терминал 64-разрядным. Сегодня разработка 32-битных версий прекращена, и потому это свойство всегда равно 1 (true).