Пишем свою оболочку для FP под Windows. Шаг 2.
Как и обещал, сегодня рассмотрим альтернативные способы подключения плеера к приложениию. Эти способы будут работать даже если плеер не установален (не зарегистрирован) на целевой машине.
Загрузка с диска.
Файл плеера Flash.ocx (версия не имеет значения) представляет из себя обычный PE-файл.
Проще говоря, это обычная DLL, которая экспортирует ряд функций. Однако есть и отличие: в этой библиотеке сидят не просто функции, там зашит класс, класс плеера.
Библиотека спроектирована таким образом, что любое приложение может обратитившись к ней когда нужно, создать экземпляр этого класса и использовать. Как и все ActiveX длл-ки
Flash.ocx экспортирует четыре функции:
DllCanUnloadNow()
DllGetClassObject()
DllRegisterServer()
DllUnregisterServer()
Последние две используются как раз при регистрации/отмене регистрации контрола в системе и для наших целей они, вобщем-то, не нужны.
А вот DllGetClassObject() — то что нужно. Эта функция позволит получить нам указатель
на «фабрику», которая и породит для нас экземпляр контрола.
Сигнатура это функции стандартна:
DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv);
Что мы сделаем: загрузим либу, найдем эту функцию и вызовем ее с соответствующими параметрами:
Загрузка из ресурсов.
Сначала, собственно, включим Flash.ocx в ресурсы приложеения.
Для этого добавим по строчке в файлы Resource.h и test.rc:
В директорию проекта (рядом с test.vcproj) положим Flash10o.ocx. Если в названии присутствует другая версия, внесите соответственно правки.
Компилируем (F7). Чувствуете, как вырос размер .ехе? Воот.
Далее логика мало отличается от предыдущего случая. За исключением вопроса: как загрузить длл из ресурсов? MS не предоставляет такого функционала на уровне Win API.
Но, как я уже говорил, интернет не без добрых людей:
http://www.joachim-bauch.de/tutorial. l-from-memory/
Здесь лежит то, что нам нужно — MemoryModule, код для загрузки длл из памяти.
(Патриотически замечу, что и наши программеры реализовали такую фичу, жаль ссылку потерял.)
Подключаем к проекту MemoryModule.c и MemoryModule.h (Правый клик по проекту->Добавить->Существующий элемент). Прописываем MemoryModule.h в инклудах базового класса.
Ну, теперь дело техники:
. ан нет. Не все. Случайно обнаружил такую вот непонятную багу.
Совершенно произвольно я длительное время использовал для эмбеда Flash10a.ocx (10.0.12.36) и не замечал, что он не грузит AVM2-ролики. Так уж вышло, что забот было других и я пользовал для тестов AVM1-ролик. Причем при загрузке этого .осх с диска и штатно — все ок.
Подсунул ему AVM2-ролик — и тут такой облом.
10.1.85.3 и 10.2.153.1 работают как ни в чем не бывало во всех трех режимах инициализации и с AVM2-роликами, и AVM1-роликами. Так что имейте в виду.
В тестовом проекте я прописал в #import и в .rc Flash10o.ocx (10.2.153.1). Не забудьте
положить его в директорию проекта.
На следующем шаге будем грузить swf из ресурсов приложения.
Пишем свою оболочку для FP под Windows. Шаг 6.
Бинарный буфер для обмена данными.
На этот раз я расскажу об одном трюке (трике?).
ExternalInterface, как вы знаете, работает только со строками: в XML пакуются числа, булы, что там еще.. А что если надо обмениваться бинарными данными? Да, конечно, есть basе64. Но все же.
Так вот. Есть несложный ход, который позволяет организовать бинарный буфер
для обмена данными. Об этом я немного рассказал здесь: http://www.flasher.ru/forum/blog.php?b=265
Итак, идея заключается в том, чтобы на стороне флеша создать экземпляр ByteArray, задать ему подходящий размер, ну, к примеру 1024*1024 (1Mб). Это и будет буфер. Размер его можно потом менять динамически, но это уже детали. Важно, чтобы экземпляр никуда не делся после создания, ссылку на него надо получше защитить.
Теперь надо получить указатель на этот буфер на стороне оболочки. Флеш не умеет передавать, да что там передавать, определять адреса своих переменных. Тут он нам ничем не поможет. К счастью, в С++ мы ничем таким не свзаны.
Займемся практикой.
Как видите, здесь после создания и выделения памяти (задали length) в sharedMemBlock
пишется «строка» «acegikmoacegikmo». Это закладка, «яйца».
Дальше дергаем EI. Ну, в данном примере название вызываемой функции не имеет значения. Важно просто поймать этот вызов в оболочке.
Поймав вызов, мы отправляемся на охоту (eggshunting):
Что может быть проще? Перебираем по-байтово память нашего процесса в поисках закладки. Процесс не такой уж и длительный. Зато теперь мы имеем указатель на буфер, созданный флешем! Можно расширить пример и показать, как в оболочке вытаскивать данные из буфера, записанные флешем. Но это я оставляю вам для тренировки. И, конечно, указатель на буфер следует тоже хорошенько запомнить в оболочке, если вы с ним хотите работать плотно.
Можно попробовать соптимизировать поиск закладки, например начинать не с нижнего адреса, а. с какого? Ну, например с адреса кучи процесса, как вариант, или с верхних адресов. Если хотите — займитесь на досуге. Но на мой взгляд это не принципиально.
А теперь немного фантазии.
Раз мы имеем бинарный буфер, можем туда писать, что угодно . то. то . эмм. да туда ж можно залить картинку из ресурсов, к примеру, или даже «исполняемый» swf!! И это безо всяких base64 и прочей лабуды! Чувствуете драйв?
ЗЫ: Подобные эксперименты я проводил и с AS2. Там в качестве буфера высупала BitmapData. Получалось найти буфер из оболочки по тому же принципу. Но дальше я не пошел. На сторне флеша с таким «буферм» работать не очень удобно, да и в оболочке тоже не фан. Впрочем, это чисто технические трудности. Другое дело, что AS2, видимо, вообще теряет актуальность. Для «оболочкописателей», по крайней мере. Хотя, и это не факт.
Пишем свою оболочку для FP под Windows. Шаг 6.
Бинарный буфер для обмена данными.
На этот раз я расскажу об одном трюке (трике?).
ExternalInterface, как вы знаете, работает только со строками: в XML пакуются числа, булы, что там еще.. А что если надо обмениваться бинарными данными? Да, конечно, есть basе64. Но все же.
Так вот. Есть несложный ход, который позволяет организовать бинарный буфер
для обмена данными. Об этом я немного рассказал здесь: http://www.flasher.ru/forum/blog.php?b=265
Итак, идея заключается в том, чтобы на стороне флеша создать экземпляр ByteArray, задать ему подходящий размер, ну, к примеру 1024*1024 (1Mб). Это и будет буфер. Размер его можно потом менять динамически, но это уже детали. Важно, чтобы экземпляр никуда не делся после создания, ссылку на него надо получше защитить.
Теперь надо получить указатель на этот буфер на стороне оболочки. Флеш не умеет передавать, да что там передавать, определять адреса своих переменных. Тут он нам ничем не поможет. К счастью, в С++ мы ничем таким не свзаны.
Займемся практикой.
Как видите, здесь после создания и выделения памяти (задали length) в sharedMemBlock
пишется «строка» «acegikmoacegikmo». Это закладка, «яйца».
Дальше дергаем EI. Ну, в данном примере название вызываемой функции не имеет значения. Важно просто поймать этот вызов в оболочке.
Поймав вызов, мы отправляемся на охоту (eggshunting):
Что может быть проще? Перебираем по-байтово память нашего процесса в поисках закладки. Процесс не такой уж и длительный. Зато теперь мы имеем указатель на буфер, созданный флешем! Можно расширить пример и показать, как в оболочке вытаскивать данные из буфера, записанные флешем. Но это я оставляю вам для тренировки. И, конечно, указатель на буфер следует тоже хорошенько запомнить в оболочке, если вы с ним хотите работать плотно.
Можно попробовать соптимизировать поиск закладки, например начинать не с нижнего адреса, а. с какого? Ну, например с адреса кучи процесса, как вариант, или с верхних адресов. Если хотите — займитесь на досуге. Но на мой взгляд это не принципиально.
А теперь немного фантазии.
Раз мы имеем бинарный буфер, можем туда писать, что угодно . то. то . эмм. да туда ж можно залить картинку из ресурсов, к примеру, или даже «исполняемый» swf!! И это безо всяких base64 и прочей лабуды! Чувствуете драйв?
ЗЫ: Подобные эксперименты я проводил и с AS2. Там в качестве буфера высупала BitmapData. Получалось найти буфер из оболочки по тому же принципу. Но дальше я не пошел. На сторне флеша с таким «буферм» работать не очень удобно, да и в оболочке тоже не фан. Впрочем, это чисто технические трудности. Другое дело, что AS2, видимо, вообще теряет актуальность. Для «оболочкописателей», по крайней мере. Хотя, и это не факт.
Пишем свою оболочку для FP под Windows. Шаг 3.
Загрузка swf из ресурсов.
Включаем construct.swf в ресурсы приложеения.
В директорию проекта (рядом с test.vcproj) положим Construct.swf. Если в название другое, внесите соответственно правки.
Компилируем (F7). Все гладко? Ок. Вообще, настоятельно рекомендую в Resource.h располагать дефайны по-возрастающей.
Как нам его загрузить в плеер? LoadMovie() понимает только физический путь к файлу на диске или в сети. А как из памяти загрузить? Для этого у плеера есть интерфейс IPersistStreamInit. Не буду тянуть за хвост резину:
Ну, вторую строчку еще можно осмыслить – просто в начало стрима пишем размер swf-данных, логично, вобщем-то. А вот зачем в самую голову стрима писать 0x55665566?
Если кто вразумительно ответит на этот вопрос, получит пирожок . Наверняка, кто-то что-то про это слышал. За себя скажу, что эти байты, видимо, о чем-то «говорят» плееру, о чем-то важном.. Возможно, о характере загружаемого контента.
Если инициализировать контрол по-другому, т.е. не из ресурсов, работает только первый вариант. Выходит, можно заранее «приготовить» таким образом плеер с мувом и потом его уже пользовать. О как.
Ну вот, фактически, мы имеем уже аналог стандартного флеш-проектора: плеер вшит, ролик вшит, полная автономия! Для разнообразия в тестовом проекте я зашил два ролика в ресурсы.
Но мы пойдем дальше, и на следующем шаге задействуем TRANSPARENT MODE плеера. Для того я, собственно, и припас Construct.swf.
Вложения
test3.zip (59.8 Кб, 274 просмотров) |
Комментарии
08.06.2011 17:04 |
08.06.2011 22:38 |
17.06.2011 14:45 |
Я знаю только 2: fUfU, gUfU =) А не подскажете где почитать про COM flash*.ocx? Не смог найти описание методов AxShockwaveFlash. Тоесть те, что интуитивно понятны, я пользую, а вот что есть — StopPlay()? =) |
17.06.2011 18:46 |
18.06.2011 16:19 |
Я с программером пытаюсь прикрутить флеш как GUI интерфейс к программе. Как мне кажется, для достойного плеера, необходимо все функции самого плеера оставлять загружаемой флешке, а она в свою очередь будет загружать другую, необходимую для показа. Пишем свою оболочку для FP под Windows. Шаг 5.Advise Sink: cоветую утопиться. Ну, вот. Похоже на то, что на этом шаге наши пути разойдутся. Если, конечно, они не разошлись раньше)). С хостом плеера более-менее разобрались. Осталось научить нашу оболочку общаться с плеером в духе «вопрос-ответ». Ну, и конечно, отдавать ему приказы. Как вы догадались, речь пойдет о взаимодействии оболочки и плеера через ExternalInterface. Видимо, это последнее, что можно отнести к «стандартным» знаниям об оболочке FP. Далее возможны варианты, то, как вы реализуете это взаимодействие — целиком ваша прерогатива. Я, по всей видимости, пойду своим путем. Конечно, я не замолкну и продолжу свои публикации насколько меня хватит. но это уже будет совсем другая песня. Ах, да. Есть еще одна фича про запас. Но о ней позже. Имплементим IDispatch в наш базовый класс. Тут есть такая возможность — унаследовать наш класс от абстрактного IDispatch, заменив абстрактные члены на нашу реализацию. И подставить его плееру, в качестве «слушателя» событий. Так и поступим. Рекомендую полностью перестроить проект после внесения изменений в исходники. Это все наброски, вы понимаете. На следующем шаге попробуем что-нибудь изобразить уже в плане «движка» для оболочки, взаимодействующей с плеером. Ну, и обещанная фича — «Создание динамических диалоговых окон и дочерних форм на основе флеш-плеера» — в одной из последующих статей. |