Ниже представлен небольшой код, который находит все запущенные терминалы Quik и запускает экспорт всех таблиц путем нажатия пункта меню 'Экспорт Данных -> Начать экспорт таблиц по DDE'.
Код не требует никаких дополнительных библиотек, вам просто достаточно добавить этот код в свой проект.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
namespace QuikIntegration.dde
{
public class QuikUtil
{
private static string _exportMenuKey = "Экспорт данных";
private static string _stopExportMenuItem = "Остановить экспорт таблиц по &DDE";
private static string _startExportByDDEMenuItem = "Начать экспорт таблиц по &DDE";
// ReSharper disable InconsistentNaming
[DllImport("user32.dll")]
static extern IntPtr GetMenu(IntPtr hWnd);
[DllImport("user32.dll")]
static extern IntPtr GetSubMenu(IntPtr hMenu, int nPos);
[DllImport("user32.dll")]
static extern int GetMenuItemCount(IntPtr hMenu);
[DllImport("user32.dll")]
static extern int GetMenuString(IntPtr hMenu, uint uIDItem, StringBuilder lpString, int nMaxCount, uint uFlag);
[DllImport("user32.dll")]
static extern uint GetMenuItemID(IntPtr hMenu, int nPos);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true)]
static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
private const UInt32 MF_BYPOSITION = 0x00000400;
public static bool StartDDE()
{
IntPtr[] quikWindows = FindQuikWindow();
if (quikWindows.Length == 0)
{
return false;
}
foreach (var quikWindow in quikWindows)
{
IntPtr mainMenu = GetMenu(quikWindow);
int exportMenuIndex = (int)FindMenuItemByPart(mainMenu, _exportMenuKey);
IntPtr exportMenu = GetSubMenu(mainMenu, exportMenuIndex);
uint exportIndex = 6; // FindMenuItemByPart(exportMenu, _startExportByDDEMenuItem);
uint menuItem = GetMenuItemID(exportMenu, (int)exportIndex);
PostMessage(quikWindow, 0x111, (IntPtr)menuItem, (IntPtr)0);
}
return true;
}
public static bool StopDDE()
{
IntPtr[] quikWindows = FindQuikWindow();
if (quikWindows.Length == 0)
{
return false;
}
foreach (var quikWindow in quikWindows)
{
IntPtr mainMenu = GetMenu(quikWindow);
int exportMenuIndex = (int)FindMenuItemByPart(mainMenu, _exportMenuKey);
IntPtr exportMenu = GetSubMenu(mainMenu, exportMenuIndex);
uint exportIndex = 7; // FindMenuItemByPart(exportMenu, _stopExportMenuItem);
uint menuItem = GetMenuItemID(exportMenu, (int)exportIndex);
PostMessage(quikWindow, 0x111, (IntPtr)menuItem, (IntPtr)0);
}
return true;
}
private static IntPtr[] FindQuikWindow()
{
Process[] processes = Process.GetProcessesByName("info");
IntPtr[] result = new IntPtr[processes.Length];
for (int i = 0; i < processes.Length; i++)
{
result[i] = processes[i].MainWindowHandle;
}
return result;
}
private static uint FindMenuItemByPart(IntPtr menu, string name)
{
int menuItemsCount = GetMenuItemCount(menu);
for (uint menuIndex = 0; menuIndex < menuItemsCount; menuIndex++)
{
StringBuilder result = new StringBuilder();
GetMenuString(menu, menuIndex, result, 1024, MF_BYPOSITION);
string buffer = result.ToString();
if (buffer.Contains(name))
{
return menuIndex;
}
}
return 0;
}
}
// ReSharper restore InconsistentNaming
}
Для того, чтобы запустить экспорт всех таблиц нужно выполнить комманду:
QuikUtil.StartDDE();остановить
QuikUtil.StopDDE();
привет...
ОтветитьУдалитьмож подскажешь..
обнаружил что если в квике открыто окошко системных сообщений
обычный заголовок "QUIK: окно сообщений"
то, т.к. в этом окне нет никаких меню ДДЕ экспорта...
то и запустить дде-экспорт не удастся...
как бы докопаться до оригинального окна info процесса?
как закрыть это "оконо сообщений"?
можно ль послать команду на закрытие этого окна ?
и потом уж рыть в нужном процессе на счет дде-экспорта
P.S. приделал поиск нужного окна по UID
проще отключить в настройках показ окна сообщений
ОтветитьУдалитьВ этой строке
ОтветитьУдалитьGetMenuString(menu, menuIndex, result, 1023, MF_BYPOSITION);
получаю:
System.ExecutionEngineException
В среде выполнения обнаружена критическая ошибка. Ошибка произошла по адресу 0x707dceca в потоке 0xe18. Код ошибки 0xc0000005. Она может быть вызвана ошибкой в CLR или в небезопасных либо не поддающихся проверке фрагментах пользовательского кода. Обычно источниками таких ошибок бывают ошибки упаковки, допускаемые пользователями при COM-взаимодействии, либо PInvoke, повредивший стек.
Давно не заходил сюда, времени совсем нету.
ОтветитьУдалитьОшибка которую вы описываете у меня тоже последнее время начала возникать, причем возникает не постоянно, а периодически, у меня стоит Windows 7.
Проблему решил криво, но у меня теперь все работает. Сейчас все работает. В теле поста поправленный код.
Спасибо за код клика по пунктам меню очень помог)
ОтветитьУдалитьХотелось бы продолжения про DDE сервер
ОтветитьУдалитьребят, очень нужен программист, который бы собственно и настроил экспорт из квика на вебсайт. нужна утилита, которая организует синхронизацию между терминалом и сайтом.
ОтветитьУдалитьне пойму как тут написать в личку на блоге, отпишитесь мне в скайп, плз, vasart_ceo или на мыло vasart1@mail.ru
И все же представленный код вызывает исключение. Лекарство простое - надо явно задать длину строки StringBuilder. Строка 94:
ОтветитьУдалитьStringBuilder result = new StringBuilder(1024);
Можно сделать дину поменьше (побольше), но тогда в следующей строке указывать точно такую же длину.
Кстати прототип в строке 25 лучше вот так описать:
static extern int GetMenuString(IntPtr hMenu, uint uIDItem, [Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder lpString, int nMaxCount, uint uFlag);
А вообще спасибо автору за этот пост! Очень хороший код, который практически не пришлось править для своих целей )))) Но можно этот класс нагрузить еще немного и расширить его функционал для автоматического запуска QUIK, автоматического соединения с сервером и всяческими событиями по поводу внезапной кончины QUIK. Я в эту сторону обязательно пойду и, если это интересно, могу выложить дальнейшее развитие класса. Пишите на hamper [at] bk.ru
Спасибо!
Всем привет!
ОтветитьУдалитьУ меня в 51-й строке
PostMessage(quikWindow, 0x111, (IntPtr)menuItem, (IntPtr)0);
Валится на ошибке:
Переполнение в результате выполнения арифметической операции.
Подскажите плиз, с чем это может быть связано )))
А кто нить пробовал сделать, чтобы при разрыве связи он сам восстанавливал DDE экспорт ?))
ОтветитьУдалитьПривет,
ОтветитьУдалитьСтранная ошибка, у меня такой никогда не возникало. А какая версия терминала установлена?
А вот обработку разрыва связи нужно делать не в этом маленьком коде. Вам необходимо повесить слушателя на событие разрыва связи в trans2quik.dll и в случае если произошел разрыв нужно перезапустить dde.
Спасибо, уже решилась ..)
УдалитьКак выяснилось дело не в самом Postmessage а в параметрах которые туда поступают. Точно уже не помню, какие точно, помню только лишь что я раскомментил строки
FindMenuItemByPart(exportMenu, _stopExportMenuItem);
Может действительно в разных версиях квика разные номера меню ))
А Вы не реализовывали решение, чтобы он сам восстанавливал DDE экспорт при его разрыве ?)
Здравствуйте!
ОтветитьУдалитьПодскажите пожалуйста, а как сделать автозапуск экспорта только лишь таблицы текущих параметров?
Добрый день,
ОтветитьУдалитьК сожалению данный код настолько туп, что умеет делать только одну операцию - это имитировать нажатие кнопки меню квика "Экспорт всех таблиц". Чтобы сделать экспорт только таблицы текущий параметров предлагаю вам настроить на экспорт только данную таблицу (хотя конечно я абсолютно не знаю как вы используете остальные таблицы и возможно данный вариант вам не подходит).