Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Transparent window layer that is click-through and always stays on top

Tags:

c#

.net

winforms

This is some code that I picked up which I tried to implement. Its purpose is to create a form layer which is transparent, full screen, borderless, clickthrough, and always on top of other windows. It then lets you draw using directx over the top of it remaining otherwise transparent.

The parts that don't work are the click-through part, and the directx render. When I run it I basically have an invisible force field in front of all other windows and have to alt-tab around to visual studio to quickly press ALT F5 and end the debug (so at least the always on top and transparency works). I have been trying to figure out why those parts don't work, but my newbie c# skills fail me. hopefully someone can spot why and provide a modification.

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Diagnostics; using System.Runtime.InteropServices; using System.Globalization; using Microsoft.DirectX; using Microsoft.DirectX.Direct3D; using System.Threading;   namespace MinimapSpy { public partial class Form1 : Form {      private Margins marg;      //this is used to specify the boundaries of the transparent area     internal struct Margins     {         public int Left, Right, Top, Bottom;     }      [DllImport("user32.dll", SetLastError = true)]      private static extern UInt32 GetWindowLong(IntPtr hWnd, int nIndex);      [DllImport("user32.dll")]      static extern int SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);      [DllImport("user32.dll")]      static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags);      public const int GWL_EXSTYLE = -20;      public const int WS_EX_LAYERED = 0x80000;      public const int WS_EX_TRANSPARENT = 0x20;      public const int LWA_ALPHA = 0x2;      public const int LWA_COLORKEY = 0x1;      [DllImport("dwmapi.dll")]     static extern void DwmExtendFrameIntoClientArea(IntPtr hWnd, ref Margins pMargins);      private Device device = null;        public Form1()     {          //Make the window's border completely transparant         SetWindowLong(this.Handle, GWL_EXSTYLE,                 (IntPtr)(GetWindowLong(this.Handle, GWL_EXSTYLE) ^ WS_EX_LAYERED ^ WS_EX_TRANSPARENT));          //Set the Alpha on the Whole Window to 255 (solid)         SetLayeredWindowAttributes(this.Handle, 0, 255, LWA_ALPHA);          //Init DirectX         //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;          this.device = new Device(0, DeviceType.Hardware, this.Handle,         CreateFlags.HardwareVertexProcessing, presentParameters);           Thread dx = new Thread(new ThreadStart(this.dxThread));         dx.IsBackground = true;         dx.Start();           InitializeComponent();      }     protected override void OnPaint(PaintEventArgs e)    {         //Create a margin (the whole form)       marg.Left = 0;      marg.Top = 0;       marg.Right = this.Width;       marg.Bottom = this.Height;          //Expand the Aero Glass Effect Border to the WHOLE form.         // since we have already had the border invisible we now         // have a completely invisible window - apart from the DirectX         // renders NOT in black.      DwmExtendFrameIntoClientArea(this.Handle, ref marg);      }     private void Form1_Load(object sender, EventArgs e)     {      }     private void dxThread()     {         while (true)         {             //Place your update logic here             device.Clear(ClearFlags.Target, Color.FromArgb(0, 0, 0, 0), 1.0f, 0);             device.RenderState.ZBufferEnable = false;             device.RenderState.Lighting = false;             device.RenderState.CullMode = Cull.None;             device.Transform.Projection = Matrix.OrthoOffCenterLH(0, this.Width, this.Height, 0, 0, 1);             device.BeginScene();              //Place your rendering logic here              device.EndScene();             //device.Present();         }          this.device.Dispose();         Application.Exit();     }    } 
like image 407
user1166981 Avatar asked Jun 18 '12 05:06

user1166981


People also ask

How do you make a Windows Form stay on top?

You can bring a Form on top of application by simply setting the Form. topmost form property to true will force the form to the top layer of the screen, while leaving the user able to enter data in the forms below. Topmost forms are always displayed at the highest point in the z-order of the windows on the desktop.

What is the transparent window?

Transparent Heater Windows are used for widely differing purposes from keeping food hot or cold to preventing aircraft windows from frosting over. In essence a Transparent Heater Window is a pane of glass with an application of transparent semiconductor coating that has electric current passed through the coating.


2 Answers

Here's a refined full sample code for making a window topmost - click through - transparent (= alpha blended). The sample makes a rotating color wheel which is rendered with DirectX, or actually with XNA 4.0, because I believe Microsoft has discontinued developing the managed directx and favours XNA today.

using System; using System.Windows.Forms; using System.Runtime.InteropServices; using Microsoft.Xna.Framework.Graphics;  namespace ClickThroughXNA {     public partial class Form1 : Form     {         // Directx graphics device         GraphicsDevice dev = null;                 BasicEffect effect = null;               // Wheel vertexes         VertexPositionColor[] v = new VertexPositionColor[100];          // Wheel rotation         float rot = 0;          public Form1()         {             InitializeComponent();              StartPosition = FormStartPosition.CenterScreen;                Size = new System.Drawing.Size(500, 500);             FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;  // no borders              TopMost = true;        // make the form always on top                                  Visible = true;        // Important! if this isn't set, then the form is not shown at all              // Set the form click-through             int initialStyle = GetWindowLong(this.Handle, -20);             SetWindowLong(this.Handle, -20, initialStyle | 0x80000 | 0x20);              // Create device presentation parameters             PresentationParameters p = new PresentationParameters();             p.IsFullScreen = false;             p.DeviceWindowHandle = this.Handle;             p.BackBufferFormat = SurfaceFormat.Vector4;             p.PresentationInterval = PresentInterval.One;              // Create XNA graphics device             dev = new GraphicsDevice(GraphicsAdapter.DefaultAdapter, GraphicsProfile.Reach, p);              // Init basic effect             effect = new BasicEffect(dev);              // Extend aero glass style on form init             OnResize(null);         }           protected override void OnResize(EventArgs e)         {             int[] margins = new int[] { 0, 0, Width, Height };              // Extend aero glass style to whole form             DwmExtendFrameIntoClientArea(this.Handle, ref margins);           }           protected override void OnPaintBackground(PaintEventArgs e)         {             // do nothing here to stop window normal background painting         }           protected override void OnPaint(PaintEventArgs e)         {                             // Clear device with fully transparent black             dev.Clear(new Microsoft.Xna.Framework.Color(0, 0, 0, 0.0f));              // Rotate wheel a bit             rot+=0.1f;              // Make the wheel vertexes and colors for vertexes             for (int i = 0; i < v.Length; i++)             {                                     if (i % 3 == 1)                     v[i].Position = new Microsoft.Xna.Framework.Vector3((float)Math.Sin((i + rot) * (Math.PI * 2f / (float)v.Length)), (float)Math.Cos((i + rot) * (Math.PI * 2f / (float)v.Length)), 0);                 else if (i % 3 == 2)                     v[i].Position = new Microsoft.Xna.Framework.Vector3((float)Math.Sin((i + 2 + rot) * (Math.PI * 2f / (float)v.Length)), (float)Math.Cos((i + 2 + rot) * (Math.PI * 2f / (float)v.Length)), 0);                  v[i].Color = new Microsoft.Xna.Framework.Color(1 - (i / (float)v.Length), i / (float)v.Length, 0, i / (float)v.Length);             }              // Enable position colored vertex rendering             effect.VertexColorEnabled = true;             foreach (EffectPass pass in effect.CurrentTechnique.Passes) pass.Apply();              // Draw the primitives (the wheel)             dev.DrawUserPrimitives(PrimitiveType.TriangleList, v, 0, v.Length / 3, VertexPositionColor.VertexDeclaration);              // Present the device contents into form             dev.Present();              // Redraw immediatily             Invalidate();                     }           [DllImport("user32.dll", SetLastError = true)]         static extern int GetWindowLong(IntPtr hWnd, int nIndex);          [DllImport("user32.dll")]         static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);          [DllImport("dwmapi.dll")]         static extern void DwmExtendFrameIntoClientArea(IntPtr hWnd, ref int[] pMargins);      } } 
like image 76
Jaska Avatar answered Oct 09 '22 22:10

Jaska


A little extension/modification to Jaska's code, which the form is transparent

public partial class Form1 : Form {     public Form1()     {         InitializeComponent();          this.TopMost = true; // make the form always on top         this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; // hidden border         this.WindowState = FormWindowState.Maximized; // maximized         this.MinimizeBox = this.MaximizeBox = false; // not allowed to be minimized         this.MinimumSize = this.MaximumSize = this.Size; // not allowed to be resized         this.TransparencyKey = this.BackColor = Color.Red; // the color key to transparent, choose a color that you don't use     }      protected override CreateParams CreateParams     {         get         {             CreateParams cp = base.CreateParams;             // Set the form click-through             cp.ExStyle |= 0x80000 /* WS_EX_LAYERED */ | 0x20 /* WS_EX_TRANSPARENT */;             return cp;         }     }      protected override void OnPaint(PaintEventArgs e)     {         base.OnPaint(e);         // draw what you want         e.Graphics.FillEllipse(Brushes.Blue, 30, 30, 100, 100);     } } 
like image 28
Alvin Wong Avatar answered Oct 10 '22 00:10

Alvin Wong