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

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

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

Расширение проектора: Продолжение 2. LocalConnection UP!

Запись от alexcon314 размещена 17.06.2009 в 12:02
Обновил(-а) alexcon314 18.06.2009 в 10:44

Итак, с инжектом разобрались. Теперь займемся LocalConnection.
В проекторе нам понадобится экземпляр класса ЛЦ. Инициалицировать коннект мы будем примерно таким образом:
Код:
var dll_url = "E" + Math.random();
var prj_url = "P" + Math.random();
dll_url = dll_url.split(".").join("");
prj_url = prj_url.split(".").join("");
var client = new LocalConnection();
client.connect(prj_url);
client.send(dll_url, prj_url);
в чем глубокий смысл данного куска кода? exe_url и prj_url - имена коннектов, которые будут слушать
длл и проектор соответственно. Они формируются как строка из случайного набора цифр, дабы обеспечить уникальность оных.
Теперь не страшно, если юзер изволит запустить несколько копий нашего приложения одновременно, надеюсь, понятно почему?
Однако, самое "ноу-хау" кроется в последней строке.
Смотрим: происходит сэнд, но на момент его осуществления НЕТ реального коннекта с именем dll_url!
Поэтому флэш сэндит сообщение, записав в поля заголовка сообщения "размер" и "таймстамп" нули.
Тело сообщения, адресат и пр. AMF-аттрибутика остается как есть. Но, никакой другой нормальный флэшовый ЛЦ данное сообщение не примет.
А вот длл примет, и если это первое сообщение, а оно обязательно должно быть первым, запомнит, какой урл ей дальше слушать (адресат - dll_url) и на какой урл отправлять свои мессаги (метод - prj_url). В этом контексте остается незадействованной возможность передачи некоторых аргументов при сэнде
(третий параметр отсутствует). Аргумент можно заюзать, на пример, для передачи каких-то инит-параметров, дебуг-левел, скажем. Пока оставляю это в стороне, есть интересная мысль как его использовать. Обязательно к этому вернусь.
Все дальнейшие сообщения из проектора так же будут с "нулевыми" размером и таймстампом, другие сообщения длл просто не будет читать, она настроена именно таким образом.
А те, которые шлет длл в проектор будут совершенно нормальные, с размером и таймстампом.
Все это приводит к "невмешательству" нашего ЛЦ проектор-длл в любые другие ЛЦ-каналы, так же как и другие ЛЦ не смогут помешать работе нашего. То бишь, имеем изолированный канал связи, что не может не радовать.
Далее, в ЛЦ (флэшовом) можно передавать любые обЪекты, поддающиеся AMF-сериализации, как то строки, числа, массивы, объекты и т.д. Полный перечень есть в спецификации. Вобщем-то, неплохо. Однако, в длл, по большому счету, нам достаточно реализовать сериализацию/десериализацию данных типа String. Собственно, стринг передается более компактно, чем, скажем, массив. А место нам придется экономить: лимит на объем сообщения 40кБ никто не отменял. Потом, мне показалось проще реализовать некий универсальный механизм парсинга строк в длл с преобразованием кусков в нужные типы данных. По крайней мере, разбора строк для целей оболочки хватает. Я не отметаю напрочь возможности реализации работы и с другими AMF-упакованными данными. Больше всего мне интересно реализовать работу с byte array. Но это уже относится к АС3, и это дело будущего, сейчас речь идет о АС2-версии оболочки..
Получив первое сообщение с именами коннектов, длл пытается вызвать метод init() на стороне проектора. В АС это выглядело бы так:
Код:
 lc.send(prj_url,"init",params);
