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.

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: