Встраиваем Flash в свое приложение
Вторник, 17. Январь 2012
Раздел: C/C++, Windows, автор: Kaimi
Как-то раз при разработке одной программы у меня возникла необходимость встроить какую-нибудь красивую мини-игру в раздел About. Так как делать красивую игру средствами WinAPI - это то ещё удовольствие и по срокам и по времени, то я решил просто-напросто встроить flash-файл в свой проект. Примерное описание того, как это сделать, мы и рассмотрим далее. В примере мы пойдем чуть дальше, а именно не только встроим флеш-ролик в окно, но и добавим парочку элементов управления. В результате у нас получится нечто подобное:
Таким образом, разобрав пример, вы запросто сможете встроить этого замечательного (или какого-нибудь другого) единорога в свое приложение, пускай и цена этого выкрутаса будет ~2.5 мегабайта.
Итак, приступим. Как всегда, начинаем с инклудов, констант, глобальных переменных и прочей лабуды.
//Регистрируем содержимое библиотеки типов и переименовываем созданное пространство имен #import "progid:ShockwaveFlash.ShockwaveFlash" rename_namespace("Flash") //atl* - необходимы для работы с классами из Active Template Library (ATL) #include <atlbase.h> #include <atlwin.h> #include <comutil.h> #include <string.h> #include <Windows.h> //Флешка, которая будет отображаться в программе по умолчанию #define DEFAULT_FLASH TEXT("flash.swf") //Идентификаторы кнопок на форме для обработки события WM_COMMAND #define ID_PLAY 101 #define ID_STOP 102 #define ID_LOAD 103 //Размер окна плеера по-умолчанию #define WIN_W 600 #define WIN_H 550 //Размер кнопок управления и интервал между ними #define BUTTON_W 60 #define BUTTON_H 20 #define BUTTON_STEP 15 //CComModule - модуль COM-сервера, необходим для доступа к его компонентам //более подробно тут: http://msdn.microsoft.com/en-us/library/1300df24.aspx CComModule _ccm; HINSTANCE ghInst; HWND ghWnd; //Прототипы используемых в проекте функций DWORD GetOpenName(TCHAR * outbuf, const TCHAR * filter, const TCHAR * title); LRESULT CALLBACK WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam); int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrev, LPSTR lpCmdLine, int nCmdShow);
Теперь WinMain, в ней создадим обыкновенное окно, которое будет содержать дочернее окно для вывода flash-контента и несколько элементов управления.
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrev, LPSTR lpCmdLine, int nCmdShow) { WNDCLASS wc = {0}; MSG msg; ghInst = hInstance; //Инициализируем COM-библиотеку CoInitialize(NULL); //Регистриуем класс AtlAxWin* //http://msdn.microsoft.com/ru-ru/library/54fexdxd.aspx AtlAxWinInit(); //Определяем атрибуты основного окна wc.lpszClassName = L"swf"; wc.hInstance = hInstance; wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE); wc.lpfnWndProc = WndProc; wc.hCursor = LoadCursor(NULL, IDC_ARROW); //Регистриуем класс основного окна if(!RegisterClass(&wc)) return MessageBox(HWND_DESKTOP, L"RegisterClass", L"Error", MB_ICONERROR | MB_OK); //Создаем окно HWND hWnd = CreateWindow ( wc.lpszClassName, L"swf", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, WIN_W, WIN_H, NULL, NULL, hInstance, NULL ); if(!hWnd) return MessageBox(HWND_DESKTOP, L"CreateWindow", L"Error", MB_ICONERROR | MB_OK); //Запускаем процесс обработки оконных сообщений while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } //Выгружаем COM-библиотеку, очищаем ресурсы, бла-бла-бла CoUninitialize(); return msg.wParam; }
Следующей идет функция обработки оконных сообщений WndProc.
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam) { //Указатель на объект ShockwaveFlash static Flash::IShockwaveFlash * flash_o; //Хендлы кнопок управления и окна для флешки static HWND hWndAX, play, stop, load; static RECT rc; //Буфер для хранения пути открываемого swf-файла WCHAR file_path[MAX_PATH]; ghWnd = hWnd; switch(uMessage) { case WM_CREATE: //Получаем размер клиентской области окна GetClientRect(ghWnd, &rc); //Создаем кнопки управления play = CreateWindow ( L"button", L"Play", WS_CHILD | WS_VISIBLE, rc.left + BUTTON_STEP, rc.bottom - 25, BUTTON_W, BUTTON_H, hWnd, (HMENU) ID_PLAY, NULL, NULL ); stop = CreateWindow ( L"button", L"Stop", WS_CHILD | WS_VISIBLE, rc.left + BUTTON_W + BUTTON_STEP, rc.bottom - 25, BUTTON_W, BUTTON_H, hWnd, (HMENU) ID_STOP, NULL, NULL ); load = CreateWindow ( L"button", L"Load", WS_CHILD | WS_VISIBLE, rc.left + BUTTON_W + BUTTON_W + BUTTON_STEP, rc.bottom - 25, BUTTON_W, BUTTON_H, hWnd, (HMENU) ID_LOAD, NULL, NULL ); //Создаем окно, в котором будет выводиться flash-содержимое hWndAX = CreateWindowEx ( 0, CAxWindow2::GetWndClassName(), NULL, WS_CHILD | WS_VISIBLE, 0, 0, WIN_W, WIN_H - 70, hWnd, NULL, ghInst, NULL ); //Создаем объект ShockwaveFlash и сохраняем указатель на него if ( FAILED ( CoCreateInstance ( __uuidof(Flash::ShockwaveFlash), NULL, CLSCTX_ALL, __uuidof(Flash::IShockwaveFlash), (void**)&flash_o ) ) ) return -1; //Прикрепляем созданный объект к окну if(FAILED(AtlAxAttachControl(flash_o, hWndAX, NULL))) { flash_o->Release(); return -1; } //Получаем директорию, откуда был запущен процесс GetCurrentDirectory(MAX_PATH, file_path); //Формируем путь swprintf_s(file_path, MAX_PATH, L"%ws\\%ws", file_path, DEFAULT_FLASH); //Загружаем флеш-файл flash_o->LoadMovie(0, file_path); //Отключаем расширенное меню флеша (которое появляется при нажатии пкм) flash_o->Menu = VARIANT_FALSE; //Определяем размеры окна GetWindowRect(hWnd, &rc); //Перемещаем окно в центр экрана SetWindowPos ( hWnd, NULL, (GetSystemMetrics(SM_CXSCREEN) - rc.right) / 2, (GetSystemMetrics(SM_CYSCREEN) - rc.bottom) / 2, 0, 0, SWP_NOZORDER | SWP_NOSIZE ); return 0; case WM_COMMAND: //Обрабатываем нажатия на элементы управления в окне switch(LOWORD(wParam)) { case ID_PLAY: flash_o->Play(); break; case ID_STOP: flash_o->Stop(); break; case ID_LOAD: if(GetOpenName(file_path, TEXT("Flash (*.swf)\0*.swf\0Все файлы (*.*)\0*.*\0\0"), TEXT("Открыть..."))) flash_o->LoadMovie(0, file_path); break; } return 0; //Обрабатываем изменение размеров окна, эдакий резиновый интерфейс case WM_SIZE: //Изменяем размеры внутреннего окна MoveWindow(hWndAX, 0, 0, LOWORD(lParam), HIWORD(lParam) - 70, TRUE); GetClientRect(hWnd, &rc); //Перемещаем элементы управления MoveWindow(play, rc.left + BUTTON_STEP, rc.bottom - 25, BUTTON_W, BUTTON_H, TRUE); MoveWindow(stop, rc.left + BUTTON_W + BUTTON_STEP, rc.bottom - 25, BUTTON_W, BUTTON_H, TRUE); MoveWindow(load, rc.left + BUTTON_W + BUTTON_W + BUTTON_STEP, rc.bottom - 25, BUTTON_W, BUTTON_H, TRUE); return 0; case WM_CLOSE: //Уничтожаем окна DestroyWindow(hWndAX); DestroyWindow(hWnd); return 0; case WM_DESTROY: //Освобождаем объект flash_o->Release(); PostQuitMessage(0); return 0; } return DefWindowProc(hWnd, uMessage, wParam, lParam); }
И, наконец, мини-функция, отвечающая за диалог открытия файла. Функция нагло скопирована из исходного кода SSH брутфорса.
DWORD GetOpenName(TCHAR * outbuf, const TCHAR * filter, const TCHAR * title) { OPENFILENAME ofn = {0}; TCHAR buf[MAX_PATH + 2]; GetModuleFileName(ghInst, buf, MAX_PATH); TCHAR * tmp = StrRChr(buf, NULL, L'\\'); if(tmp != 0) { *tmp = 0; ofn.lpstrInitialDir = buf; } ofn.hInstance = ghInst; ofn.hwndOwner = ghWnd; ofn.lStructSize = sizeof(OPENFILENAME); ofn.lpstrFilter = filter; ofn.nFilterIndex = 1; ofn.lpstrFile = outbuf; ofn.lpstrFile[0] = 0; ofn.lpstrFile[1] = 0; ofn.nMaxFile = MAX_PATH; ofn.lpstrTitle = title; ofn.Flags = OFN_EXPLORER | OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_LONGNAMES | OFN_NONETWORKBUTTON | OFN_PATHMUSTEXIST; return GetOpenFileName(&ofn); }
Если не брать в расчет элементы управления и авторесайз внутреннего окна при изменении размеров внешнего, то получили в общем-то довольно простой пример, который запросто подгоняется под свои задачи как, например, флеш-блокиратор windows (согласитесь, гораздо проще пихнуть в оверлей флешку, а не клепать хреновые билдеры с ограниченными возможностями по редизайну).
Скачать: исходный код + бинарник с флешкой


Bo0oM :
Добавил в закладки.
[Ответить]
foox :
А без ATL слабо?
[Ответить]
Kaimi:
Январь 18th, 2012 at 18:29
Конечно, я ведь программирую через пень колоду. Хотя если подгонишь спецификацию формата flash последней версии...
[Ответить]
Kolomna_Rulezzz :
Байтоёбы байтоёбчики.
[Ответить]
NO_WAI,_MLP_Rules! :
Always, I wanna be with you
And make believe with you
And live in harmony, harmony, oh love :3
[Ответить]