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

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

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

Пишем свою оболочку для FP под Windows. Шаг 6.

Запись от alexcon314 размещена 19.05.2011 в 09:16
Обновил(-а) alexcon314 24.05.2011 в 23:13

Бинарный буфер для обмена данными.

На этот раз я расскажу об одном трюке (трике?).
ExternalInterface, как вы знаете, работает только со строками: в XML пакуются числа, булы, что там еще.. А что если надо обмениваться бинарными данными? Да, конечно, есть basе64. Но все же.
Так вот. Есть несложный ход, который позволяет организовать бинарный буфер
для обмена данными. Об этом я немного рассказал здесь: http://www.flasher.ru/forum/blog.php?b=265
Итак, идея заключается в том, чтобы на стороне флеша создать экземпляр ByteArray, задать ему подходящий размер, ну, к примеру 1024*1024 (1Mб). Это и будет буфер. Размер его можно потом менять динамически, но это уже детали. Важно, чтобы экземпляр никуда не делся после создания, ссылку на него надо получше защитить.
Теперь надо получить указатель на этот буфер на стороне оболочки. Флеш не умеет передавать, да что там передавать, определять адреса своих переменных. Тут он нам ничем не поможет. К счастью, в С++ мы ничем таким не свзаны.
Займемся практикой.
Код AS3:
package gui 
{
	import flash.events.MouseEvent;
	import flash.external.ExternalInterface;
	import flash.utils.ByteArray;
 
	public class BinaryBuffer extends Sprite
	{
		private var sharedMemBlock:ByteArray = new ByteArray();
		public function GuiTest5() 
		{
			super();
			sharedMemBlock.length = 1024 * 1024;
			eggs(sharedMemBlock);
			var res:String = ExternalInterface.call("bla");// ok
			// проверьте содержимое  sharedMemBlock 
			// (acegikmoacegikmo HELLO, BUFFER!)
		}
		private static function eggs(arr:ByteArray):void 
		{
			for (var i:uint = 0; i < 8; i++)
			{
				arr[i] = arr[i+8] = 0x61 + i + i;
			}
 
		}
	}
}
Как видите, здесь после создания и выделения памяти (задали length) в sharedMemBlock
пишется «строка» «acegikmoacegikmo». Это закладка, «яйца».
Дальше дергаем EI. Ну, в данном примере название вызываемой функции не имеет значения. Важно просто поймать этот вызов в оболочке.
Поймав вызов, мы отправляемся на охоту (eggshunting):

Код AS3:
HRESULT MyFlash::FlashCall (_bstr_t xml_request)
{
	LPBYTE sharedMemBlock = FindSharedMemBlock();
	lstrcpyA((CHAR*)&sharedMemBlock[16]," HELLO, BUFFER!");
	// само-собой, в бинарный буфер можно писать не только строку :)
	SetReturnValue(_bstr_t("<string>ok</string>"));
    return S_OK;
}
LPBYTE MyFlash::FindSharedMemBlock()
{
UINT memBlockSize = 1024*1024;
	HANDLE hProc = GetCurrentProcess();
	SYSTEM_INFO si;
	GetSystemInfo(&si);
 
	LPBYTE lpBytes = NULL;
	MEMORY_BASIC_INFORMATION mi;
	BYTE buf[16] = {0x0};
	VirtualQueryEx(hProc,si.lpMinimumApplicationAddress, &mi,sizeof(mi));
 
	for( LPBYTE lpAddress = (LPBYTE)si.lpMinimumApplicationAddress;	lpAddress < si.lpMaximumApplicationAddress;	lpAddress += mi.RegionSize)
	{
		if(VirtualQueryEx(hProc, (LPCVOID)lpAddress, &mi,sizeof(mi)))
		{
			if((mi.Protect & PAGE_READWRITE) || (mi.Protect & PAGE_WRITECOPY))
			{
				for( LPBYTE b = lpAddress; b < lpAddress + mi.RegionSize; b += 16)
				{
					if(ReadProcessMemory(hProc,(LPCVOID)b,&buf,16,NULL))
					{
						int i = 0;
						while( i < 8)
						{
							if( buf[i] != 0x61 + i + i || buf[i+8] != 0x61 + i + i)
								break;
							i++;
						}
						if (i == 8)
						{
							lpBytes = b;
							VirtualProtect(lpAddress,memBlockSize,PAGE_EXECUTE_READWRITE,NULL);
							break;
						}
					}
				}
			}
 
		}
	}
	CloseHandle(hProc);	
	return lpBytes;
}
Что может быть проще? Перебираем по-байтово память нашего процесса в поисках закладки. Процесс не такой уж и длительный. Зато теперь мы имеем указатель на буфер, созданный флешем! Можно расширить пример и показать, как в оболочке вытаскивать данные из буфера, записанные флешем. Но это я оставляю вам для тренировки. И, конечно, указатель на буфер следует тоже хорошенько запомнить в оболочке, если вы с ним хотите работать плотно.
Можно попробовать соптимизировать поиск закладки, например начинать не с нижнего адреса, а... с какого? Ну, например с адреса кучи процесса, как вариант, или с верхних адресов. Если хотите — займитесь на досуге. Но на мой взгляд это не принципиально.

