0. Version

Ave's DesktopEffects is copyright Andreas Verhoeven 2008. DesktopEffects nor its SDK nor documentation can be distributed WITHOUT explicit permission from the author, Andreas Verhoeven.

Version: 2008, April 12

1. Introduction

What is it?

Ave's DesktopEffects changes the desktop background from a static bitmap into a dynamic rendered background. It does this by taking over the desktops rendering and changing it, possibly with the help of Direct3D.
By allowing Direct3D rendering as the desktops wallpaper, pretty effects can be created without taxing the CPU.

DesktopEffects runs on Vista with or without DWM and on Windows XP

Plugins

Ave's DesktopEffects uses a plugin mechanism to allow new effects being added. Every effect in DesktopEffects, is an COM object that implements a specific COM interface. This COM object then gets hosted inside DesktopEffect and will get called by DesktopEffects to render the desktop.

Getting Started

The quickest way to start a new effect with Visual Studio is to start a new ATL project, pick DLL.
Next, add a new ATL Simple Object through the Class Wizard, give it a name and, on the Options page, check the Custom radio-button.
. Now, let the COM object extend IAveDesktopEffect and add a COM_INTERFACE_ENTRY to the interface map for IAveDesktopEffect.
Then, #include AveDesktopEffects.h and AveDesktopEffectDefines.h.
Now, you are ready to implement the IAveDesktopEffect.h methods. Most of the methods will be stub implementations which can be taken from one of the example files.

Files

2. Architecture

2.1 Host

DesktopEffects uses a straightforward architecture, where there is one Host object that will host Effects. The host will make sure that the environment will be correctly set up and provides everything for rendering onto the desktop.

The host implements the IAveDesktopEffectsHost interface, which provides the following functionality:

(*note with the "desktop" we mean the background + icons of the shell, not the desktop of the windowmanager where all windows live in).

2.2 Effect

An effect will be hosted inside the Host object and is able to make requests, such as start rendering, to the host. The host object, in turn, will perform the operation and when needed, will call back into the effect.

Effects will need to implement the IAveDesktopEffect to be used as an effect inside DesktopEffects. Effects need to provide the following functionality:

Next to that, Effects will also be able to:

3. IAveDesktopEffectsHost

DesktopEffect will host Effects inside an object that implements a IAveDesktopEffectsHost. A pointer to this interface will be given to Effects when they are initialized.

3.1 Methods

An overview of the methods in this interface will be given. All methods adher to the normal COM rules; they return a HRESULT with S_OK on success or an errorcode on error (such as E_FAIL, E_INVALIDARG, E_POINTER). Furthermore, out parameters will be used to return values in, in parameters will be used to read values from.

HRESULT Start(void)

Makes DesktopEffects take over the desktop rendering from the shell so that an Effect can render onto the desktop.

HRESULT Stop(void)

Makes DesktopEffects stop taking over the desktop rendering and let the shell render the desktop again.

HRESULT IsRunning([out] VARIANT_BOOL* isRunning)

Sets *isRunning to VARIANT_TRUE iff DesktopEffects is rendering the desktop, sets *isRunning to VARIANT_FALSE

HRESULT GetTargetWindow([out] HWND* targetWindow)

Sets *targetWindow to the handle of the window where the desktop will be rendered onto.

HRESULT LoadPluginByCLSID([in] BSTR clsid)

Loads an IAveDesktopEffect plugin by its CLSID. The parameter is passed in as a string (BSTR) instead of a CLSID.

HRESULT IsD3DActive([out] VARIANT_BOOL* isActive)

Sets *isActive to VARIANT_TRUE iff is Direct3D rendering of the desktop is activated. If GDI rendering is enabled or the shell is still rendering the desktop, *isActive will be set to VARIANT_FALSE.

HRESULT D3DRenderIconBuffer([in] DWORD mode)

In D3D mode, DesktopEffects takes care of rendering everything other than the desktop background. Thus, The host will need to manage the icons on the desktop. Since some effects might want to peform special effects to the icons on the desktop, it is possible to let the host render the "icon buffer" into the current D3D scene by calling this method.
The following modes are supported thru the mode parameter:
  • AVE_D3D_RENDERICONBUFFER_FULL Renders the icons as it would do normally onto the D3D scene. This includes changing the view-matrixes, textures, lightning and other D3D parameters so that the icons are rendered normally.
  • AVE_D3D_RENDERICONBUFFER_ONLY_DRAW Renders the icons by only outputting a textured quad directly onto the D3D scene. No other parameters than texture0 are changed.
  • AVE_D3D_RENDERICONBUFFER_ONLY_SET_TEXTURE Does not render the icons at all, only sets texture0 to a texture that reflect the icons on the desktop.
  • It must be noted that no direct access to the icon buffer is really given, since DesktopEffects never wants to mess with the users icons: an effect should really be on the background.

