Пишем свою оболочку для FP под Windows. Шаг 2.
Как и обещал, сегодня рассмотрим альтернативные способы подключения плеера к приложениию. Эти способы будут работать даже если плеер не установален (не зарегистрирован) на целевой машине.
Загрузка с диска.
Файл плеера Flash.ocx (версия не имеет значения) представляет из себя обычный PE-файл.
Проще говоря, это обычная DLL, которая экспортирует ряд функций. Однако есть и отличие: в этой библиотеке сидят не просто функции, там зашит класс, класс плеера.
Библиотека спроектирована таким образом, что любое приложение может обратитившись к ней когда нужно, создать экземпляр этого класса и использовать. Как и все ActiveX длл-ки
Flash.ocx экспортирует четыре функции:
DllCanUnloadNow()
DllGetClassObject()
DllRegisterServer()
DllUnregisterServer()
Последние две используются как раз при регистрации/отмене регистрации контрола в системе и для наших целей они, вобщем-то, не нужны.
А вот DllGetClassObject() - то что нужно. Эта функция позволит получить нам указатель
на «фабрику», которая и породит для нас экземпляр контрола.
Сигнатура это функции стандартна:
DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv);
Что мы сделаем: загрузим либу, найдем эту функцию и вызовем ее с соответствующими параметрами:
// определяем тип будущего указателя на DllGetClassObject() typedef VOID (WINAPI *LPGetClassObject )(REFCLSID rclsid, REFIID riid, LPVOID* ppv); // загружаем либу HMODULE hModule = LoadLibrary(szFileOCX); // получаем указатель на DllGetClassObject() LPGetClassObject fLPGetClassObject = (LPGetClassObject)GetProcAddress(hModule, "DllGetClassObject"); // вызываем IClassFactory* clf = NULL; IShockwaveFlash* flash = NULL; fLPGetClassObject(CLSID_ShockwaveFlash, IID_IClassFactory, (LPVOID*)&clf); // фабрика создет для нас экземпляр плеера и сохраняет указатель на него в flash HRESULT hr = clf->CreateInstance(NULL, __uuidof(IShockwaveFlash),(void**)&flash); clf->Release();
HRESULT CFlashWnd::CreateInstance(WCHAR* szFileOCX) { if(isInit) return S_FALSE; HMODULE hModule = LoadLibrary(szFileOCX); if(!hModule) return S_FALSE; LPGetClassObject fLPGetClassObject = (LPGetClassObject)GetProcAddress(hModule, "DllGetClassObject"); if(!fLPGetClassObject ) return S_FALSE; IClassFactory* clf = NULL; fLPGetClassObject(CLSID_ShockwaveFlash, IID_IClassFactory, (LPVOID*)&clf); if(!clf ) return S_FALSE; HRESULT hr = clf->CreateInstance(NULL, __uuidof(IShockwaveFlash),(void**)&flash); clf->Release(); isInit = hr == S_OK; return hr; }
Загрузка из ресурсов.
Сначала, собственно, включим 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 в инклудах базового класса.
Ну, теперь дело техники:
HRESULT CFlashWnd::CreateInstance(UINT id, WCHAR* resType) { if(hInst == NULL) return S_FALSE; if(isInit) return S_FALSE; IClassFactory* clf = NULL; HRSRC hResInfo = ::FindResource(hInst, MAKEINTRESOURCE(id), resType); if(!hResInfo) return S_FALSE; DWORD dwFlashOCXCodeSize = ::SizeofResource(hInst, hResInfo); if(dwFlashOCXCodeSize == 0) return S_FALSE; HGLOBAL data = ::LoadResource(hInst, hResInfo); if(!data) return S_FALSE; LPVOID lpFlashOCXCode = ::LockResource(data); if(!lpFlashOCXCode) return S_FALSE; HMEMORYMODULE hMem = MemoryLoadLibrary(lpFlashOCXCode); if(!hMem ) return S_FALSE; LPGetClassObject fLPGetClassObject = (LPGetClassObject)MemoryGetProcAddress(hMem, "DllGetClassObject"); if(!fLPGetClassObject ) return S_FALSE; fLPGetClassObject(CLSID_ShockwaveFlash, IID_IClassFactory, (LPVOID*)&clf); if(!clf ) return S_FALSE; HRESULT hr = clf->CreateInstance(NULL, __uuidof(IShockwaveFlash),(void**)&flash); clf->Release(); isInit = hr == S_OK; return hr; }
Дальше — по накатанной. Получаем «фабрику», потом инстанс плеера.
Использование:
Вот и все.
... ан нет. Не все. Случайно обнаружил такую вот непонятную багу.
Совершенно произвольно я длительное время использовал для эмбеда 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 из ресурсов приложения.
Всего комментариев 0
Комментарии
Последние записи от alexcon314
- Пишем свою оболочку для FP под Windows. Шаг 6. (19.05.2011)
- Пишем свою оболочку для FP под Windows. Шаг 5. (18.05.2011)
- Пишем свою оболочку для FP под Windows. Шаг 4. (18.05.2011)
- Пишем свою оболочку для FP под Windows. Шаг 3. (18.05.2011)
- Пишем свою оболочку для FP под Windows. Шаг 2. (17.05.2011)