Question

I have been working on RAD Studio and on that this is performed automatically if the background is fully transparent, but it seems that it isn't as simple to do in Visual Studio. I have read articles and questions of functions GetWindowLong() and SetWindowLong(), but when I try to use them myself, I get error "the name xxx does not exist in the current context". What I tried was:

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            int initialStyle = GetWindowLong(this.Handle, -20);
            SetWindowLong(this.Handle, -20, initialStyle | 0x80000 | 0x20);
        }
    }
}

So is there some file I have to include in order get it to work, or do I have to place the function elsewhere? I'm also curious to know why does it behave so differently in the RAD Studio and Visula Studio.

Was it helpful?

Solution

The methods you are using are not found in the standard .NET libraries, you need to invoke them through user32.dll.

[DllImport("user32.dll", EntryPoint = "GetWindowLong", CharSet = CharSet.Auto)]
private static extern IntPtr GetWindowLong32(HandleRef hWnd, int nIndex);

[DllImport("user32.dll", EntryPoint = "GetWindowLongPtr", CharSet = CharSet.Auto)]
private static extern IntPtr GetWindowLongPtr64(HandleRef hWnd, int nIndex);

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

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

public static IntPtr GetWindowLong(HandleRef hWnd, int nIndex)
{
    if (IntPtr.Size == 4) return GetWindowLong32(hWnd, nIndex);
    else return GetWindowLongPtr64(hWnd, nIndex);
}

Calling them this way will now work correctly:

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

Make sure you are using System.Runtime.InteropServices

EDIT: I found and modified some code from another question (I will add link if I can find it, I closed the tab and can't find it), and came up with this:

[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo); private const int MOUSEEVENTF_LEFTDOWN = 0x02; private const int MOUSEEVENTF_LEFTUP = 0x04;

    public enum GWL
    {
        ExStyle = -20,
        HINSTANCE = -6,
        ID = -12,
        STYLE = -16,
        USERDATA = -21,
        WNDPROC = -4
    }

    public enum WS_EX
    {
        Transparent = 0x20,
        Layered = 0x80000
    }

    public enum LWA
    {
        ColorKey = 0x1,
        Alpha = 0x2
    }

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

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

    [DllImport("user32.dll", EntryPoint = "SetLayeredWindowAttributes")]
    public static extern bool SetLayeredWindowAttributes(IntPtr hWnd, int crKey, byte alpha, LWA dwFlags);

    private void Form1_Click(object sender, EventArgs e)
    {
        base.OnShown(e);

        int originalStyle = GetWindowLong(this.Handle, GWL.ExStyle);
        int wl = GetWindowLong(this.Handle, GWL.ExStyle);
        wl = wl | 0x80000 | 0x20;

        SetWindowLong(this.Handle, GWL.ExStyle, wl);

        int X = Cursor.Position.X;
        int Y = Cursor.Position.Y;

        mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, X, Y, 0, 0);
        System.Threading.Thread.Sleep(50);

        SetWindowLong(this.Handle, GWL.ExStyle, originalStyle);

        TopMost = true;
    }

I'm not an expert on how to do this, and I'm not sure if I like that solution, but it works.

Make sure you subscribe to the event with: this.Click += Form1_Click;

OTHER TIPS

Assuming Form name as form1

Set these properties to following.

form1.BackColor = Control;
form1.TransparencyKey = Control;

now you can easily click through the transparent area of the form. hope this is what you were looking for.

Shujaat Siddiqui's answer works just fine for clicking through the transparency. It will not hide the form's title though nor its borders.

To do this you may either set the Opacity=0d or chose a FormBorderStyle=none along with a Text="" and ControlBox=false;

You may also think about cutting holes into the window's region to get precise control where click will go through and where not.

In all these cases you will also have to plan for control of the form's position and size..

But, as long as you don't go for semi-tranparency of the background all can be done..

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