Question

I want to draw DirectX content so that it appears to be floating over top of the desktop and any other applications that are running. I also need to be able to make the directx content semi-transparent, so other things show through. Is there a way of doing this?

I am using Managed DX with C#.

Was it helpful?

Solution

I found a solution which works on Vista, starting from the link provided by OregonGhost. This is the basic process, in C# syntax. This code is in a class inheriting from Form. It doesn't seem to work if in a UserControl:

//this will allow you to import the necessary functions from the .dll
using System.Runtime.InteropServices;

//this imports the function used to extend the transparent window border.
[DllImport("dwmapi.dll")]
static extern void DwmExtendFrameIntoClientArea(IntPtr hWnd, ref Margins pMargins);

//this is used to specify the boundaries of the transparent area
internal struct Margins {
    public int Left, Right, Top, Bottom;
}
private Margins marg;

//Do this every time the form is resized. It causes the window to be made transparent.
marg.Left = 0;
marg.Top = 0;
marg.Right = this.Width;
marg.Bottom = this.Height;
DwmExtendFrameIntoClientArea(this.Handle, ref marg);

//This initializes the DirectX device. It needs to be done once.
//The alpha channel in the backbuffer is critical.
PresentParameters presentParameters = new PresentParameters();
presentParameters.Windowed = true;
presentParameters.SwapEffect = SwapEffect.Discard;
presentParameters.BackBufferFormat = Format.A8R8G8B8;

Device device = new Device(0, DeviceType.Hardware, this.Handle,
CreateFlags.HardwareVertexProcessing, presentParameters);

//the OnPaint functions maked the background transparent by drawing black on it.
//For whatever reason this results in transparency.
protected override void OnPaint(PaintEventArgs e) {
    Graphics g = e.Graphics;

    // black brush for Alpha transparency
    SolidBrush blackBrush = new SolidBrush(Color.Black);
    g.FillRectangle(blackBrush, 0, 0, Width, Height);
    blackBrush.Dispose();

    //call your DirectX rendering function here
}

//this is the dx rendering function. The Argb clearing function is important,
//as it makes the directx background transparent.
protected void dxrendering() {
    device.Clear(ClearFlags.Target, Color.FromArgb(0, 0, 0, 0), 1.0f, 0);

    device.BeginScene();
    //draw stuff here.
    device.EndScene();
    device.Present();
}

Lastly, a Form with default setting will have a glassy looking partially transparent background. Set the FormBorderStyle to "none" and it will be 100% transparent with only your content floating above everything.

OTHER TIPS

You can either use DirectComposition, LayeredWindows, DesktopWindowManager or WPF. All methods come with their advantages and disadvantages:

-DirectComposition is the most efficient one, but needs Windows 8 and is limited to 60Hz.

-LayeredWindows are tricky to get working with D3D via Direct2D-interop using DXGI.

-WPF is relatively easy to use via D3DImage, but is also limited to 60Hz and DX9 and no MSAA. Interop to higher DX-Versions via DXGI are possible, also MSAA can be used when the MSAA-Rendertarget is resolved to the native nonMSAA surface.

-DesktopWindowManager is great for high performance available since Windows Vista, but DirectX-Versions seem to be limited by the Version the DWM uses (still DX9 on Vista). Workarounds for higher DX-Versions should be possible via DXGI where available.

If you don't need per pixel aplha, you can also use the opacity-value of a semi-transparent form.

Or you use the native Win32 method for the Window global alpha (Remember a alpha of 0 will not catch the mouse input):

SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
COLORREF color = 0;
BYTE alpha = 128;
SetLayeredWindowAttributes(hWnd, color, alpha, LWA_ALPHA);

I have been able to use all of the described techniques with C# and SharpDX, but in case of DirectComposition, LayeredWindows and native Win32 a little C++-Wrappercode was needed. For starters I would suggest to go via WPF.

I guess that will be hard without using the Desktop Window Manager, i.e. if you want to support Windows XP. With the DWM, it seems to be rather easy though.

If speed is not an issue, you may get away with rendering to a surface and then copying the rendered image to a layered window. Don't expect that to be fast though.

WPF is also another option.

Developed by Microsoft, the Windows Presentation Foundation (or WPF) is a computer-software graphical subsystem for rendering user interfaces in Windows-based applications.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top