C#鼠标穿透功能(WinForm)
C#鼠标穿透功能(WinForm)
在WinForm开发时,会用到这样一个场景,给屏幕增加水印Logo,但不影响画面的操作。这里就会用到鼠标穿透功能。
User32.Dll函数
要想实现鼠标穿透功能,需要用到User32.Dll的几个函数:SetWindowLong、GetWindowLong、SetLayeredWindowAttributes。
SetWindowLong
语法规则
LONG SetWindowLongA(
[in] HWND hWnd,
[in] int nIndex,
[in] LONG dwNewLong
);
描述:更改指定窗口的属性。 函数还将指定偏移量的 32 位 (长) 值设置为额外的窗口内存。
参数 | 类型 | 描述 |
---|---|---|
[in] hWnd | HWND | 窗口的句柄,以及窗口所属类的间接句柄。 |
[in] nIndex | int | 要设置的值的从零开始的偏移量。 有效值在零到额外窗口内存的字节数之间,减去整数的大小。 若要设置任何其他值,请指定以下值之一。 |
[in]dwNewLong | LONG | 替换值 |
其中nIndex的值含义如下,常用到值为GWL_EXSTYLE=(-20)和GWL_STYLE=(-16)
值 | 含义 |
---|---|
GWL_EXSTYLE-20 | 设置新的 扩展窗口样式 |
GWL_HINSTANCE-6 | 设置新的应用程序实例句柄。 |
GWL_ID-12 | 设置子窗口的新标识符。 该窗口不能是顶级窗口。 |
GWL_STYLE-16 | 设置新 窗口样式 |
GWL_USERDATA-21 | 设置与窗口关联的用户数据。 此数据供创建窗口的应用程序使用。 其值最初为零。 |
GWL_WNDPROC-4 | 为窗口过程设置新地址。如果窗口不属于调用线程所在的进程,则无法更改此属性。 |
返回值:Long
如果函数成功,则返回值是指定 32 位整数的上一个值。
如果函数失败,则返回值为零。 要获得更多的错误信息,请调用 GetLastError。
如果指定的 32 位整数的上一个值为零,并且函数成功,则返回值为零,但函数不会清除最后一个错误信息。 这使得很难确定成功或失败。 若要处理此问题,在调用 SetWindowLong 之前,应通过调用 SetLastError 0 来清除最后一个错误信息。 然后,函数失败将由返回值零和 GetLastError 结果指示为非零。
目前基本不做判断
GetWindowLong
语法规则
LONG GetWindowLongA(
[in] HWND hWnd,
[in] int nIndex
);
描述:
检索有关指定窗口的信息。 该函数还会检索 32 位 (DWORD) 指定偏移量到额外窗口内存的值。
参数 | 类型 | 描述 |
---|---|---|
[in] hWnd | HWND | 窗口的句柄,以及窗口所属类的间接句柄。 |
[in] nIndex | int | 要检索的值的从零开始的偏移量。 有效值的范围是零到额外窗口内存的字节数减去 4;例如,如果指定了 12 个或更多字节的额外内存,则值 8 将是第三个 32 位整数的索引。 若要检索任何其他值,请指定以下值之一。 |
其中nIndex的值含义如下,常用到值为GWL_EXSTYLE=(-20)和GWL_STYLE=(-16)
值 | 含义 |
---|---|
GWL_EXSTYLE-20 | 检索 扩展窗口样式 |
GWL_HINSTANCE-6 | 检索应用程序实例的句柄。 |
GWL_HWNDPARENT-8 | 检索父窗口的句柄(如果有)。 |
GWL_ID-12 | 检索窗口的标识符。 |
GWL_STYLE-16 | 检索 窗口样式 |
GWL_USERDATA-21 | 检索与窗口关联的用户数据。 此数据供创建窗口的应用程序使用。 其值最初为零。 |
GWL_WNDPROC-4 | 检索窗口过程的地址,或表示窗口过程地址的句柄。 必须使用 CallWindowProc函数调用窗口过程。 |
返回值
类型: LONG
如果函数成功,则返回值为请求的值。
如果函数失败,则返回值为零。 要获得更多的错误信息,请调用 GetLastError。
如果以前未调用 SetWindowLong , 则 GetWindowLong 为额外窗口或类内存中的值返回零。
SetLayeredWindowAttributes
语法规则
BOOL SetLayeredWindowAttributes(
[in] HWND hwnd,
[in] COLORREF crKey,
[in] BYTE bAlpha,
[in] DWORD dwFlags
);
描述:设置分层窗口的不透明度和透明度颜色键。
参数 | 类型 | 描述 |
---|---|---|
[in] hWnd | HWND | 分层窗口的句柄。 使用 CreateWindowEx 函数创建窗口时指定WS_EX_LAYERED,或者在创建窗口后通过 SetWindowLong 设置WS_EX_LAYERED来创建分层窗口。 Windows 8: 顶级窗口和子窗口支持 WS_EX_LAYERED 样式。 以前的 Windows 版本仅支持 顶级窗口WS_EX_LAYERED 。 |
[in] crKey | COLORREF | COLORREF 结构,指定要在组合分层窗口时使用的透明度颜色键。 窗口以这种颜色绘制的所有像素都是透明的。 若要生成 COLORREF,请使用 RGB 宏。 |
[in]bAlpha | BYTE | 用于描述分层窗口的不透明度的 Alpha 值。 类似于 BLENDFUNCTION 结构的 SourceConstantAlpha 成员。 当 bAlpha 为 0 时,窗口是完全透明的。 当 bAlpha 为 255 时,窗口是不透明的。 |
[in]dwFlags | DWORD | 要执行的操作。 此参数可使用以下一个或多个值。 |
值 | 含义 |
---|---|
LWA_ALPHA0x00000002 | 使用 bAlpha 确定分层窗口的不透明度。 |
LWA_COLORKEY0x00000001 | 使用 crKey 作为透明度颜色。 |
第二个就是要设置的一个透明色,第三个是要设置的透明度,bAlpha的范围是 0-255,如果是0,那么完全透明,如果是255,是完全不透明。 第四个参数,就是设置是按照透明色来透明,还是按照bAlpha来透明。或者两个都设置。 如果 dwFlags 设置了LWA_COLORKEY,那么crKey就起作用,窗口中所有的crKey颜色区域就会全部透明,如果dwFlags设置了LWA_ALPHA,那么bAlpha就会起作用,整个窗口就会按照bAlpha的值来透明。也可以这两个一起设置来同时实现这两个效果。
功能代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace demo189_窗体移动
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//定义user32.dll参数值
private const uint WS_EX_LAYERED = 0x80000;
private const int WS_EX_TRANSPARENT = 0x20;
private const int GWL_STYLE = (-16);
private const int GWL_EXSTYLE = (-20);
private const int LWA_ALPHA = 0;
//更改指定窗口的属性
[DllImport("user32", EntryPoint = "SetWindowLong")]
private static extern uint SetWindowLong(IntPtr hwnd,int nIndex,uint dwNewLong
);
//检索有关指定窗口的信息
[DllImport("user32", EntryPoint = "GetWindowLong")]
private static extern uint GetWindowLong(IntPtr hwnd,int nIndex
);
//设置分层窗口的不透明度和透明度颜色键
[DllImport("user32", EntryPoint = "SetLayeredWindowAttributes")]
private static extern int SetLayeredWindowAttributes(IntPtr hwnd,int crKey,int bAlpha,int dwFlags
);
/// <summary>
/// 设置窗体具有鼠标穿透效果
/// </summary>
public void SetPenetrate()
{
this.TopMost = true;
//GetWindowLong(this.Handle, GWL_EXSTYLE);
SetWindowLong(this.Handle, GWL_EXSTYLE, WS_EX_TRANSPARENT | WS_EX_LAYERED);
SetLayeredWindowAttributes(m_hWnd,0,(BYTE)220,LWA_ALPHA);
//SetLayeredWindowAttributes(m_hWnd,RGB(255,0,255),(BYTE)220,LWA_ALPHA|LWA_COLORKEY);
//SetLayeredWindowAttributes(m_hWnd,RGB(0,255,0),0,LWA_COLORKEY);
}
private void Form1_Load(object sender, EventArgs e)
{
this.Opacity = 0.7;
SetPenetrate();
}
}
}