В качестве параметров длл передает некоторые сведения, как то: путь к папке из которой произошел старт проектора, путь к юзерскому профилю в системе, позицию и размер окна. Можно без особых усилий дополнить этот список любыми другими сведениями, проявив фантазию и смекалку, но пока оставим, как есть. Все эти данные пакуются в строку с разделителем " :", который используется и при составлении строк, отправляемых из проектора. Опционально разделитель можно настроить. В проекторе реализуем метод:
Код:
 client.init = function(msg:String) {
 //здесь разбираем строку msg и отдаем первые команды в оболочку.
}
Т.е. ini() - первый метод(или функция), который будет вызван оболочкой в проекторе. Все, теперь ЛЦ up!
Как организована связь.
Проектор шлет команду, типа "установи позицию окна в (0,0)". Длл, приняв команду, генерит свой внутренний евент, спускающий отдельный поток, в котором команда обрабатывается, сендится результат ее выполнения в проектор и генерится евент "слушай дальше". И так по кругу.
В проекторе команды тоже шлются не абы как. Организуется очередь команд. Зачем? Дело в том, что приниматься за обработку следующей команды, не закончив обработку предыдущей, негоже. Потому каждая команда сендится из проектора в длл только по факту прибытия сообщения с результатом (плохим или хорошим, не важно) предыдущей команды. Ответом длл на первое сообщение будет вызов метода init на стороне клиента в проекторе. Это важно. Именно с него начинается прокачка основной очереди команд.
Проектор стартует со скрытым окном. В обработчик init можно ( и нужно) вставить вызов методов по настройке внешнего вида окна, завершив вызовом метода show(), дабы окно показать. Или как минимум просто вызов show(). Это не единственный путь "инициализации" приложения, есть мысль отправлять некий сценарий инициализации прямо в превом запросе (третий параметр первого send'а в длл, помните?), тогда init() останется просто как дополнительная опция.
Далее я приведу примеры, а сейчас один момент.

Из сказанного видно, что наша оболочка обладает одной весьма важной и не очень приятной особенностью: команды, отсылаемые оболочке выполняются асинхронно с кодом, их пославшим, т.е. с АС-кодом. В целом, все это сильно походит на взаимодействие "клиент-сервер", когда отослав запрос, вы вынуждены ожидать ответ, чтобы продолжить работу. Т.е. в АС нельзя написать что-то типа
Код:
 var result = any_method(any_params);
Придется писать что-то вроде:
Код:
 any_method(any_params);// это мы просто отправили команду в длл.
 listener.onData = function(message){
	// здесь обрабатываем результат выполнения any_method()
 }
Это усложняет код, увы. Требуется некоторый опыт.
Ставить обработчик на результат каждого метода не обязательно. Прокачка очереди команд организована независимо от того, есть обработчик на результат предыдущей команды или нет.
Вобщем, все сказанное выше, я попытался облачить в набор АС2-классов. Причем классов, в которых есть только статические члены. Это позаимствовано у цинка, где "оболочечные" классы представляют из себя просто наборы статических функций.
Далее, я приведу перчень классов, которые уже реализованы в той или иной степени в длл-оболочке с их кратким описанием. Общее их количество 15 (пока). Число методов в совокупности около 100. Ну, и примеры, конечно.
Всего комментариев 31

Комментарии

Старый 17.06.2009 19:32 chingachgoog вне форума
chingachgoog
 
Аватар для chingachgoog
Цитата:
Из сказанного видно, что наша оболочка обладает одной весьма важной и не очень приятной особенностью: команды, отсылаемые оболочке
выполняются асинхронно с кодом, их пославшим, т.е. с АС-кодом.
Есть у меня подозрения, что во ФП есть возможность ПОЛНОСТЬЮ приостанавливать все события, т.е. можно добиться эффекта синхронности.
Помните, в Цинке
Код:
myDLL = new mdm.DLL("user.dll") // загрузка dll
if (!myDLL.isLoaded) {...
Вторая строчка синхронна с первой! Т.е. флеш ждет, пока загрузиться user.dll!
Впрочем можно и более банально увидеть "флеш-останов" - нажать кнопку "закрыть окно" и удерживать нажатой мышь (если отпустить в другом месте, то флеш продолжит прерванную работу). А еще останов есть при локальной загрузке файлов.
Старый 18.06.2009 10:35 alexcon314 вне форума
alexcon314
Конечно, можно остановить выполнение АС. метод delay(miliSec:Number) - один из первых, что я реализовал, помнится)). Но тут есть специфика, связанная с ЛЦ. Насколько я понял, канал ЛЦ плеер "опрашивает" самопроизвольно, ну т.е. просто в основном потоке наряду с остальными функциями стоит, видимо и этот "опрос". Скажем, если приостановить обработку оконной функции все замрет. Но не факт, что замрет именно прерд вызовом опроса, может после пробуждения таки выполнится какой-то другой кусок кода или еще что.., вобщем, пока это дело темное. Принудительно заставить плеер опросить канал и забрать данные не получается. Да и не в этом дело даже. Сам ЛЦ так реализован, что нету у него точки возврата. send() и все. Поток пошел дальше. И пофик, куда там send() ушел. Увы, синхронность тут в пролете.
В цинке все иначе. Там юзается ExternalInterface, и там все по-другому. Там реально получаем синхронный вызов. call() "приостанавливает" поток, точнее, все выглядит так, как если бы плеер выполнял обычный АС код, ну типа подвызова функции, только подвызов уходит в оболочку.
Обновил(-а) alexcon314 18.06.2009 в 10:39
Старый 25.06.2009 20:57 chingachgoog вне форума
chingachgoog
 
