Полезности

Здесь буду выкладывать решения разных небольших задач:

Закрыть терминал из скрипта

Исходный код индикаторов QUIK. СКАЧАТЬ

Добавить комментарий

Полезности: 38 комментариев

  1. Здравствуйте.
    Пишу небольшую программку - помощника на С++ для Квика.
    Подскажите пожалуйста, какие команды послать Квику, чтобы сделать активной нужную таблицу?
    Наверное то же самое, нужно установит фокус на нужную таблицу, но вопрос, как это сделать?
    Программные клики левой кнопкой на строках нужной таблицы проходят нормально, нужные строки выделяются как положено,
    но при этом окно не становится активным и соответственно меню не меняется, что для меня крайне важно.
    Очень прошу помощи.
    Спасибо.

    1. Здравствуйте! Тоже недавно мучился с подобной задачей, нужно было выкинуть все из кармана транзакций, в итоге пришел к решению отправлять окну 2 сообщения, чтобы его активировать:

      1
      2
      
      ShowWindow(hPocket, SW_MINIMIZE);
      ShowWindow(hPocket, SW_RESTORE);

      Весь код DLL, вдруг пригодится:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      
      #include <windows.h>
      #include <string>
       
      using namespace std;
       
      //=== Необходимые для Lua константы ============================================================================//
      #define LUA_LIB
      #define LUA_BUILD_AS_DLL
       
      //=== Заголовочные файлы LUA ===================================================================================//
      extern "C" {
      #include "Lua\lauxlib.h"
      #include "Lua\lua.h"
      }
       
      //=== Стандартная точка входа для DLL ==========================================================================//
      BOOL APIENTRY DllMain(HANDLE hModule, DWORD  fdwReason, LPVOID lpReserved)
      {
      	//Каждому событию соответствует свое значение аргумента fdwReason, передаваемого функции DllMain при его возникновении   
      	switch (fdwReason)
      	{
      	case DLL_PROCESS_ATTACH: // Подключение DLL          
      		break;
      	case DLL_PROCESS_DETACH: // Отключение DLL
      		break;
      	case DLL_THREAD_ATTACH:  // Создание нового потока
      		break;
      	case DLL_THREAD_DETACH:  // Завершение потока
      		break;
      	}
      	return TRUE;
      }
       
      //Возвращает заголовок окна по HWND
      std::string GetWindowCaption(HWND hwnd) {
      	int c = GetWindowTextLength(hwnd);
      	int captionLength = GetWindowTextLength(hwnd);
      	PSTR caption = (PSTR)VirtualAlloc((LPVOID)NULL, (DWORD)(captionLength + 1), MEM_COMMIT, PAGE_READWRITE);
      	GetWindowText(hwnd, caption, captionLength + 1);
       
      	return caption;
      }
       
      //=== Реализация функций, вызываемых из LUA ====================================================================//
      static int forLua_Do(lua_State *L)// Возвращает заданный текст
      {
      	string Str = "";
      	HWND hInfoClass = FindWindow("InfoClass", NULL);
       
       
      	HWND hMDIClient = FindWindowExA(hInfoClass, NULL, "MDIClient", NULL);
       
      	HWND h = NULL;
      	while (Str != "Карман") {
      		h = FindWindowExA(hMDIClient, h, "HostWindow", NULL);
      		Str = GetWindowCaption(h);
      	}
       
       
      	HWND hPocket = h;
       
      	HWND hInfoMDITransPocket = FindWindowEx(h, NULL, "InfoMDITransPocket", "Карман");
       
      	HWND hMultiList = FindWindowEx(hInfoMDITransPocket, NULL, "MultiList", "");
       
      	ShowWindow(hInfoClass, SW_MINIMIZE);
      	ShowWindow(hInfoClass, SW_RESTORE);
       
      	ShowWindow(hPocket, SW_MINIMIZE);
      	ShowWindow(hPocket, SW_RESTORE);
       
      	PostMessage(hMultiList, WM_RBUTTONUP, NULL, NULL);
      	h = NULL;
      	TCHAR buff[100];
      	string buffer = "";
      	while (true) {
      		h = FindWindowExA(NULL, h, NULL, NULL);
      		GetClassName(h, buff, 100);
      		buffer = buff;
      		int index = buffer.find("#");
      		if (index != string::npos && GetWindowCaption(h) == "") {
      			break;
      		}
      	}
       
      	for (int i = 0; i < 12; i++) {
      		PostMessage(h, WM_KEYDOWN, VK_DOWN, NULL);
      		PostMessage(h, WM_KEYUP, VK_DOWN, NULL);
      	}
       
      	PostMessage(h, WM_KEYDOWN, VK_RETURN, NULL);
      	PostMessage(h, WM_KEYUP, VK_RETURN, NULL);
       
      	return (0);
      }
       
       
      //=== Регистрация реализованных в dll функций, чтобы они стали "видимы" для Lua ================================//
      static struct luaL_reg ls_lib[] = {
      	{ "Do", forLua_Do }, // из скрипта Lua эту функцию можно будет вызывать так: QuikPocketPopAll.Do(); здесь можно указать любое другое название
      	{ NULL, NULL }
      };
       
      //=== Регистрация названия библиотеки, видимого в скрипте Lua ==================================================//
      extern "C" LUALIB_API int luaopen_QuikPocketPopAll(lua_State *L) {
      	luaL_openlib(L, "QuikPocketPopAll", ls_lib, 0);
      	return 0;
      }
      1. Дмитрий, огромная БЛАГОДАРНОСТЬ Вам за эту информацию.
        Как вы и советовали, применил связку из двух, рекомендованных Вами, сообщений и функция заработала!
        Отдельное Спасибо за код DLL-ки, очень мне пригодится для руководства.
        Очень точный ответ и вовремя.
        Спасибо.

          1. Дмитрий, Добрый День.
            Моя программка работает, но часто вылавливает не обновлённое состояние меню Квика. Например если реально ткнуть мышкой в окно графика,
            то меню заполняется командами актуальными для графика, после этого меню как бы виснет и не хочет обновлять своё содержимое пока реально (программный тык не помогает) не ткнёшь в него реальной мышкой.
            Подскажите пожалуйста, Какое сообщение нужно послать в (или для) меню Квика, чтобы оно (меню)
            приобрело своё новое состояние (обновилось) в связи с вновь выбранным (активированным) окном с таблицей?
            Спасибо.

  2. Дмитрий, здравствуйте.
    Может дадите совет?
    Где почитать, как снять информацию с листа квика (Имя класса: MultiList). Именно этот класс составил проблему.
    Вариант написания робота (Lua), который собирает информацию и взаимодействует с моей программой, не подходит.
    Программу пишу на С++.
    Спасибо.

            1. Вот, что он написал:
              "Могу только посоветовать тому человеку использование функций WinAPI
              FindWindowEx
              далее, после того, как HWND окна MultiList будет найден - уже можно будет установить перехватчик сообщений посылаемых окну на свою оконную функцию где и будет анализ сообщений. После того, как действия будут выполнены - надо передать сообщение штатной функции окна.
              Сам хук - можно установить функцией винапи SetWindowsHookEx

              либо через
              SetWindowLongPtr
              с параметром
              GWLP_WNDPROC
              при этом - сохранив указатель на старую оконную функцию"

              1. Спасибо.
                MultiList нахожу без всяких сложностей.
                Буду пробовать вылавливать сообщения листу, чтобы узнать как с ним общаться.
                Покопал в интернете, MultiList - какая-то тайна за семью печатями, маловато информации.
                Дмитрий, Спасибо Огромное.

                1. Продолжение: "нет смысла искать MultiList в интернете.
                  Это внутренний QUIK-овский оконный класс. Как получать и изменять сообщения окна (в том числе и класса MultiList) - указано по приведённым ссылкам.
                  Чтобы отделить один мультилист от другого и выделить нужный HWND - можно смотреть (проверять в цикле с FindWindowEx) на заголовок окна (ф-ция WinAPI GetWindowText)"

                    1. Вот, что ответил на это специалист 🙂 : "большего сказать не могу. пусть сам дальше думает. простого метода нет."

      1. Это Вам. Спасибо.
        Под последним вашим постом почему-то отсутствует кнопка "Ответить".
        Поэтому сказал "Спасибо" немного в другом месте. 8-))

  3. Дмитрий, здравствуйте.
    Может ли скрипт, по достижении ценой определённого уровня, приостановить работу другого скрипта,
    потом при каких-то условиях, опять запустить его в работу?
    По сути нужен скрипт управляющий работой другого скрипта.
    Возможно это?
    Прошу совета.
    Спасибо.

    1. Здравствуйте. Вопрос не мне, но...
      В рамках одного терминала, используя StaticVar https://quik2dde.ru/viewtopic.php?id=61.
      Скрипт, который должен приостановить свою работу, может опрашивать соответствующее поле на предмет "работать"/"покурить" и уходить в цикл, который будет ждать команды "работать".

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

        1. Здравствуйте.
          В таком случае все просто, вам нужно написать скрипт, который будет передавать в поле StaticVar команды, затем отдать этот скрипт вместе с купленным разработчику купленного скрипта и за отдельную плату он вам подключит StaticVar, объявит нужное пространство имен, сделает опрос ячейки памяти и ожидающий цикл.
          Ну или переписать логику купленного скрипта, что несколько сложнее, но открывает больше возможностей для вас лично))

          1. Уважаемый kalikazandr, Спасибо.
            Переписывать купленный скрипт, не вариант.
            Изменять купленный скрипт, не вариант.
            Обращаться к разработчику купленного скрипта, не вариант.
            Нужно написать скрипт, который будет управлять приостановкой(при условиях) и запуском в работу(при условиях) стороннего (купленного) скрипта.
            Прошу совета.
            Спасибо.

            1. Чтож, в таком случае делаете скрипт, который будет сильно вас извещать при наступлении соответствующего события и выключать/включать купленный скрипт руками, как самый легкий путь. Либо попробовать используя w32.dll (с выше указанного форума) найти окно "доступные скрипты" и кнопки управления в этом окне. Задача не тривиальная, на мой взгляд проще переписать платного бота или получить исходники.

              1. Нужно написать скрипт, который будет управлять приостановкой(при условиях) и запуском в работу(при условиях) стороннего (купленного) скрипта.
                Спасибо.

                  1. Тут напишу.
                    Нужна работа купленного робота (написан на QLUA) в заданном мною диапазоне цен (часть стратегии).
                    При выходе цены из диапазона купленный скрипт (робот) приостанавливаем, при заходе цены в диапазон запускаем.
                    Желательно, чтобы управляющий купленным роботом скрипт был написан на QLUA.
                    Спасибо.

                    1. Здравствуйте! Через WinAPI, наверное, можно это реализовать, т.е. программно нажимать кнопки "Запустить" и "Остановить" скрипт, но нужно будет поковыряться, чтобы до них добраться. Пример использования WinAPI есть в скрипте автоматической авторизации: https://quikluacsharp.ru/quik-qlua/qlua-lua-skript-avtomaticheskoj-avtorizatsii/