Simple WFA Overlay

post, c#, vb, .NET, overlay, tutorial

Introduction #

Have you ever wondered how to make a form, that always stays in front of a window, while being completely click through and having a transparent background? Two months ago, I wanted to create a form that overlays the popular game Among Us in c#.net. In this short tutorial I want to explain to you how you can exactly the explained behavior in c# and Visual Basic!

Creating a new project #

These first steps are the same for c#.net and vb.net.

Adjusting properties in the Designer #

In the bottom right you will see a section called Properties

The Code #

1) First we need to import a few functions from user32.dll, but to enable DLL import, we first need to import InteropServices

(Visual Basic) Just add this as the first line of your file

Imports System.Runtime.InteropServices

(C#) Add this line after all other “using” statements

using System.Runtime.InteropServices

Then import “GetWindowLong”, “SetWindowLong”, “FindWindow” and “GetWindowRect”

“GetWindowLong” and “SetWindowLong” are needed to get and set the current window style to make it clickthrough.

“FindWindow” is needed to retrieve a handle of the top most window with a specific window name (a window’s title).

“GetWindowRect” is needed to get the Rectangle a window is located in by the handle we retrieve via “FindWindow”.

(Visual Basic) Add this code after “Public Class Form1”:

<DllImport("user32.dll")> Public Shared Function GetWindowLong(ByVal hWnd As IntPtr, ByVal nIndex As Integer) As Integer
End Function

<DllImport("user32.dll")> Public Shared Function SetWindowLong(ByVal hWnd As IntPtr, ByVal nIndex As Integer, ByVal dwNewLong As Integer) As Integer
End Function

<DllImport("user32.dll")> Public Shared Function FindWindow(ByVal lpClassName As IntPtr, ByVal lpWindowName As String) As IntPtr
End Function

<DllImport("user32.dll")> Private Shared Function GetWindowRect(ByVal hWnd As IntPtr, ByRef lpRect As RECT) As Boolean
End Function

(C#) Add this code after “public partial class Form1 : Form”:

[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

[DllImport("user32.dll")]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);

[DllImport("user32.dll")]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

[DllImport("user32.dll")]
static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);

2) To make the form click through we first need to retrieve the extended window styles of our current form with “GetWindowLong”. After that we can modify these values with “SetWindowLong”.

(Visual Basic) Put this code right before the DLLImports from section 1)

Private InitialStyle As Integer

(Visual Basic) Put this code in the automatically created “Form1_Load” sub procedure:

InitialStyle = GetWindowLong(Me.Handle, -20)
SetWindowLong(Me.Handle, -20, InitialStyle Or &H80000 Or &H20)

(C#) Put this code in the {}brackets of the automatically created “Form1_Load” function:

int initialStyle = GetWindowLong(this.Handle, -20);
SetWindowLong(this.Handle, -20, initialStyle | 0x80000 | 0x20);

3) In order to move the window, we use the previously created timer to update the form position according to the position of the targeted window. We first have to define the name of the target window to then get a window handle. Please replace “This PC” with the Name of your target window.

(Visual Basic) We best place this code after our DLLImports from step 1)

Public Const WINDOW_NAME As String = "This PC"
Dim h = FindWindow(Nothing, WINDOW_NAME)

(C#) We best place this code after our DLLImports from step 1)

public const string WINDOW_NAME = "This PC";
IntPtr handle = FindWindow(null, WINDOW_NAME);

4) Then we need to define a rectangle, where we can later put the attributes of our target window, which we will later apply to our own window.

(Visual Basic) Place this code directly after the last code segment

<StructLayout(LayoutKind.Sequential)> Public Structure RECT
    Dim Left, Top, Right, Bottom As Integer
End Structure

Dim r As RECT

(C#) Place this code directly after the last code segment

public struct RECT
{
    public int left, top, right, bottom;
}

RECT rect;

5) For every tick (every 10 ms or so, depending on if you have changed the interval) of the timer we can now get the rectangle of the target window and apply the dimensions to our own window.

(Visual Basic) Put this code in the automatically created “Timer1_Tick” sub procedure:

GetWindowRect(h, r)
Me.Size = New Size(r.Right - r.Left, r.Bottom - r.Top)
Me.Top = r.Top
Me.Left = r.Left

(C#) Put this code in the {}brackets of the automatically created “Timer1_Tick” function:

GetWindowRect(handle, out rect);
this.Size = new Size(rect.right - rect.left, rect.bottom - rect.top);
this.Top = rect.top;
this.Left = rect.left;

Custom Elements #

You have finished the main part of the tutorial (Congrats 🎉). You can now add custom elements to your form to test if your overlay works. Go back to the tab with [Design] in the name and drag a Label from the Toolbox onto the Form and change the “BackColor” to “Control” or something similar and press the “Start” Button at the top of the window, but make sure that you have opened your target window first, else it obviously won’t work :)