Transparent Flash Control in Plain C++
This article illustrates the implementation of a simple OLE container that is used to host a transparent or windowed Flash Player Object.
Part 1. OLE Interfaces
The simplest OLE control implementation for an ActiveX object should consist of several interfaces:
- IOleClientSite
- IOleInPlaceSiteWindowless
- IOleInPlaceFrame
- IStorage
My implementation of the OLE container is called COleContainerWnd. It is declared as in the following:
template<class TObj> class COleContainerWnd : virtual public IOleClientSite, virtual public IOleInPlaceSiteWindowless, virtual public IOleInPlaceFrame, virtual public IStorage
where TObj is the desired interface of an ActiveX object.
Part 2. Flash Object
Importing the Flash Object into VC++ is done by using the #import command:
#import "c:\\windows\\system32\\macromed\\flash\\flash.ocx" named_guids
The named_guids directive is used to generate a CLSID_ShockwaveFlash class ID.
If you are running under Windows 2000, change the system folder to "winnt".
As a result of the #import command, the compiler will generate the flash.tli and flash.tlh files. They contain your Flash Player interface declarations.
Part 3. CFlashWnd Derivative Class
This class is based on COleContainer and uses ShockwaveFlashObjects:IShockwaveFlash as the template parameter:
class CFlashWnd : public COleContainerWnd<ShockwaveFlashObjects::IShockwaveFlash>, public ShockwaveFlashObjects::_IShockwaveFlashEvents
It also implements the _IShockwaveFlashEvents interface to receive fscommand() events from the Flash movie.
The creation of CFlashWnd object:
g_flashWnd = new CFlashWnd;
g_flashWnd->Create(ShockwaveFlashObjects::CLSID_ShockwaveFlash,
WS_EX_LAYERED, WS_POPUP | WS_VISIBLE |
WS_CLIPSIBLINGS, g_hWnd, g_hInst);
The first parameter is the class ID of the Flash Player Object. The second parameter is the extended window style; it should be set to WS_EX_LAYERED for transparent Flash control and 0 for non-transparent. The third is the window style, followed by the owner window and application instance.
The HWND handle for the OLE container can be retrieved by using the GetHWND() function.
Part 4. Inside CFlashWnd::Create()
First, the window class is registered. Then, the window with your specified styles is created.
The OleCreate function creates an instance of an IOleObject object. It passes COleContainer's IOleClientSite and IStorage to the IOleObject object. Then, the OleSetContainedObject is called to inform the object of its embedded state. TheIShockwaveFlash interface is obtained from IOleObject by using QueryInterface. IViewObjectEx is obtained in the same way.
If a windowless control is created, the container needs the IOleInPlaceObjectWindowless interface to dispatch messages to the object because the object does not have its own window. In another case, the IOleInPlaceObject interface is required to draw the object.
IOleObject::DoVerb() is used to show the object and switch it to its running state.
hr = m_lpO->DoVerb(OLEIVERB_SHOW, NULL, (IOleClientSite *)this,
0, NULL, NULL);
Now, the Flash Player object is fully created.
Part 5. Transparent Window Drawing
It is not quite trivial to draw semitransparent translucent windows. The algorithm is the following:
- Create a WS_POPUP window with WS_EX_LAYERED style.
- Create a 32-bit DIB Section using the CreateDIBSection() function and select it to any compatible DC. It will be an offscreen plain to render window contents to.
- Render window contents, preserving the alpha channel.
- Call the UpdateLayeredWindow() function to draw the window to the screen.
To render Flash player contents, I use the OleDraw helper function. It internally calls the IViewObject::Draw() method:
hr = OleDraw(lpV, DVASPECT_TRANSPARENT, hdcDraw, &rTotal);
- lpV: IViewObject interface of flash player control
- hdcDraw: Offscreen plain
- rTotal: Client rectangle of the container window
The DVASPECT_TRANSPARENT drawing aspect tells the object to draw its content using alpha blending.
When implementing this, I 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 a 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 the 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 a black surface, I get the following:
- R'black = Rsrc * alpha
- G'black = Gsrc * alpha
- B'black = Bsrc * alpha
If I draw the contents of Flash onto a white surface, I get this:
- 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, you can draw the contents of the Flash player twice and then correct the spoiled alpha channel.
Part 6. Events
Flash Control Events are handled by using IDispatch. After the Flash control is created, you retrieve a IConnectionPointContainer and try to find 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;
After a successful Advise(), you will receive events in the IDispatch::Invoke method.

Comments
Access Violation
Posted by YanTayga on 08/24/2012 05:16amThere is error running your example on flash 11 - access violation. This line: hr = m_lpO-DoVerb(OLEIVERB_SHOW, NULL, (IOleClientSite *)this, 0, NULL, NULL); Wrong this pointer is passed to OLECONTAINER(void)::Draw
-
ReplyResolution to Access Violation
Posted by Arvind Lakra on 12/10/2012 03:50amHi , Did u got any valid resolution for the above issue ?
ReplyBroken
Posted by DJ on 05/01/2012 05:27pmThe download link is broken
ReplyGreate job!
Posted by hailongxl on 04/22/2011 09:48pmThanks a lot!
Reply.Net?
Posted by jberenguer on 04/05/2009 09:22pmcould you point me towards a C# version - I really could use transparent control in .net - can you convert this to C# dll? pretty please? Jimmy Berenguer
ReplyI am impressed by your container.
Posted by Wirt on 02/08/2008 05:08pmYou did a great job. You are really senior. How old are you by the way? Wirt From Canada.
Reply#import problem
Posted by Ali Imran on 01/10/2008 04:36am#import not working with mingw compiler (dev c++ ide) any other solution ? #import "c:\\windows\\system32\\macromed\\flash\\flash.ocx" named_guids regards
Replygreat
Posted by elliot115 on 04/13/2007 02:06amgreat
Reply