Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Блоги Правила Справка Пользователи Календарь Поиск рулит! Сообщения за день Все разделы прочитаны
 

Вернуться   Форум Flasher.ru > Блоги > chingachgoog

Оценить эту запись

Работа в Цинке с несколькими COM-портами

Запись от chingachgoog размещена 17.12.2009 в 20:51

Цинк, к сожалению умеет работать только с одним COM-портом.
Оттого класс mdm.COMPort статичный (по-крайней мере исходя из мануала).
При попытке открыть новый COM-порт, старый просто начинает игнорироваться.

Что же делать, когда надо работать с несколькими COM-портами?
Опробованное мной решение - запуск дополнительного (невидимого) Цинк-приложения, основная функция которого - работа с COM-портом и связь с основным Цинк-приложением через LocalConnection.

Собственно все. Работает довольно стабильно.
Ниже будут интересные моменты связанные с этим способом.
Всего комментариев 7

Комментарии

Старый 17.12.2009 21:21 chingachgoog вне форума
chingachgoog
 
Аватар для chingachgoog
Проблема №1 - дополнительное приложение должно быть невидимое

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

Цинк умеет прятать окна, например там есть метод
mdm.Forms.имя_формы.hide()

Но все равно будет замусорена панель задач (таскбар) и режим Alt+Tab.
Метода типа mdm.Application.hide() в Цинке нет!

Поэтому придется пошаманить с WinAPI и стандартными виндовыми библиотеками:

Собственно нам нужна только одна библиотека - user32.dll:
Код:
// Загружаем из системы стандартную библиотеку
myDLL=new mdm.DLL(mdm.System.Paths.windows+"/system32/user32.dll")
if (!myDLL.isLoaded) mdm.Dialogs.prompt("Не удалось найти user32.dll")
В этой библиотеке и есть нужный нам метод ShowWindow(hWnd,SW_HIDE)
Хэндлер окна можно получить методом Цинка mdm.System.getWindowList(), но тут постигает неудача, т.к. этот метод дает только хэндлер окна (формы) приложения, а не самого приложения.
При использовании полученного таким образом хэндлера в методе ShowWindow мы получим лишь аналог метода Цинка mdm.Forms.имя_формы.hide(). Т.е. форма (окно) с экрана скроется, но в панели задач останется (((

Поэтому придется использовать еще одну функцию WinAPI: FindWindow(nil,'Имя приложения'):

Код:
// Даем приложению (заголовку) уникальное имя:
mdm.Application.title = "Уникальное имя"

// Ищем хэндл этого приложения (не путать с хэндлом главного окна приложения!)
myDLL.clear()
myDLL.addParameter("integer", "0");
myDLL.addParameter("string", "Уникальное имя");
hWnd = myDLL.call("integer", "FindWindowA");
Собственно теперь остается лишь запустить ShowWindow(hWnd,SW_HIDE):

Код:
myDLL.clear()
myDLL.addParameter("integer", hWnd)
myDLL.addParameter("integer", "0")
myDLL.call("boolean", "ShowWindow")
Приложение исчезло из панели задач (таскбара)!
Вкупе с mdm.Forms.имя_формы.hide() и установкой Цинка (Size/Position -> Form Behavior -> Visible снять чекбокс) мы получили практически шпиёна, которого видно только в процессах диспетчера задач!
Старый 17.12.2009 21:34 chingachgoog вне форума
chingachgoog
 
Аватар для chingachgoog
Проблема №2 - открытие разными приложениями одного COM-порта

Если при открытии одним и тем же приложением другого COM-порта Цинк просто проигнорирует предыдущий, то в обратном случае, когда второе Цинк-приложение открывает (пытается открыть) тот же COM-порт, что и первое вываливается цинковский дебаггер, что совсем не весело.

Цинковский мануал врет (обычное для мануалов дело), что метод mdm.COMPort.open ничего не возвращает. Он возвращает булевую величину: подключились или нет.

Код:
var zzz=mdm.COMPort.open(port, ... );
if (!zzz) mdm.Dialogs.prompt("Не удалось подключиться к "+port)
Но в случае с подключением двух приложений возникает исключение, которое вываливает окно дебаггера Цинка. Как его перехватить я пока не знаю. Поэтому просто совет - следить, чтобы два приложения не пытались присоединиться к одному COM-порту.
Старый 18.12.2009 09:19 alexcon314 вне форума
alexcon314
Я не понял, ты еще один ехе запускаешь? Вот из-за чего сыр-бор)).
А дочернюю форму просто сделать не пробовал?
Ну, типа MainForm - это свф с кодом для взаимодействия с портом СОМ1, SubForm1 - это свф с кодом для для взаимодействия с портом СОМ2. Дочернюю форму тупо делать невидимой, или через mdm.Forms.имя_формы.hide() или в настройках проекта галочку Size/Position -> Form Behavior -> Visible не ставить. И общаться с оной гораздо было бы удобнее через mdm.Forms.formName.callFunction() (ну, впрочем, это уже детали). Я как-то давненько проверял - код в каждой форме исполняется отдельным потоком, так что коннекты к портам не должны накладываться друг на друга. Есть правда трабла: код в дочернй форме не начнет исполняться, пока ее не покажешь. Но это лечится.

Да, еще есть в настройках проекта галочка PC Executable Settings -> Do not show in Taskbar. Там же, кстати и Show in Tray. Так что без лишних телодвижений можно написать что-то типа сервиса, т.е. программки, которая висит в трее, по клику или событию разворачивается, а то и вообще не видна)).

