Обсуждение статьи "Управление терминалом MetaTrader с помощью DLL"

 

Опубликована статья Управление терминалом MetaTrader с помощью DLL:

В данной статье рассматривается управление элементами интерфейса MetaTrader с использованием вспомогательной DLL-библиотеки на примере изменения настроек рассылки Push-сообщений. К статье приложен исходный код библиотеки и пример скрипта.

Имеется список MetaQuotesID, который составляет более четырех адресов для рассылки. Как известно, функция SendNotification использует только ID, указанные в окне настроек на вкладке "Уведомления". Таким образом, средствами MQL можно делать рассылку только на указанные ранее ID и не более четырех за раз. Попробуем исправить данную ситуацию.

Задачу можно решать двумя путями: написать полностью аналог функции для рассылки Push-сообщений или поменять настройки терминала и воспользоваться стандартной функцией. Первый путь довольно трудоемкий и, самое главное, не универсальный, поэтому был выбран другой вариант. Но и сами настройки терминала можно менять разными способами. Из тех что мне известны, это взаимодействие через интерфейс или подмена значений в памяти самого процесса. Хотя работа с памятью будет для пользователя выглядеть намного лучше, так как не будет мигающих окон, но при малейшей ошибке это может нарушить работу всего терминала. При работе через интерфейс мы в худшем случае не сможем найти нужное окно или кнопку.

Итак, в данной статье мы рассмотрим управление терминалом через интерфейс с помощью вспомогательной библиотеки DLL. В частности, будем рассматривать изменение настроек. "Общение" с терминалом будем организовывать через обращение к его окнам и компонентам, то есть так, как это делают обычные пользователи. Никаких вмешательств в процесс терминала не производим. Данный метод можно будет применять и для решения иных задач, к которым может привести самая неудержимая фантазия.

1.3. Работа с меню

Работа с меню, как и со всеми остальными компонентами, начинается после нахождения хэндла родителя, то есть определенного окна. После этого необходимо найти соответствующий пункт меню, подпункт и произвести его выбор.

Тут необходимо сделать важное замечание: количество пунктов меню в терминале изменяется в зависимости от того, развернуто окно графика или нет (см. рис. 2). Нумерация пунктов меню начинается с 0.

Рис. 2. Изменение количества пунктов меню

Рис. 2. Изменение количества пунктов меню

При изменении количества пунктов меню, соответственно, изменяется и порядковый номер пункта "Сервис". Поэтому при работе учитываем количество общее количество пунктов с помощью функции GetMenuItemCount(Hnd:HMenu), в которую передается хэндл меню.

Автор: Galina Bobro

 

Интересная задача выбрана. Правда, удивлен, что ее решение пустили "в эфир". Ведь таким макаром можно создать спам-сервис ))

 

По поводу самого решения возникли мысли и вопросы: 

1. Для вызова окна "Настройки" можно было бы использовать более универсальный способ: эмуляция нажатия  Ctrl + O. Вариант с меню не настолько уж и универсальный, т. к. зависит от расположения пунктов главного меню. Да, можно сказать, что и Ctrl+O никто не гарантирует. Тем не менее, изменение горячих клавиш в процессе развития приложения происходит достаточно редко и для этого должны быть веские причины.

2. Вместо нажатия "ОК" в окне "Настройки" - эмуляция клавиши Enter.

3. Что делать обычному пользователю, если в следующем билде разработчики добавят закладки в окно "Настройки", изменив при этом порядковый номер вкладки "Уведомления"? Программист то понятно - исправит на новый номер.

 

P. S. Что-то не так с семантикой предложения: "Даже несмотря на быструю работу программы, пользователь может его закрыть окно, что повлечет полное зависание терминала." В итоге мысль непонятна. Просьба исправить.

 
Игорь Герасько:

Интересная задача выбрана. Правда, удивлен, что ее решение пустили "в эфир". Ведь таким макаром можно создать спам-сервис ))

 

По поводу самого решения возникли мысли и вопросы: 

1. Для вызова окна "Настройки" можно было бы использовать более универсальный способ: эмуляция нажатия  Ctrl + O. Вариант с меню не настолько уж и универсальный, т. к. зависит от расположения пунктов главного меню. Да, можно сказать, что и Ctrl+O никто не гарантирует. Тем не менее, изменение горячих клавиш в процессе развития приложения происходит достаточно редко и для этого должны быть веские причины.

2. Вместо нажатия "ОК" в окне "Настройки" - эмуляция клавиши Enter.

3. Что делать обычному пользователю, если в следующем билде разработчики добавят закладки в окно "Настройки", изменив при этом порядковый номер вкладки "Уведомления"? Программист то понятно - исправит на новый номер.

 

