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
        );

        ///  
        /// 设置窗体具有鼠标穿透效果 
        ///  
        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();
        }
    }
}

你可能感兴趣的:(c#,windows,鼠标穿透)