在网页中只需要加入以下代码
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,29,0" width="600" height="60">
<param name="movie" value="test.swf">
<param name="quality" value="high">
<param name="wmode" value="transparent">
<embed src="***.swf" quality="high" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" width="600" height="60"></embed>
</object>
就可以实现 Flash 背景透明
在VC中要实现 Flash 背影透明播放,Google了一下找到一个 Demo
原文URL:
http://www.codeproject.com/KB/COM/flashcontrol.aspx需要自己实现一个OLE容器,以前很少接触COM,现在要实现的是一个OLE容器,先汗一下!!!!
想到一个问题:自己实现一个OLE容器跟使用直接使用FlashOcx 控件有何不同?
-- 未解决
Part 1
实现一个ActiveX对象的OLE容器需要继承几个接口
IOleClientSite
IOleInPlaceSiteWindowless
IOleInPlaceFrame
IStorage
(具体做什么,需要找资料恶补一下~~~~ ActiveX, OLE容器……)
在DEMO里实现了一个OLE容器类叫 COleContainerWnd
template<CLASS T>
class COleContainerWnd : virtual public IOleClientSite,
virtual public IOleInPlaceSiteWindowless,
virtual public IOleInPlaceFrame,
virtual public IStorage
是个模板类,T是留给 ActiveX 的接口
Part 2
把 flash.ocx 引进来,因为里面包含了Flash播放器的相关接口定义,它就是我们要放到容器里的 ActiveX 对象了
#import "flash.ocx" named_guids
Part 3
CFlashWnd派生类
class CFlashWnd: public COleContainerWnd<ShockwaveFlashObjects::IShockwaveFlash>,
public ShockwaveFlashObjects::_IShockwaveFlashEvents,
public ShockwaveFlashObjects::IServiceProvider
再汗一下,CFlashWnd 是个容器,还要实现 public ShockwaveFlashObjects::IServiceProvider 接口作甚?
至于要继承 ShockwaveFlashObjects::_IShockwaveFlashEvents 接口的目的是为了接收 Flash 动画发过来的 fscommand() 事件,在 Flash的AS(动作脚本)中调用 FsCommand(),就会
触发这个事件了
(这是一个精通 Flash 的同学告诉我的!!)
CFlashWnd 对象的创建
g_flashWnd = new CFlashWnd;
g_flashWnd->Create(ShockwaveFlashObjects::CLSID_ShockwaveFlash,
WS_EX_LAYERED, WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS,
g_hWnd, g_hInst);
Create() 函数的第一个参数:Flash 播放对象的ClassID
Create() 函数的第二个参数:窗体的扩展风格 WS_EX_LAYERED ,据说加了这个风格才能实现透明 Flash ,为啥?
……
Part 4
CFlashWnd::Create() 的内幕
注册了窗口类,然后就 CreateWindows 了
值得注意的是
OleCreate() 函数用来创建一个 IOleObject 对象的实例,需要 把 Ole 容器 的 IOleClientSite 和 IStorage 作为参数传给它
hr = OleCreate(m_CLSID, IID_IOleObject, OLERENDER_DRAW,
0, (IOleClientSite *)this, (IStorage *)this, (void **)&m_lpO);
不解的是,virtual public IOleInPlaceSiteWindowless 跟 virtual public IOleInPlaceFrame 不用理了?
hr = OleSetContainedObject(m_lpO, TRUE);
OleSetContainedObject () 函数通知 IOleObject 对象跟它说,你已经被嵌到 OLE 容器里了
hr = m_lpO->QueryInterface(__uuidof(T), (void **)&m_lpControl);
然后用 IOleObject 的 QueryInterface 获取 IShockwaveFlash 接口(那个 T, 就是 ShockwaveFlashObjects::IShockwaveFlash 了)
hr = m_lpO->QueryInterface(IID_IViewObjectEx, (void **)&m_lpViewObjectEx);
同样的方法,也得到了 IViewObjectEx 的接口
IViewObjectEx 用来干嘛的??
要创建一个无窗口的控件,OLE容器需要 IOleInPlaceObjectWindowless 接口来分派消息给对象, 因为 对象本身没有自己所属的窗体
另外,IOleInPlaceObject 接口需要重出那个对象
hr = m_lpO->DoVerb(OLEIVERB_SHOW, NULL, (IOleClientSite *)this, 0, NULL, NULL);
IOleObject::DoVerb() 用来显示对象和将对象置为运行的状态
这样,Flash 播放对象就建好了.....
Part 5.
透明窗体的重画
1、创建窗体时加上 WS_EX_LAYERED 属性
2、用 CreateDIBSection() 创建一个 32位的DIB块, 然后把它 Select 到 DC 里面, It will be an offscreen plain to render window contents to. (这句不知如何译....)
3、描绘窗体的内容, preserving the alpha channel. (同上..)
4、调用 UpdateLayeredWindow() 函数重画窗体
描绘 Flash 播放的内容,用 OleDraw() 函数, 在 IViewObject::Draw() 中调用
hr = OleDraw(lpV, DVASPECT_TRANSPARENT, hdcDraw, &rTotal);
lpV – IViewObject interface of flash player control
hdcDraw – offscreen plain
rTotal – client rectangle of the container window
DVASPECT_TRANSPARENT drawing aspect tells the object to draw it's content using alpha blending.
DVASPECT_TRANSPARENT drawing aspect tells the object to draw it's content using alpha blending.
While implementing this, I have met a serious bug in Flash Player Control 8. This bug is only in this version. Players 7 and 9 are free of it. The bug is in the way Flash Control fills the alpha channel of a 32 bit device context. If at least 1 of 255 alpha values is applied to pixel, the colors are mixed correctly, but the resulting alpha channel is set to 255, even if it was initially zero. This makes it impossible to create semitransparent windows. So I had to develop a solution to fix this bug. The solution is quite simple:
These equations are used by Flash Player Control for alpha blending:
R' = Rdst * (1 – alpha) + Rsrc * alpha
G' = Gdst * (1 – alpha) + Gsrc * alpha
B' = Bdst * (1 – alpha) + Bsrc * alpha
If I draw the contents of Flash onto black surface I get
R'black = Rsrc * alpha
G'black = Gsrc * alpha
B'black = Bsrc * alpha
If I draw the contents of Flash onto white surface I get
R'white = 255 * (1 – alpha) + Rsrc * alpha
G'white = 255 * (1 – alpha) + Rsrc * alpha
B'white = 255 * (1 – alpha) + Rsrc * alpha
Here is the system of equations:
R'black = Rsrc * alpha
R'white = 255 * (1 – alpha) + Rsrc * alpha
where alpha and Rsrc are unknown. After solving it you will get:
(255-Alpha) = R'white – R'black
Alpha = 255 – (R'white – R'black) So, the solution is found. Now, we can draw contents of flash player twice and then correct the corrupted alpha channel.
Part 6. Events
Flash Player 对象的事件是用IDispatch来处理的,在创建后得到一个 IConnectionPointContainer 去获取 DIID__IShockwaveFlashEvents 的 连接点(connection point)
hr = m_lpControl->QueryInterface(IID_IConnectionPointContainer,
(void**)&m_lpConCont);
if (FAILED(hr))
return FALSE;
hr = m_lpConCont->FindConnectionPoint(
ShockwaveFlashObjects::DIID__IShockwaveFlashEvents, &m_lpConPoint);
if (FAILED(hr))
return FALSE;
hr = m_lpConPoint->Advise(
(ShockwaveFlashObjects::_IShockwaveFlashEvents*)this,
&m_dwConPointID);
if (FAILED(hr))
return FALSE;
Part 7. DirectDraw
为了提交重画的性能,所以使用 DirectDraw 接口
Flash对象通过 ShockwaveFlashObjects::IServiceProvider::raw_RemoteQueryService 这个接口来访问它
(需要找一下 FlashObject 接口的文档了解一下)
(眼睛睁不开,需要先睡一会………………)