P. S. Что-то не так с семантикой предложения: "Даже несмотря на быструю работу программы, пользователь может его закрыть окно, что повлечет полное зависание терминала." В итоге мысль непонятна. Просьба исправить.

Сама в шоке)

Спасибо за идею, попробую еще из клавишами, правда тут еще будет играть большую роль фокус. Если вдруг пользователь клацнет на окно что появляется  или на что-то еще (вдруг ему еще музыку захочется параллельно послушать) , то не известно что собственно нажмем.

За билд: очень сомнительно что будут частые существенные изменения в виде окна. Конечно это недостаток. 

В последнем не поняла что тут именно не ясно, может и потому что мне, как автору, все по умолчанию понятно. При работе скрипта появляется окно настроек которое потом ищем. Так как программно выполняются действия, то пользователь видит практически мигание окна, но вполне может успеть его закрыть (проверяла). Если это произойдет, а поиск в бесконечном цикле, то имеем полностью "висящий" терминал.

 
Galina Bobro:

В последнем не поняла что тут именно не ясно, может и потому что мне, как автору, все по умолчанию понятно. При работе скрипта появляется окно настроек которое потом ищем. Так как программно выполняются действия, то пользователь видит практически мигание окна, но вполне может успеть его закрыть (проверяла). Если это произойдет, а поиск в бесконечном цикле, то имеем полностью "висящий" терминал.

Имелось в виду часть предложения: "пользователь может его закрыть окно". Возможно, здесь лишнее "его". А может и что-то другое.
 
Игорь Герасько:

По поводу самого решения возникли мысли и вопросы: 

1. Для вызова окна "Настройки" можно было бы использовать более универсальный способ: эмуляция нажатия  Ctrl + O. Вариант с меню не настолько уж и универсальный, т. к. зависит от расположения пунктов главного меню. Да, можно сказать, что и Ctrl+O никто не гарантирует. Тем не менее, изменение горячих клавиш в процессе развития приложения происходит достаточно редко и для этого должны быть веские причины.

а что 
 PostMessageW(hParentWnd, WM_COMMAND, 33265, 0);

Больше не работает ? 

 
Игорь Герасько:
Имелось в виду часть предложения: "пользователь может его закрыть окно". Возможно, здесь лишнее "его". А может и что-то другое.
Исправлено, спасибо за замечание.
 
Sergey Dzyublik:
а что 
 PostMessageW(hParentWnd, WM_COMMAND, 33265, 0);

Больше не работает ? 

Не проверял. Но к подобного рода решениям отношусь с осторожностью, т. к. они недокументированы. Следовательно, могут в любой момент "поломаться" и нигде об этом никто ничего не напишет. В то же время программист будет долго ломать голову, прежде чем найдет возникшую ошибку. А вот Ctrl+O на данный момент является документированной возможностью терминала. Поэтому ее можно смело использовать. При изменениях в поведении терминала от разработчиков обязательно последуют изменения документации.
 

вот это я называю mad skills !

способ поражает одновременно и простотой и изощрённостью ;)

 
Dmitry Orlov:

вот это я называю mad skills !

способ поражает одновременно и простотой и изощрённостью ;)


интересно, кто-нибудь это все проверял ?

п‌ереписываю все на С++, здесь вот что-то странное:

HWND cSetPush::FindTab(int i_AccountNumber,int i_Language)
{
  TCHAR t_Buffer[255];
  HWND  h_Button;
  HWND  h_Parent;
  HMENU h_Menu;
  int i;
  UINT ui_MenuItemID;

  _itow(i_AccountNumber,gt_MT_WindowName,10);

  wcscpy(gt_MT_WindowClassName,TEXT("MetaTrader"));

  EnumWindows(&FindFunc, 0);

  if (gh_MT_Window != NULL)
  {
          SetForegroundWindow(gh_MT_Window);

          h_Menu = GetMenu(gh_MT_Window);

          if (GetMenuItemCount(h_Menu) == 7)
          h_Menu = GetSubMenu(h_Menu,4);
          else
          h_Menu = GetSubMenu(h_Menu,5);

          ui_MenuItemID = GetMenuItemID(h_Menu,6);

h_Menu - это handle для Tools

Tools содержит

0‌ - New Order

1‌ - History Center

2 - Global Variables

3 - MetaEditor

4 - Options

‌надо наверное так:

ui_MenuItemID = GetMenuItemID(h_Menu,4);

 

Есть у кого Set_Push.dll  готовая,  поделитесь плиз.

Разбираться как из dpr dpoj делать dll  буду, но позже.

 
а как развернуть окно графика в mt5