Аватар для chingachgoog
Цитата:
Конечно, можно остановить выполнение АС. метод delay(miliSec:Number) - один из первых, что я реализовал, помнится)).
А это тут на форуме "помнится" или вообще?
Старый 26.06.2009 09:23 alexcon314 вне форума
alexcon314
Это я про свою "оболочку".
Старый 26.06.2009 14:06 chingachgoog вне форума
chingachgoog
 
Аватар для chingachgoog
Интересная возможность. Напиши про нее как-нибудь. Ведь ее можно использовать в других оболочках (которые как раз через ExternalInterface взаимодействуют, например). А может даже можно сделать обратный ход? "Разморозить" останов при загрузке локальных файлов?
Старый 26.06.2009 15:14 alexcon314 вне форума
alexcon314
Способ, который использовал я - вызов Sleep(dwMilliseconds) где нибудь в оконной процедуре проектора. Можно еще "вешать" мьютекс по которому плеер получает доступ к ЛЦ-каналу, но это по-ходу одно и тоже. Ибо кроме операций с сетью, все крутится в одном потоке. Насчет разморозить не понял.
Старый 26.06.2009 15:52 chingachgoog вне форума
chingachgoog
 
Аватар для chingachgoog
Цитата:
Насчет разморозить не понял.
Я про старую проблему, типа с прелоудером на локальном приложении
Когда ФП при локальной загрузке чего-либо останавливает всю перерисовку экрана и весь код (но событие onProgress все же где-то накапливается и после загрузки "выстреливает" скопом). Это я и назвал "заморозкой" или остановом.
Зачем это делается мне не понятно, но прелоудер из-за этого сделать решительно невозможно. Вот и подумалось насчет обратного хода - разморозки при загрузке файлов.
Старый 28.07.2009 18:27 Skyggedans вне форума
Skyggedans
 
Аватар для Skyggedans
Интересная темка

А кто знает как в AS3 принудительно выставить у LocalConnection objectEncoding в AMF3?
Я щас пишу расширение к AIR-у для того, чтобы прикрутить к нему Python, причем в качестве механизма сериализации был выбран pickle, потому как в питоне уже есть готовый быстрый встроенный модуль. AS-ответку я уже написал, на входе/выходе у нее ByteArray, который нужно частями пропихивать через LC. Но почему-то данные в память флэш кладет в AMF0 А так как AMF0 про ByteArray ничего не знает, он его сериализует как обычный Object, то есть без данных.

