With Windows 7, Microsoft introduced a new technology called Direct2D (which is also supported on Windows Vista SP2 with the Platform Update installed). Looking through all its documentation, you'll notice it's aimed at Win32 developers; however, the Windows API Code Pack allows .NET developers to use the features of Windows 7 easily, with Direct2D being one of the features supported. Unfortunately, all the WPF examples included with the Code Pack require hosting the control in a
HwndHost, which is a problem as it has airspace issues. This basically means that the Direct2D control needs to be separated from the rest of the WPF controls, which means no overlapping controls with transparency.
The attached code allows Direct2D to be treated as a normal WPF control and, thanks to some COM interfaces, doesn't require you to download the DirectX SDK or even play around with any C++ - the only dependency is the aforementioned Code Pack (the binaries of which are included in the attached file). This article is more about
the problems found along the way the challenges involved in creating the control, so feel free to skip to the Using the code section if you want to jump right in.
WPF is built on top of DirectX 9, and uses a retained rendering system. What this means is that you don't draw anything to the screen, but instead create a tree of visual objects; their drawing instructions are cached and later rendered automatically by the framework. This, coupled with using DirectX to do the graphics processing, enables WPF applications not only to remain responsive when they have to be redrawn, but also allows WPF to use a "painter's algorithm" painting model. In this model, each component (starting at the back of the display, going towards the front) is asked to draw itself, allowing them to paint over the previous component's display. This is the reason it's so easy to have complex and/or partially transparent shapes with WPF - because it was designed taking this scenario into account. For more information, check out the MSDN article.
In contrast to the managed WPF model, Direct2D is immediate-mode where the developer is responsible for everything. This means you are responsible for creating your resources, refreshing the screen, and cleaning up after yourself. It's built on top of Direct3D 10.1, which gives it high-performance rendering, but provides several of the advantages of WPF (such as device independent units, ClearType text rendering, per primitive anti-aliasing, and solid/linear/radial/bitmap brushes). MSDN has a more in-depth introduction; however, it's more aimed at native developers.
Direct2D has been designed to be easily integrated into existing projects that use GDI, GDI+, or Direct3D, with multiple options available for incorporating Direct2D content with Direct3D 10.1 or above. The Direct2D SDK even includes a nice sample called DXGI Interop to show how to do this.
To host Direct3D content inside WPF, the
D3DImage class was introduced in .NET 3.5 SP1. This allows you to host Direct3D 9 content as an
ImageSource, enabling it to be used inside an
Image control, or as an
ImageBrush etc. There's a great article here on CodeProject with more information and examples.
The astute would have noticed that whilst both technologies can work with Direct3D, Direct2D requires version 10.1 or later, whilst the
D3DImage in WPF only supports version 9. A quick internet search resulted in this blog post by Jeremiah Morrill. He explains that an
IDirect3DDevice9Ex (which is supported by
D3DImage) supports sharing resources between devices. A shared render target created in Direct3D 10.1 can therefore be pulled into a
D3DImage via an intermediate
IDirect3DDevice9Ex device. He also includes example source code which does exactly this, and the attached code is derived from his work.
So, we now have a way of getting Direct2D working with Direct3D 10.1, and we can get WPF working with Direct3D 10.1; the only problem is the dependency of both of the examples on unmanaged C++ code and the DirectX SDK. To get around this problem, we'll access DirectX through its COM interface.
Component Object Model
I'll admit I know nothing about COM, apart from to avoid it! However, there's an article here on CodeProject that helped to make it a bit less scary. To use COM, we have to use low level techniques, and I was surprised (and relieved!) to find that the
Marshal class has methods which could mimic anything that would normally have to be done in unmanaged code.
Since there are only a few objects we need from Direct3D 9, and there are only one or two functions in each object that are of interest to us, instead of trying to convert all the interfaces and their functions to their C# equivalent, we'll manually map the V-table as discussed in the linked article. To do this, we'll create a helper function that will extract a method from the specified slot in the V-table:
public static bool GetComMethod<T, U>(T comObj, int slot, out U method) where U : class
IntPtr objectAddress = Marshal.GetComInterfaceForObject(comObj, typeof(T));
if (objectAddress == IntPtr.Zero)
method = null;
IntPtr vTable = Marshal.ReadIntPtr(objectAddress, 0);
IntPtr methodAddress = Marshal.ReadIntPtr(vTable, slot * IntPtr.Size);
method = (U)((object)Marshal.GetDelegateForFunctionPointer(
This code first gets the address of the COM object (using
Marshal.GetComInterfaceForObject), then gets the location of the V-table stored at the start of the COM object (using
Marshal.ReadIntPtr), then gets the address of the method at the specified slot from the V-table (multiplying by the system size of a pointer, as
Marshal.ReadIntPtr specifies the offset in bytes), then finally creates a callable delegate to the returned function pointer (
An important thing to note is that the
IntPtr returned by the call to
Marshal.GetComInterfaceForObject must be released; I wasn't aware of this, and found my program leaking memory when the resources were being re-created. Also, the function uses an
out parameter for the delegate so we get all the nice benefits of type inference and, therefore, reduces the amount of typing required for the caller. Finally, you'll notice there's some nasty casting to
object and then to the
delegate type. This is unfortunate but necessary, as there's no way to specify a delegate generic constraint in C# (the CLI does actually allow this constraint, as mentioned by Jon Skeet in his blog). Since this is an internal class, we'll assume that the caller of the function knows this constraint.
With this helper function, it becomes a lot easier to create a wrapper around the COM interfaces, so let's take a look at how to provide a wrapper around the
IDirect3DTexture9 interface. First, we'll create an internal interface with the
InterfaceType attributes attached so that the
Marshal class knows how to use the object. For
guid, we'll need to look inside the DirectX SDK header files, in particular d3d9.h:
interface DECLSPEC_UUID("85C31227-3DE5-4f00-9B3A-F11AC38C18B5") IDirect3DTexture9;
With the same header open, we can also look for the interface's declaration, which looks like this after running it through the pre-processor and removing the
struct IDirect3DTexture9 : public IDirect3DBaseTexture9
virtual HRESULT QueryInterface( const IID & riid, void** ppvObj) = 0;
virtual ULONG AddRef(void) = 0;
virtual ULONG Release(void) = 0;
virtual HRESULT GetDevice( IDirect3DDevice9** ppDevice) = 0;
virtual HRESULT SetPrivateData( const GUID & refguid,
const void* pData,DWORD SizeOfData,DWORD Flags) = 0;
virtual HRESULT GetPrivateData( const GUID & refguid,
void* pData,DWORD* pSizeOfData) = 0;
virtual HRESULT FreePrivateData( const GUID & refguid) = 0;
virtual DWORD SetPriority( DWORD PriorityNew) = 0;
virtual DWORD GetPriority(void) = 0;
virtual void PreLoad(void) = 0;
virtual D3DRESOURCETYPE GetType(void) = 0;
virtual DWORD SetLOD( DWORD LODNew) = 0;
virtual DWORD GetLOD(void) = 0;
virtual DWORD GetLevelCount(void) = 0;
virtual HRESULT SetAutoGenFilterType( D3DTEXTUREFILTERTYPE FilterType) = 0;
virtual D3DTEXTUREFILTERTYPE GetAutoGenFilterType(void) = 0;
virtual void GenerateMipSubLevels(void) = 0;
virtual HRESULT GetLevelDesc( UINT Level,D3DSURFACE_DESC *pDesc) = 0;
virtual HRESULT GetSurfaceLevel( UINT Level,IDirect3DSurface9** ppSurfaceLevel) = 0;
virtual HRESULT LockRect( UINT Level,D3DLOCKED_RECT* pLockedRect,
const RECT* pRect,DWORD Flags) = 0;
virtual HRESULT UnlockRect( UINT Level) = 0;
virtual HRESULT AddDirtyRect( const RECT* pDirtyRect) = 0;
We only need one of these methods for our code, which is the
GetSurfaceLevel method. Starting from the top and counting down, we can see that this is the 19th method, so will therefore be at slot 18 in the V-table. We can now create a wrapper class around this interface.
internal sealed class Direct3DTexture9 : IDisposable
private delegate int GetSurfaceLevelSignature(IDirect3DTexture9 texture,
uint Level, out IntPtr ppSurfaceLevel);
internal interface IDirect3DTexture9
private IDirect3DTexture9 comObject;
private GetSurfaceLevelSignature getSurfaceLevel;
internal Direct3DTexture9(IDirect3DTexture9 obj)
this.comObject = obj;
public void Dispose()
public IntPtr GetSurfaceLevel(uint Level)
this.comObject, Level, out surface));
private void Release()
if (this.comObject != null)
this.comObject = null;
this.getSurfaceLevel = null;
In the code, I've used
Marshal.ThrowExceptionForHR to make sure that the call succeeds - if there's an error, then it will throw the relevant .NET type (e.g., a result of
E_NOTIMPL will result in a
NotImplementedException being thrown).
To use the attached code, you can either include the compiled binary into your project, or include the code as there's not a lot of it (despite the time spent on creating it!). Either way, you'll need to make sure you reference the Windows API Code Pack DirectX library in your project.
In the code, there are three classes of interest:
D3D10Image class inherits from
D3DImage, and adds an override of the
SetBackBuffer method that accepts a Direct3D 10 texture (in the form of a
Microsoft.WindowsAPICodePack.DirectX.Direct3D10.Texture2D object). As the code is written, the texture must be in the
DXGI_FORMAT_B8G8R8A8_UNORM format; however, feel free to edit the code inside the
GetSharedSurface function to whatever format you want (in fact, the original code by Jeremiah Morrill did allow for different formats, so take a look at that for inspiration).
Direct2DControl is a wrapper around the
D3D10Image control, and provides an easy way to display a
Scene. The control takes care of redrawing the
D3D10Image when it's invalidated, and also resizes their contents. To help improve performance, the control uses a timer to resize the contents 100ms after the resize event has been received. If another request to be resized occurs during this time, the timer is reset to 100ms again. This might sound like it could cause problems when resizing, but internally, the control uses an
Image control, which will stretch its contents when it's resized so the contents will always be visible; they just might get temporarily blurry. Once resizing has finished, the control will redraw its contents at the correct resolution. Sometimes, for reasons unknown to me, there will be a flicker when this happens, but by using the timer, this will occur infrequently.
Scene class is an abstract class containing three main functions for you to override:
OnRender. The reason for the first two functions is that a DirectX device can get destroyed (for example, if you switch users), and afterwards, you will need to create a new device. These methods allow you to create/free device dependent resources, such as brushes for example. The
OnRender method, as the name implies, is where you do the actual drawing.
Putting this together gives us this code to create a simple rectangle on a semi-transparent blue background:
<d2d:Direct2DControl x:Name="d2DControl" />
using D2D = Microsoft.WindowsAPICodePack.DirectX.Direct2D1;
internal sealed class MyScene : Direct2D.Scene
private D2D.SolidColorBrush redBrush;
protected override void OnCreateResources()
this.redBrush = this.RenderTarget.CreateSolidColorBrush(
new D2D.ColorF(1, 0, 0));
protected override void OnFreeResources()
if (this.redBrush != null)
this.redBrush = null;
protected override void OnRender()
var size = this.RenderTarget.Size;
var rect = new D2D.Rect
(int)size.Width - 10,
(int)size.Height - 10
this.RenderTarget.Clear(new D2D.ColorF(0, 0, 1, 0.5f));
public partial class MainWindow : Window
this.d2DControl.Scene = new MyScene();
Updating the Scene
In the original code to update the
Scene, you needed to call
Direct2DControl.InvalidateVisual. This has now been changed so that calling the
Render method on
Scene will cause the new
Updated event to be fired, which the
Direct2DControl subscribes to and invalidates its area accordingly.
Also discovered was that the
Scene would sometimes flicker when redrawn. This seems to be an issue with the
D3DImage control, and the solution (whilst not 100%) is to synchronize the
AddDirtyRect call with when WPF is rendering (by subscribing to the
CompositionTarget.Rendering event). This is all handled by the
Direct2DControl for you.
To make things easier still, there's a new class deriving from
AnimatableScene. After releasing the first version, there was some confusion with how to do continuous scene updates, so hopefully this class should make it easier - you use it the same as the
Scene class, but your
OnRender code will be called, when required, by setting the desired frames per second in the constructor (though see the Limitations section). Also note that if you override the
OnCreateResources method, you need to make sure to call the base's version at the end of your code to start the animation, and when you override the
OnFreeResources method, you need to call the base's version first to stop the animation (see the example in the attached code).
Mixed mode assembly is built against version 'v2.0.50727'
The attached code is compiled against .NET 4.0 (though it could probably be retargeted to work under .NET 2.0), but the Code Pack is compiled against .NET 2.0. When I first referenced the Code Pack and tried running the application, the above exception kept getting raised. The solution, found here, is to include an app.config file in the project with the following
Direct2D will work over remote desktop; however (as far as I can tell), the
D3DImage control is not rendered. Unfortunately, I only have a Home Premium version of Windows 7, so cannot test any workarounds, but would welcome feedback in the comments.
The code written will work with targeting either x86 or x64 platforms (or even using the Any CPU setting); however, you'll need to use the correct version of Microsoft.WindowsAPICodePack.DirectX.dll; I couldn't find a way of making this automatic, and I don't think the Code Pack can be compiled to use Any CPU as it uses unmanaged code.
The timer used in the
AnimatableScene is a
DispatchTimer. MSDN states:
DispatcherTimer is] not guaranteed to execute exactly when the time interval occurs [...]. This is because
DispatcherTimer operations are placed on the Dispatcher queue like other operations. When the
DispatcherTimer operation executes is dependent on the other jobs in the queue and their priorities.
- 02/11/10 -
Direct2DControl has been changed to use a
DispatchTimer so that it doesn't contain any controls needing to be disposed of (makes FxCop a little happier), and the control is now synchronized with WPF's
CompositionTarget.Rendering event to reduce flickering.
Scene has been changed to include an
Updated event and to allow access to its
D2DFactory to derived classes. Also, the
AnimatedScene class has been added.
- 21/09/10 - Initial version.