HRESULT StartD3DMode(void)

Makes DesktopEffects render the desktop using Direct3D, instead of GDI. This call must be matched with a call to StopD3DMode().
Multiple calls to this function must be matched with the same number of calls to StopD3DMode() to stop rendering the desktop using Direct3D. In other words, calls to this function are counted.

HRESULT StopD3DMode(void)

Makes DesktopEffects stop rendering the desktop using Direct3D and return to GDI rendering. This call must be proceeded by a call to StartD3DMode.

HRESULT D3DRender(void)

When in D3DMode, will make DesktopEffects render the desktop onto a D3D scene, while making callbacks to the current loaded IAveDesktopEffect. Basically, this function makes DesktopEffects do one cycle of the rendering loop directly.

It is to note that the desktop might still be rendered into a D3D scene without calling this function, because of updates to the desktop itself (such as selecting icons). If that is the case, DesktopEffects will act like D3DRender() was called and thus perform a render cycle when it thinks it is necessary.

HRESULT MakeSureIsInitialized(void)

Makes sure DesktopEffect is initialized properly. Normally, this function does not have to be called.

HRESULT GetWallpaperTexture([out] IUnknown** texture)

In D3D rendering mode, this function will return a texture that reflects the user's bitmap wallpaper for use by the IAveDesktopEffect object.
For example, an effect can use this function to get a texture of the user's wallpaper and render it completely morphed inside the D3D scene onto the desktop.

HRESULT GetWallpaperTexture([out] IUnknown** texture)

In D3D rendering mode, this function will return a texture that reflects the user's bitmap wallpaper for use by the IAveDesktopEffect object.
For example, an effect can use this function to get a texture of the user's wallpaper and render it completely morphed inside the D3D scene onto the desktop.

The texture will be passed backed as an IUnknown pointer to the caller; The caller can obtain a reference to the DirectX texture object by QueryInterface()'ing the IUnknown object for IID_IDirect3DTexture9.

The caller is responsibile for calling Release() on the returned IUnknown object.

HRESULT SetWallpaperTexture([in] IUnknown* texture)

In D3D rendering mode, this function will change the wallpaper texture used while rendering the desktop onto a D3D scene to another texture. If the texture gets actually rendered, depends on the preferences and flags of the IAveDesktopEffect object.
This function is, for example, usefull when implementing a wallpaper changer. Instead of implementing the rendering of the wallpaper, the effect can simply call this function with the new wallpapers texture and provide stub implementations for the D3D render functions.

The texture needs to be passed in as an IUnknown pointer to the callee, but the IUknown must be able to be QueryInterface()'ed for IID_IDirect3DTexture9.

The callee is responsibile for calling Release() on the passed IUnknown object.

HRESULT GetHelperWindow([in] IUnknown* effectAsUnknown, [out,retval] HWND* hwnd)

This function will set *hwnd to a handle to a window that can be freely used by the calling effect for timers, thread marshalling and such. This "helper" window is created on demand and only once per effect and serves only as a convenience for effects so that they don't have to setup a helper window themselves.

The effect should pass in its itself as an IUnknown, so that the caller can be uniquely identified. This is necessary because every effect has its own helper window.

When a helper window is created, all messages received by this helper window will be passed to the effect by means of its OnNotificationWindowMessage() callback.

Usually, a call to this method would look like:
HWND helperWindow = NULL;
host->GetHelperWindow(this, &helperWindow);
			

3.2 States

DesktopEffects can be in different states, which can be set and read by the IAveDesktopEffectsHost interface. A brief overview of the states will be given here.

Running states

DesktopEffects can be in the following running states:
  • Not runningthe desktop rendering is done by the shell and no Effect is loaded
  • Running+Stoppedthe desktop rendering is taken over by DesktopEffects and an Effect is loaded
  • Running+Startedthe desktop rendering is done by DesktopEffects and the Effect is notified by having its OnStart() method. The effect normally renders the desktops background in this case.
  • Running+Pausedthe desktop is rendered by the shell, but the effect is loaded

Rendering states