Кстати, у меня уже есть готовая рабочая реализация проектора через ExternalInterface в связке с Питоном, но там юзается ActiveX а NPSWF32.dll я так и не смог прикрутить, поэтому проект пока забросил и взялся за AIR. Если интересно будет, могу подкинуть по этой теме много идей.
Старый 29.07.2009 09:08 alexcon314 вне форума
alexcon314
Цитата:
Если интересно будет, могу подкинуть по этой теме много идей.
По какой теме? Каких идей?
Старый 29.07.2009 11:05 Skyggedans вне форума
Skyggedans
 
Аватар для Skyggedans
Цитата:
По какой теме? Каких идей?
По теме ExternalInterface и синхронизации.

Кстати, вчера таки нашел как сделать так, чтобы LocalConnection клал данные в омегу в AMF3 формате. Когда записываешь listener в блок по смещению 40096, за его именем надо впихнуть строку вида "::4", тогда флэш каким-то образом определяет, что листенер поддерживает AMF3 и начинает сериализовать в него.
Старый 29.07.2009 14:04 alexcon314 вне форума
alexcon314
Интересно. До этого не добрался сам.
Ну, так какие идеи? Я имею в виду синхронизацию без ExternalInterface?
Да и еще, по каким законам происходит сериализация в SharedObject? ну и десереализация? ЛЦ - это что-то вроде шаредов, только "онлайн" и можно сразу просекать версию клиента. А в шаредах тогда как?
Обновил(-а) alexcon314 29.07.2009 в 14:22
Старый 29.07.2009 14:20 Skyggedans вне форума
Skyggedans
 
Аватар для Skyggedans
А что если на LocalConnection.status повесить обработчик, который при изменении статуса будет устанавливать некий flag, а после вызова send() входить в
Код AS3:
while (!flag);
и ждать пока flag не будет установлен?
status отработает в данном случае? (я с LC только недавно работать начал)
Старый 29.07.2009 14:27 Skyggedans вне форума
Skyggedans
 
Аватар для Skyggedans
В шаредах в отличие от LC разрабы оставили пропертя defaultObjectEncoding и objectEncoding, так что там все вручную рулится.
Старый 29.07.2009 14:30 alexcon314 вне форума
alexcon314
Т.е. вешать плеер? Ну, идея не так уж безумна.. Только вряд ли кто-нибудь установит флаг - онстатус обрабатывается в одном потоке с циклом. Если в цикл засадить проверку чего-нибудь "внешнего", того же шареда, к примеру - куда ни шло. Это получится типа эмуляция двух потоков (плеера и оболочки) с одним объектом синхронизации (шаредом) в их общем пользовании. Жаль только Sleep или Wait во флэше нету.
defaultObjectEncoding скорее превнесли а не "оставили", т.е. сделали новое свойство. Раньше такого не было. А разрулить можно только в девятке. Но это в смысле применения в оболочке не особо критично, думаю.
Обновил(-а) alexcon314 29.07.2009 в 14:38
Старый 29.07.2009 14:36 Skyggedans вне форума
Skyggedans
 
Аватар для Skyggedans
Ну предусмотреть две возможности, там где синхронизация критична, то вешать.
В моем проекторе именно так и делается - где ответ нужен здесь и сейчас - там ждем возврата от ExternalInterface.call(), а где нужна отложенная операция - там через call() вызывается метод некоего питоновского объекта, который запускает новый поток в интерпретаторе и сразу дает возврат. А когда поток отрабатывает, из него вызывается враппер для CallFunction() флэшового ActiveX-а, в который передается имя callback-а в ActionScript-е, которое формируется как ИмяКлассаОбъекта@АдресЭкземпляра_ИмяМетода.
Старый 29.07.2009 14:44 alexcon314 вне форума
alexcon314
Эммм... не понял. Что значит "ждем возврата от ExternalInterface.call()"?
ExternalInterface.call() сама по-себе синхронаая операция. Или я не прав? Чего там "ждать" и "вешать" - все само "вешается" как надо.
Про две возможности - это да, я тоже думаю, что это может быть полезно. Либо синхронный вызов, либо, если нужда какая - асинхронный: отправил в обработку отделный поток, тот отработал и отдуплился. Прикольно. Практической ценности пока ноль, но в этом что-то есть. Вобщем-то, ExternalInterface - "это просто".
Но использование ActivX-плеера легально только если юзер сам его установил в систему, предварительно скачав с сайта адоба. А если не установит все накрывается медным тазом.
А вам не приходилось делать API-перехват?
Обновил(-а) alexcon314 29.07.2009 в 14:50
Старый 29.07.2009 14:57 Skyggedans вне форума
Skyggedans
 
