用ATL实现无窗口(Windowless)的Flash播放器

来源:互联网 发布:危险化学品查询软件 编辑:程序博客网 时间:2024/05/21 02:13
用ATL实现无窗口(Windowless)的Flash播放器
 
首先,说明一点:我不会写文章,如果有表达不清晰的地方,还请各位包涵一二了,可以在评论中告诉我。
 
其次,看这篇文章的至少要对ATL有一定的了解。
 
OK,开始主题,一开始我也是不知道ATL已经有实现windowless容器接口的类,所以我找到了codeproject上一个无窗的实现(http://www.codeproject.com/KB/atl/WindowlessMedia.aspx?msg=2948497#xx2948497xx)。他的标题是说用的ATL,其实不完全是这样,准确的说他是用了WTL。试着运行了他的例子,确实是无窗口显示Flash了。但是,因为我在我的应用里面加了个浏览器“刷新”一样的功能,用户可以按F5重新加载播放器。这时,我Release旧的播放器,再创建一个新的播放器,旧播放器并不能完全Release(也就是旧Flash还在内存中)。
 
后面在某个国外的帖子里面有人回复说可以用CAxHostWindow,于是看了下CAxHostWindow的代码,发现CAxHostWindow确实实现了Windowless容器所需要的接口,废话不多说了,直接上关键代码。

class ATL_NO_VTABLE CFlashWnd:
    public CAxHostWindow,
    public IFlashWindow
{
    DECLARE_NOT_AGGREGATABLE(CFlashWnd);
    DECLARE_WND_CLASS(_T("FlashWnd"))
    BEGIN_MSG_MAP(CFlashWnd)

        // …………更多自己要处理的消息
        if (uMsg == WM_NCHITTEST)
        {
            m_nHit = DefWindowProc(uMsg, wParam, lParam);
            lResult = m_nHit;
            return TRUE;
        }
        CHAIN_MSG_MAP(CAxHostWindow)
        if (m_nHit == HTCLIENT)
        {// 应用Flash的鼠标光标
            MESSAGE_HANDLER(WM_SETCURSOR, OnWindowMessage)
        }
        if (WM_MOUSEWHEEL == uMsg)
        {// 使Flash可以使用鼠标滚轮
            MESSAGE_HANDLER(WM_MOUSEWHEEL, OnWindowlessMouseMessage)
        }
        MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
    END_MSG_MAP()
    // create flash init stream,这个函数很关键,szFlashInit的数据是复制了设计器中的Flash控件的资源数据,里面已经设置好WMode为Opaque,这是Flash无窗口的基础。当然这里的做法是一个偷懒的办法,呵呵,因为我完全不了解ActiveX初始数据的组织格式;也没有去寻找其它方式提供初始数据
    HRESULT STDMETHODCALLTYPE CreateStreamInit(IStream** ppStream)
    {
        static WCHAR szFlashInit[]= { 0x0376, 0x011a, 0x0000,
            0x0000, 0x0000, 0x5567, 0x5566, 0x0900, 0x0000, 0x6775, 0x0000, 0x420b, 
            0x0000, 0x0008, 0x0002, 0x0000, 0x0000, 0x0008, 0x0000, 0x0000, 0x0008, 
            0x0000, 0x0000, 0x0008, 0x000e, 0x0000, 0x004f, 0x0070, 0x0061, 0x0071, 
            0x0075, 0x0065, 0x0000, 0x0008, 0x0006, 0x0000, 0x002d, 0x0031, 0x0000, 
            0x0008, 0x0006, 0x0000, 0x002d, 0x0031, 0x0000, 0x0008, 0x000a, 0x0000, 
            0x0048, 0x0069, 0x0067, 0x0068, 0x0000, 0x0008, 0x0002, 0x0000, 0x0000, 
            0x0008, 0x0006, 0x0000, 0x002d, 0x0031, 0x0000, 0x0008, 0x0000, 0x0000, 
            0x0008, 0x0002, 0x0000, 0x0000, 0x0008, 0x0010, 0x0000, 0x0053, 0x0068, 
            0x006f, 0x0077, 0x0041, 0x006c, 0x006c, 0x0000, 0x0008, 0x0004, 0x0000, 
            0x0030, 0x0000, 0x0008, 0x0004, 0x0000, 0x0030, 0x0000, 0x0008, 0x0002, 
            0x0000, 0x0000, 0x0008, 0x0000, 0x0000, 0x0008, 0x0002, 0x0000, 0x0000, 
            0x000d, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
            0x0008, 0x0004, 0x0000, 0x0031, 0x0000, 0x0008, 0x0004, 0x0000, 0x0030, 
            0x0000, 0x0008, 0x0000, 0x0000, 0x0008, 0x0004, 0x0000, 0x0030, 0x0000, 
            0x0008, 0x0008, 0x0000, 0x0061, 0x006c, 0x006c, 0x0000, 0x0008, 0x000a, 
            0x0000, 0x0074, 0x0072, 0x0075, 0x0065, 0x0000
        };
        HGLOBAL hMem = GlobalAlloc(GMEM_FIXED,sizeof(szFlashInit));
        LPVOID pData = GlobalLock(hMem);
        CopyMemory(pData, szFlashInit, sizeof(szFlashInit));
        GlobalUnlock(hMem);
        return CreateStreamOnHGlobal(hMem, TRUE, ppStream);
    }
    BOOL CreateFlash(HWND hWnd, RECT *pRect, DWORD ws=WS_OVERLAPPEDWINDOW|WS_VISIBLE, DWORD wsEx=0)
    {
        m_sizeMin.cx = pRect->right;
        m_sizeMin.cy = pRect->bottom;
        HMENU hMenu = NULL;
        Create(hWnd, pRect, NULL, ws, wsEx, hMenu);
        // 修正最小窗口大小
        LPSTREAM pStream = NULL;
        HRESULT hr = CreateStreamInit(&pStream);
        CComBSTR bstrLicKey;
        hr = _DialogSplitHelper::ParseInitData(pStream,&bstrLicKey.m_str);
        BOOL bRet = CreateFlashInstance(pStream);// pStream不为NULL,且WMode的属性必须为Opaque或Transparent,才能实现无窗口的Flash播放器
        pStream->Release();
        return bRet;
    }
    BOOL CreateFlashInstance(LPSTREAM pStreamInit=NULL)
    {
        HRESULT hr; 
        _bstr_t bStrClsid= L"ShockwaveFlash.ShockwaveFlash.1"
        hr = CreateControl(bStrClsid, m_hWnd, pStreamInit); 
        if(FAILED(hr)) 
        {
            MessageBox(_T("您没有安装Flash播放器或版本太低,请先安装最新版本Flash播放器"));
            DestroyWindow();
            return FALSE; 
        }
        shwaveflash = NULL;
        hr = QueryControl(__uuidof(IShockwaveFlash), (void**)&shwaveflash); 
        if(FAILED(hr)) 
            return FALSE; 
        long lVer = shwaveflash->FlashVersion();
        if (HIWORD(lVer) < 10 || (HIWORD(lVer)== 10 && LOWORD(lVer) < 2))
        {
            MessageBox(_T("您的Flash播放器版本太低,请升级到最新版本"));
            DestroyWindow();
            return FALSE;
        }
        IOleWindow* pOleWnd;
        if (shwaveflash->QueryInterface(IID_IOleWindow, (LPVOID*)&pOleWnd)== S_OK)
        {
            HWND hwnd;
            pOleWnd->GetWindow(&hwnd);    // 这里是取不到窗口句柄的
            pOleWnd->Release();
        }
        return TRUE;
    }
    // 销毁Flash
    BOOL DestroyFlash()
    {
        if (shwaveflash != NULL)
        {
            shwaveflash->Release();
            shwaveflash = NULL;
            
            ReleaseAll();
        }
        return TRUE;
    }
    void LoadUrl(_bstr_t url, _bstr_t flashvars)
    {
        shwaveflash->put_FlashVars(flashvars);
        bstr_t fullscreen(_T("true"));
        shwaveflash->put_AllowFullScreen(fullscreen);
        bstr_t allownet(_T("all"));
        shwaveflash->put_AllowNetworking(allownet);
        bstr_t allowscript(_T("always"));
        shwaveflash->put_AllowScriptAccess(allowscript);
        shwaveflash-> put_Movie(url);// you have to change the path here 
        shwaveflash-> Play(); 
    }
    LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
    {
        DestroyFlash();
        PostQuitMessage(0);
        bHandled = FALSE;
        return 0;
    }
    // …………省略若干方法
public:
    IShockwaveFlash * shwaveflash;
    LRESULT    m_nHit;
    // …………省略若干变量
};
 
CFlashWnd类的使用方法:
CComObject<CFlashWnd>  flashwnd;
flashwnd.CreateFlash(NULL, NULL);
flashwnd.LoadUrl(L"D:\\test.swf", L"");
 
以上代码因为是取的程序中的关键代码,所以不保证能够编译通过。
原创粉丝点击