DesktopEffects knows three rendering states:
  • Shell the desktop is rendered by the shell
  • GDI the desktop is rendered by DesktopEffects using GDI
  • Direct3D (D3D) the desktop is rendered by DesktopEffects onto a Direct3D scene

4. IAveDesktopEffect

4.1 Methods

HRESULT GetName([out] BSTR* pName)

Gets called when DesktopEffects wants to know the name of the Effect. The callee should assign a BSTR with the name of the effect to *pName. The caller will free the BSTR.

HRESULT GetAuthor([out] BSTR* pAuthor

Gets called when DesktopEffects wants to know the author of the Effect. The callee should assign a BSTR with the author of the effect to *pAuthor. The caller will free the BSTR.

GetDescription([out] BSTR* pDescription)

Gets called when DesktopEffects wants to know the description of the Effect. The callee should assign a BSTR with the description of the effect to *pDescription. The caller will free the BSTR.

HRESULT GetIcon([out] HBITMAP* pHBitmap)

Gets called when DesktopEffects needs to display an icon for the effect. The callee should allocate a 64x64 ARGB HBITMAP containing the icon for the effect and assign it to *pHBitmap. The caller will free the HBITMAP.

HRESULT GetCooperationFlags([out] DWORD* pFlags)

Not implemented at the moment. Return S_OK.

HRESULT OnInitialize([in] IAveDesktopEffectsHost* host)

Called when an Effect is loaded and will be used inside DesktopEffects.
The Effect should initialize itself and store the pointer to the IAveDesktopEffectsHost object for future use.

Important: The effect should not start rendering as a result of this call nor ask the host to Start(), since it might be possible that an effect is initialized already, but the user does not want DesktopEffect to render.

HRESULT OnUninitialize(void)

Called when an Effect is about to be unloaded. The Effect should release all resources it has and, importantly, Release() the reference it has to the IAveDesktopEffectsHost object it obtained.

Calls to this function will always be matched with a previous call to OnInitialize().

HRESULT OnStart(void)

Called when DesktopEffects took over the desktop rendering. At this point, the effect can start rendering in GDI mode or request to start rendering in D3D mode by calling the host's StartD3DMode() method.

HRESULT OnStop(void)

Called when DesktopEffects stops rendering the desktop or when the effect is unloaded. The effect should stop rendering in GDI mode or request to stop D3D mode rendering by calling the host's StopD3DMode() method.

HRESULT OnPause(void)

Called when rendering is paused and not performed by DesktopEffects.

HRESULT OnResume(void)

Called when rendering is resumed by DesktopEffects after a matching call to OnPause().

HRESULT OnD3DStart([in] IUnknown* directDevice)

Called as a result of DesktopEffect starting up Direct3D rendering mode. At this point, the desktop will be rendered onto a D3D scene.

A pointer to an IDirect3DDevice9 object used for rendering the desktop is passed in thru the directDevice parameter as an IUnknown. The effect should QueryInterface() for IID_IDirect3DDevice9 and store the resulting IDirect3DDevice9 reference for future usage in the rendering cycle.

HRESULT OnD3DStop(void)

Called whenever D3D mode rendering is stopped, either of a result of a call to the host's StopD3dMode() method, or of an external influence.
The Effect should stop all D3D rendering and free all D3D rendering related resources, including the previously obtained reference to the IDirect3DDevice9 object by calling its Release() method.

HRESULT OnBeforeGdiBackgroundUpdate([in] HDC hdc, [in] const RECT* updateRect, [out] DWORD* pWhatToDo)

GDI Render Cycle
Called before the background of the desktop is updated in GDI rendering mode.
  • hdc is a handle to the device context used for drawing and can be used to modify the background or its properties
  • updateRect a pointer to a rectangle describing the part of the desktop that gets updated
  • pWhatToDo set *pWhatToDo to one of the following:

    • AVE_GDI_BACKGROUND_PAINT_DO_NOT_OVERRIDE let the normal background be painted. (default in GDI mode)
    • AVE_GDI_BACKGROUND_PAINT_DO_NOT_CLEAR do not clear the background with solid black
    • AVE_GDI_BACKGROUND_PAINT_DO_CLEAR clear the background with solid black. (default in D3D mode)
    • AVE_GDI_WANTS_TO_RENDER_OVER_DEFAULT_BG paint the normal background, and after that, call the Effects OnAfterGdiBackgroundUpdate()

HRESULT OnAfterGdiBackgroundUpdate([in] HDC hdc, [in] const RECT* updateRect

GDI Render Cycle
Called when the *pWhatToDo parameter of OnBeforeGdiBackgroundUpdate was set to AVE_GDI_WANTS_TO_RENDER_OVER_DEFAULT_BG and the normal background (wallpaper) has been rendered into the hdc. Allows the Effect to paint over the normal background of the desktop.

  • hdc is a handle to the device context used for drawing and can be used to modify the background or its properties
  • updateRect a pointer to a rectangle describing the part of the desktop that gets updated

HRESULT OnBeforeIconBufferUpdate(void)

D3D Render Cycle
Called before the internal icon buffer is updated when in D3D rendering mode. The icon buffer is updated with the contents of the desktop icons whenever there are changes to the desktop icons and the next render cycle is started.

At this point, the icon buffer does not contain an up to date reflection of the desktop icons yet.

It might be possible that multiple updates to the desktop icons will get the icon buffer updated in one batch and result in one render cycle.

HRESULT OnAfterIconBufferUpdate(void)

D3D Render Cycle
Called after the internal icon buffer is updated when in D3D rendering mode. The icon buffer is updated with the contents of the desktop icons whenever there are changes to the desktop icons and the next render cycle is started. This callback might come into use when making use of the D3DRenderIconBuffer() function of the Host.

At this point, the icon buffer does contain an up to date reflection of the desktops icons.

It might be possible that multiple updates to the desktop icons will get the icon buffer updated in one batch and result in one render cycle.

HRESULT OnD3DRender([out] BOOL* pHasRendered))

D3D Render Cycle
Called when a D3D render cycle is started. This is usually initiated by the Effect calling the Host's D3DRender() method or by an external update to the desktop icons.

This callback allows the Effect to take over the render cycle completely (beginning a scene, drawing into the scene, drawing the icon buffer, closing the scene and presenting). If an Effect chooses to do this, it must set *pHasRendered to TRUE so that DesktopEffects knows that the render cycle has been performed already.

Normally, an Effect does nothing in this callback, but some Effects might want to take over the render cycle for performance reasons (for example, video rendering).

HRESULT OnBeforeD3DRender([out] DWORD* pBgColor)

D3D Render Cycle
Called when DesktopEffects' own rendering cycle will be started (thus, when it was not taken over by the effect in the OnD3DRender() callback).

An effect gets the chance to do per-cycle initialization here and, change the background color of the D3D scene by setting the *pBgColor parameter to the preferred ARGB color.

HRESULT OnBeforeD3DSceneStart(void)

D3D Render Cycle
Called when DesktopEffects' own rendering cycle has been started after the device has been cleared, but before the D3D scene is started.

The Effect can modify D3D parameters at this point.

HRESULT OnD3DSceneStart(void)

D3D Render Cycle
Called when DesktopEffects' own rendering cycle has started the D3D scene and did set it up correctly.

By default, the Device is in a 2D render state with a quad VertexBuffer that is the size of the desktop, with direct mapping texture coords.

If the AVE_SUPPORTS_D3D_DRAW_OVER_REAL_WALLPAPER flag was returned by this Effect, the user's wallpaper will be drawn into the D3D scene at this point.

Usually, this is the function where a regular D3D effect does its own rendering of the desktops background

HRESULT OnBeforeIconBufferRender(void)

D3D Render Cycle
Called when DesktopEffects' own rendering cycle has called the Effects OnD3DSceneStart() callback and DesktopEffects is about to render the desktops icons onto the D3D scene.

At this point, the scene has the desktop background rendered, but not yet the icons.

HRESULT OnAfterIconBufferRender(void)

D3D Render Cycle
Called when DesktopEffects' own rendering cycle has called the Effects OnD3DSceneStart() callback and DesktopEffects has rendered the desktop icons into the D3D scene.



At this point, the scene has the desktop background rendered and the desktop icons.

HRESULT OnD3DSceneEnd(void)

D3D Render Cycle
Called when DesktopEffects' own rendering cycle has drawn everything in the D3D scene and will end the scene.

At this point, the scene has completely be rendered.

HRESULT OnBeforeD3DPresent(void)

D3D Render Cycle
Called when DesktopEffects' own rendering cycle is about to present the scene onto the real desktop.

At this point, the scene is completely rendered and ended.

HRESULT OnAfterD3DPresent(void)

D3D Render Cycle
Called when DesktopEffects' own rendering cycle presented the D3D scene onto the real desktop.

At this point, the user sees the just rendered frame on the real desktop.

HRESULT HRESULT OnAfterD3DRender(void)

D3D Render Cycle
Called when DesktopEffects' own rendering cycle has been completed.

At this point, the D3D rendering cycle has been completed.

HRESULT OnTargetWindowMessage([in] HWND hwnd, [in] UINT msg, [in] WPARAM wParam, [in] LPARAM lParam, [out] LRESULT* lResult, [out] BOOL* bHandled)

Called when a Window Message is received by the target window on which the render will be performed.
The Effect get the possibility to, for example, track mouse movements on the desktop by tracing WM_MOUSEMOVE messages and responding accordingly. A good example would be a sparkle that follows the mouse cursor by watching for WM_MOUSEMOVE messages and adding sparks to the D3D scene on the places where the mouse is located.

The parameters are analogue to the WndProc() parameters, with the exception of the bHandled parameter. An effect can set *bHandled to TRUE if it does not want to let the real window nor DesktopEffects handle the message.

HRESULT GetConfigurationWindow([out] HWND* hwnd, [in] HWND parent)

Called when a configuration window for this Effect is needed and the effect returned the AVE_SUPPORTS_CONFIG flag.
The configuration window must be prepared to run inside another window, thus should not have borders and must not be modal. The parent of the configuration window should be set to the parent parameter.
A WM_AVE_EFFECTCONFIG_OK message will be sent to the configuration window, when the user clicks the 'OKAY' button.
It is recommended, however, that changes are instantly applied to the rendering of the effect to give the user a live view of what a setting does.

Set *hwnd to the handle of the created configuration window. The caller takes ownership of the window and will be responsible for destroying it.

HRESULT OnNotification(DWORD dwNotification)

Called when the Host needs to notify the Effect. The dwNotification parameter is set to one of the following:
  • AVE_NOTIFICATION_BEFORE_WALLPAPER_CHANGED The callback is called with this value if the user changed its real wallpaper, but DesktopEffect did not yet update its internal (D3D) wallpaper texture.
  • AVE_NOTIFICATION_AFTER_WALLPAPER_CHANGEDThe callback is called with this value if the user changed its real wallpaper and after DesktopEffect changed its internal (D3D) wallpaper texture.
As an example, the wallpaper notifications could be used by an 'automatic wallpaper fader' effect to keep track of the previous and current wallpaper texture of the user and, using D3D, provide a fading animation between the two wallpapers.

HRESULT DoesSupport([out] DWORD* pFlag)

Called when DesktopEffects needs to know what the Effect supports. The following flags can be set to the *pFlag parameter by the effect to indicate that it supports the feature:
  • AVE_SUPPORTS_CONFIG The effect supports a configuration window which can be obtained through the effects GetConfigurationWindow() method.
  • AVE_SUPPORTS_D3D_DRAW_OVER_REAL_WALLPAPERIn D3D mode, the effect supports drawing over the real wallpaper.
    If this flag is set by the effect, DesktopEffects' own rendering cycle will draw the real wallpaper into the D3D scene before calling any of the other D3D rendering callbacks.
    This allows an effect to simply show an effect between the wallpaper and the icons without rendering any of those itself.

HRESULT OnNotificationWindowMessage([in] HWND hwnd, [in] UINT msg, [in] WPARAM wParam, [in] LPARAM lParam, [out] LRESULT* lResult, [out] BOOL* bHandled)

Called when a Window Message is received by the helper window of the effect.
The effect can create its own helper window by calling its Host GetHelperWindow() method. This helper window then can be used for timers and other messages.
The parameters are analogue to the WndProc() parameters, with the exception of the bHandled parameter. An effect can set *bHandled to TRUE iff it handled the window message.

4.2 GDI Rendering Cycle

XXX TODO

4.3 D3D Rendering Cycle

XXX TODO

4.4 Registration

DesktopEffects plugins are COM objects that implement IAveDesktopEffect, which means that every plugin has its own unique CLSID from the COM system which will be used to identify the plugin.

To be able to list all possible DesktopEffect plugins, they must register themselves under the following registry key:
HKEY_LOCAL_MACHINE
{
    NoRemove SOFTWARE
    {
        NoRemove AveSoftware
        {
            NoRemove AveDesktopEffects
            {
                NoRemove Effects
                {
                    NoRemove YOUREFFECTNAME
                    {
                        val classid = s 'YOURCLSID'
                    }
                }
            }
        }
    }
}
YOUREFFECTNAME must be changed to the name of your effect, for example, 'My Custom Effect'.
YOURCLSID must be changed to the CLSID of your IAveDesktopEffect implementation.