Аватар для Skyggedans
Как-то делал TimeFake для отучения от триала одной гитарной софтины. Помнится там инжектилась длл-ка, в которой находилась фейковая GetLocalTime() на которую подменялся указатель в таблице импорта этого exe-шника.
Старый 29.07.2009 15:02 Skyggedans вне форума
Skyggedans
 
Аватар для Skyggedans
Вообще, все эти Адобовские лицензии, конечно, зло.
Я как-то сделал стартёр для AIR прилад, чтоб работали всегда и везде, а потом в лицензии прочитал, что запрещается распространять их райнтайм путем обхода процедуры установки и подтверждения пользователем их EULA
Старый 29.07.2009 15:09 Skyggedans вне форума
Skyggedans
 
Аватар для Skyggedans
Кстати, насколько я знаю вместе с Firefox-ом поставляется и NPSWF32.dll, интересно, какая на него лицензия...
Но заюзать эту штуку задача нетривиальная, хотя в ScreenWeawer-е это как-то сделали. Но я хоть и смотрел исходники, но нифига не понял.
Старый 29.07.2009 15:09 alexcon314 вне форума
alexcon314
Ну вот, я и говорю "Да зравствует стандартный проектор!"
Конечно, можно в свое удовольствие юзать ActiveX, только как-то это скучно. Можно фреймворк какой нить смастрячить типа f-in-box'a, только кому он нужен?
Я даже сомневаюсь что и расширение стандартного проектора, даже если что-то и выйдет, будет иметь успех... ибо, есть тот-же цинк.
Обновил(-а) alexcon314 29.07.2009 в 15:13
Старый 29.07.2009 15:11 Skyggedans вне форума
Skyggedans
 
Аватар для Skyggedans
Да, кстати, а как, интересно, Адоб смотрит на существование таких вещей как Цинк и F-IN-BOX. Одно дело, был бы это какой-то опенсорс, то еще фиг с ним, а так это вполне серьезные коммерческие проекты, за которые просят очень серьезные деньги.
Старый 29.07.2009 15:19 alexcon314 вне форума
alexcon314
Ааа.. вот это не очень понятно. По смутным обрывочным сведениям у мдм есть древний договор с макромедией еще, который якобы не утратил юридической силы до сих пор. Кроме того, они ссылаются вот сюда. Другие, типа финбокса, вообще плеер не распространяют, либо тоже клянутся в наличии какой-то идульгенции.
Вот тут было обсуждение.
Обновил(-а) alexcon314 29.07.2009 в 15:25
Старый 29.07.2009 15:25 Skyggedans вне форума
Skyggedans
 
Аватар для Skyggedans
Плеер-то с финбоксом они не распространяют, но финбокс на то и финбокс, чтоб юзать флэш без установки. Как они, интересно, аргументируют это своим кастомерам, которые покупают этот продукт за деньги.
Старый 29.07.2009 15:28 alexcon314 вне форума
alexcon314
Да никак. Мы не распространяем, и точка. Все под твою юзерскую ответственность.
Старый 29.07.2009 15:43 Skyggedans вне форума
Skyggedans
 
