没画完的画

喂马 劈柴 BBQ~
posts - 37, comments - 55, trackbacks - 0, articles - 0
  C++博客 ::  :: 新随笔 :: 联系 :: 聚合  :: 管理

Transparent Flash Control

Posted on 2008-09-11 22:13 没画完的画 阅读(4278) 评论(4)  编辑 收藏 引用 所属分类: Windows COM

在网页中只需要加入以下代码

<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 *)this0, 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 接口的文档了解一下)


(眼睛睁不开,需要先睡一会………………)






Feedback

# re: Transparent Flash Control   回复  更多评论   

2008-09-12 10:24 by true
很认真的完成了此文,顶一个!

# re: Transparent Flash Control   回复  更多评论   

2008-09-12 15:37 by 贾春雨
有点晕啊! 真地很厉害。

# re: Transparent Flash Control   回复  更多评论   

2009-12-15 15:45 by 杨严
可是 为什么不能直接运行呢。。出了好多调试错误。

# re: Transparent Flash Control   回复  更多评论   

2010-08-29 21:52 by disala
@杨严
看清楚啦~
他们用了什么函数?
有dx函数存在啊,你的vs环境配置了没有?

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理