Как-то раз при разработке одной программы у меня возникла необходимость встроить какую-нибудь красивую мини-игру в раздел About. Так как делать красивую игру средствами WinAPI - это то ещё удовольствие и по срокам и по времени, то я решил просто-напросто встроить flash-файл в свой проект. Примерное описание того, как это сделать, мы и рассмотрим далее. В примере мы пойдем чуть дальше, а именно не только встроим флеш-ролик в окно, но и добавим парочку элементов управления. В результате у нас получится нечто подобное:
Таким образом, разобрав пример, вы запросто сможете встроить этого замечательного (или какого-нибудь другого) единорога в свое приложение, пускай и цена этого выкрутаса будет ~2.5 мегабайта.
Итак, приступим. Как всегда, начинаем с инклудов, констант, глобальных переменных и прочей лабуды.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
//Регистрируем содержимое библиотеки типов и переименовываем созданное пространство имен #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-контента и несколько элементов управления.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
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 брутфорса.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
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 (согласитесь, гораздо проще пихнуть в оверлей флешку, а не клепать хреновые билдеры с ограниченными возможностями по редизайну).
Скачать: исходный код + бинарник с флешкой
Добавил в закладки.
А без ATL слабо?
Конечно, я ведь программирую через пень колоду. Хотя если подгонишь спецификацию формата flash последней версии...
Байтоёбы байтоёбчики.
Always, I wanna be with you
And make believe with you
And live in harmony, harmony, oh love :3