Аватар для Skyggedans
Вспомнил тут по синхронизации LocalConnection.
send() же вроде не возвращает управление, пока не вычитает обнуленные timestamp и length из омеги? А для этого ему нужно владение мютексом. Что мешает не отпускать мютекс до завершения операции в бэкенде? Причем, LC в отличие от ExternalInterface не вываливается с мессагой, когда наступает таймаут на возврат из call().
Старый 29.07.2009 16:23 alexcon314 вне форума
alexcon314
Ничто не мешает держать мютекс, это да. Но, то что "...пока не вычитает нули..." - это вряд ли. send() возвращает управление, если была произведена успешная запись в маппинг-файл и мютекс им отпущен. Отправителю пофик, кто и когда проичитает мессадж. Нули - это признак, что адресат получил мессадж, и ждать пока он получит, не отпуская мютекс при этом, можно вечно.
Потом, получил я мессадж, захватил мутекс, держу пока не отработаю, отработал-отпустил. Но синхронизировать не выйдет. Пока я получу мютекс и залочу, пока поток плеера дойдет до обращения к захваченному мютексу на следующем витке проверки и встанет в очередь ожидания.. Вобщем, пара - тройка ас-строчек выполнится, а может и еще чего, скажем кадр нагружен или еще там что.. . и возврат произойдет не туда..
ЛЦ - штука отличная, но синхронизировать лц-вызовы нельзя, так по крайне мере мне думается сейчас.
А вот апи-перехват - это уже теплее. Думаю, использовать этот вариант, как основной, лц оставить для евентов, ну и если замахиваться, то и на асинхронные вызовы.
Для перехвата выбрал обращения к шаредам. Запись в шаред - это WriteFile(), ловим, читаем команду, физически в файл можно не писать. Обрабатываем, отпускаем (return). В ас за записью ставим сразу чтение - это Readfile(), ловим, подставляем результат, отпускаем. В итоге в ас после записи-чтения имеем на выходе результат обработки команды. Насколько мне удалось выяснить, все операции с локальными шаредами в плеере синхронизированы. Но тут есть свои заморочки: плеер может брать шареды не с диска а из памяти, если неправильно к ним обращаться в ас, т.е. ловля ReadFile в пролете; что-то не ладится с буферами при подстановке в ReadFile(), не пойму пока что именно; нужно предусмотреть обращение плеера к локальным настройкам размеров шаредов и подставить в момент этого обращения нужные настройки; version depended: разные плееры по-разному реализуют работу с шаредами и на уровне апи и на уровне сериализации, то биш протокола... Но если выгорит - было бы кулл: синхронность+отсутствие ограничений на размер мессаджа в обе стороны.
Обновил(-а) alexcon314 29.07.2009 в 16:54
Старый 29.07.2009 16:52 Skyggedans вне форума
Skyggedans
 
Аватар для Skyggedans
А у шаредов тоже лимит в 40К?
Старый 29.07.2009 16:54 alexcon314 вне форума
alexcon314
Нет. Можно выставить анлимит в момент чтения настроек. Но если настроечных фалов нет, плеер генерит их по дефолту, принимает дефолтную 100к настройку на размер и тут поможет только перезапуск, когда он попытается считать настройки со сгенеренного файла.
Обновил(-а) alexcon314 29.07.2009 в 16:57
Старый 29.07.2009 18:36 Skyggedans вне форума
Skyggedans
 
Аватар для Skyggedans
Эх... Буду я новый проектор мутить походу на основе SWHX. Просто выкину из него весь Neko stuff и буду прикручивать питон.
Там, кстати, хитро сделано, используется External API но только для пропихивания своих сериализованных строк. Ну а я буду пихать через него свои pickle-строки, правда придется их искейпить, а это лишние затраты.
Старый 29.07.2009 20:01 alexcon314 вне форума
alexcon314
Skyggedans, предложение:
завести блог на флэшере и постить инфу по вашему проекту на основе SWHX. haXe, Neko тема не избитая, должно быть интересно.
Естественно, все на добровольной основе.
Ну, и удачи).
Старый 29.07.2009 21:41 Skyggedans вне форума
Skyggedans
 
Аватар для Skyggedans
Спасибо
Съезжу в отпуск и займусь вплотную
 

 


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


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