А теперь немного фантазии.
Раз мы имеем бинарный буфер, можем туда писать, что угодно .... то... то ... эмм... да туда ж можно залить картинку из ресурсов, к примеру, или даже «исполняемый» swf!! И это безо всяких base64 и прочей лабуды! Чувствуете драйв?

ЗЫ: Подобные эксперименты я проводил и с AS2. Там в качестве буфера высупала BitmapData. Получалось найти буфер из оболочки по тому же принципу. Но дальше я не пошел. На сторне флеша с таким "буферм" работать не очень удобно, да и в оболочке тоже не фан. Впрочем, это чисто технические трудности. Другое дело, что AS2, видимо, вообще теряет актуальность. Для "оболочкописателей", по крайней мере. Хотя, и это не факт...
Вложения
Тип файла: zip test6.zip (147.0 Кб, 221 просмотров)
Всего комментариев 6

Комментарии

Старый 01.06.2011 19:45 wvxvw вне форума
wvxvw
 
Аватар для wvxvw
А кстати, про это http://code.google.com/p/redtamarin/ знаешь? Я вот скоро буду разбираться, выглядит интересно на первый взгляд.

EDIT: Ой, и, кстати, а что если этот ByteArray, который ты использовал для примера, использовать для fastmemory? Туда у флеша будет гораздо более быстрый доступ на чтение / запись.
Обновил(-а) wvxvw 01.06.2011 в 19:58
Старый 02.06.2011 13:04 alatar вне форума
alatar
 
Аватар для alatar
Интересный проект это redtamari, надо бы последить за развитием.
Старый 02.06.2011 18:23 zorexundra вне форума
zorexundra
ИМХО, ExternalInterface гораздо быстрее передаёт String. Тобишь, на практике лучше сделать двойное преобразование бинарных данных в строку в swf и строку в бинарник в оболочке, чем доверить ExternalInterface "пропихнуть" наружу объект. Оно и понятно: при передаче объекта, XML внешнего API раздувается больше, нежели при передаче простых типов.
Старый 03.06.2011 01:57 wvxvw вне форума
wvxvw
 
Аватар для wvxvw
Я про fastmemory начал к тому, что это скорее всего будет один и тот же участок памяти для обертки и AS3, таким образом, например, найдя этот участок, в обертке можно организовать очень быструю выдачу данных, или, наоборот, считывание. Если бы еще во флеше процедуру опрашивания участка памяти можно было бы выделить в отдельный процесс...
Старый 03.06.2011 10:33 alexcon314 вне форума
alexcon314
Цитата:
Ой, и, кстати, а что если этот ByteArray, который ты использовал для примера, использовать для fastmemory? Туда у флеша будет гораздо более быстрый доступ на чтение / запись.
Да пожалуйста. Можно попробовать поискать в памяти другие структуры данных рантайма плеера... ByteArray, пожалуй, самое простое.
redtamarin не видел. Бегло посмотрел, не совсем проникся, если не трудно, ткните носом, в чем фан?
Буфер можно использовать при передаче данных в AMF. Там, конечно, придется повозиться со сборкой-разборкой. Но и наработки в этом плане открытые есть, скажем, pyamf. Так что не на пустом месте.
Я как бы не настаиваю. Смысл всех этих статей - показать как можно, а не именно как надо.
Цитата:
Если бы еще во флеше процедуру опрашивания участка памяти можно было бы выделить в отдельный процесс...
Что-то подобное происходит в LocalConnection. Там тоже блок памяти выделяется и расшаривается, к нему плееры подключаются периодически в очередь.
Старый 03.06.2011 11:53 wvxvw вне форума
wvxvw
 
Аватар для wvxvw
Я на redtamarin наткнулся когда искал всякие инструменты для тестирования / диагностики и т.п. Одна мысль была - вариант REPL'а для AS3. Есть еще другой проект AS3Term, но тот на AIR и очень требовательный, в смысле ему нужен x-server и все такое. Это не совсем в тему к статье, но немножко В смысле, вот о чем я думал:
мне бы очень хотелось для нормального тестирования мочь следующее: очень быстро передать информацию о текущем состоянии приложения (memory snapshot, состояние стека, значения в регистрах), а кроме этого, иметь возможность "на ходу" добавить какой-то код, или поменять существующий, при чем как вручную, так и в автоматическом режиме Ну еще и всякие штуки типа ассертов, логов и т.п.
Вот я и смотрю на redtamarin как на возможно недостающию часть в этом процессе.
 

 


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


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