Даешь "каспера" на флэше!! Смерть шпиёнам!!
Обновил(-а) alexcon314 18.12.2009 в 09:24
Старый 18.12.2009 10:50 chingachgoog вне форума
chingachgoog
 
Аватар для chingachgoog
Цитата:
Да, еще есть в настройках проекта галочка PC Executable Settings -> Do not show in Taskbar.
Точно! ))) Эффект тот же и проще )))

Цитата:
А дочернюю форму просто сделать не пробовал?
Ну, типа MainForm - это свф с кодом для взаимодействия с портом СОМ1, SubForm1 - это свф с кодом для для взаимодействия с портом СОМ2.
Это сразу пробывал. Но не вышло. Мне показалось, что mdm.COMPort - это один единственный метод/класс оболочки и не важно в каком окне крутится флеш-плеер.

Хотя я не стал долго копать в этом направлении. Присмотрюсь еще раз. Обе формы у меня были видимыми...

add:

Хотя не уверен, что даже если так работает (через субформу), то это мне поможет. Мне заранее не известно число COM-портов, с которыми придется работать. Поэтому мой экзешник можно запускать нужное число раз - по числу COM-портов.
В Цинке разве можно динамически создавать субформы? Можно, конечно, создать процесс mdm.Process.create(), но как туда подгрузить код?
Обновил(-а) chingachgoog 18.12.2009 в 11:18
Старый 18.12.2009 12:40 alexcon314 вне форума
alexcon314
В тройке можно динамически создавать субформы, параметром указав свф для нее, насколько помню. В двойке нельзя. Но это.. можно зашить форм по максимуму, на мильен же их надо.
Насчет
Цитата:
Это сразу пробывал. Но не вышло. Мне показалось, что mdm.COMPort - это один единственный метод/класс оболочки и не важно в каком окне крутится флеш-плеер.
возможно, тут ты прав. Я не проверял. Если будешь проверять, попробуй callFunction() сделать, вызвав функцию коннкекта в дочерней форме, чтоб наверняка принудить ее коннектится, не полагаясь на автоматическое исполнение кода в субформе.
Обновил(-а) alexcon314 18.12.2009 в 12:45
Старый 21.12.2009 15:51 chingachgoog вне форума
chingachgoog
 
Аватар для chingachgoog
Проблема №3 - закрытие COM-порта

С закрытием COM-порта у меня происходит мистика. То ли Цинк глючит, то ли драйвер COM-устройства. Если из приложения убрать все mdm.COMPort.close(), то частота глюка резко уменьшается. Но 100% глюк не убивается - он просто реже всречается.

Нормальная работа:
Открываем приложение с COM-портом. Закрываем приложение.
(на устройстве видно, что приходит какой-то сигнал от приложения - моргает диод. Причем сигнал приходит и без mdm.COMPort.close()
Открываем приложение второй раз - все работает...

Глюк:
Открываем приложение с COM-портом. Закрываем приложение.
(на устройстве видно, что никакого сигнала не приходит. Особенно часто это происходит при использовании mdm.COMPort.close())
Открываем приложение второй раз - висим (очевидно при попытке открыть COM-порт). Висим мертво, без цинковского дебаггера и т.п. Только резет спасает.

Вобщем рекомендую избавиться от всех mdm.COMPort.close() в программе.
Старый 24.12.2009 16:09 chingachgoog вне форума
chingachgoog
 
Аватар для chingachgoog
Покспериментировал с субформами...

Вообщем, заставить работать два COM-порта пока не удалось.
Но выяснился интересный момент: mdm.COMPort.open может открывать НОВЫЙ порт в одном приложении только в том случае, если не был вызван обработчик onCOMPort. Вернее mdm.COMPort.open ОТКРЫВАЕТ новый порт (возращает true), но обработчик onCOMPort не переназначается и работает с изначального COM-порта. Видимо все дело именно в обработчике. Осталось придумать как его размножить...
 

 


Часовой пояс GMT +4, время: 05:51.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.