用C#写依附于桌面的透明带鼠标穿透窗体的总结。

最近公司需要做一个桌面程序,功能倒是简单,只不过是对特效要求比较特殊,要求窗体依附于桌面(WIN+D等直接显示桌面的时候不消失)、可以设置透明度、没有数据的地方可以实现鼠标穿透。

搞了半天,也没完全实现,用API可以分别实现 鼠标穿透、窗体透明(这个不用API也可以)。但是当这些特效一旦和依附桌面相结合的时候,通通达不到效果,要么窗体不显示,要么实现不了。而且窗体捕获不到显示桌面时候发送的的消息(估计当WIN+D等显示桌面的时候直接把桌面设置为topmost了,而不给窗体发送消息。)估计是我对桌面的hWnd捕获不对。现在先把代码分别贴出来。以后备用。

PS:我测试的系统是windows7,如果是XP 2000 2003下面代码可以正常实现,在VISA和win7下不行。

using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Haedu_Job
{
    public partial class mainfrm : Form
    {
        public mainfrm()
        {
            InitializeComponent();
            this.CanPenetrate();
        }
        #region 创建依附于桌面的窗体 
        [DllImport("user32.dll", EntryPoint = "FindWindow")]
        public static extern int FindWindow(string lpClassName, string lpWindowName);[DllImport("user32.dll", EntryPoint = "GetWindow")] //获取窗体句柄,hwnd为源窗口句柄 /*wCmd指定结果窗口与源窗口的关系,它们建立在下述常数基础上: GW_CHILD寻找源窗口的第一个子窗口 GW_HWNDFIRST为一个源子窗口寻找第一个兄弟(同级)窗口,或寻找第一个顶级窗口 GW_HWNDLAST为一个源子窗口寻找最后一个兄弟(同级)窗口,或寻找最后一个顶级窗口 GW_HWNDNEXT为源窗口寻找下一个兄弟窗口 GW_HWNDPREV为源窗口寻找前一个兄弟窗口 GW_OWNER寻找窗口的所有者 */ 
        public static extern int GetWindow(int hwnd, int wCmd);
        [DllImport("user32.dll", EntryPoint = "SetParent")]
        public static extern int SetParent(int hWndChild, int hWndNewParent); 
        const int GW_HWNDFIRST = 0; //{同级别 Z 序最上} 
        const int GW_HWNDLAST = 1; //{同级别 Z 序最下}
        const int GW_HWNDNEXT = 2;//{同级别 Z 序之下} 
        const int GW_HWNDPREV = 3; //{同级别 Z 序之上} 
        const int GW_OWNER = 4; //{属主窗口} 
        const int GW_CHILD = 5;//{子窗口中的最上} //
        [DllImport("user32.dll", EntryPoint = "GetDesktopWindow")] //
        public static extern int GetDesktopWindow();
        #endregion
        #region 消息处理 //截取消息,进行处理 //
        private const int WM_SIZE = 0x0005; //
        const int SIZE_MAXIMIZED = 2; //
        const int SIZE_MINIMIZED = 1; //
        protected override void WndProc(ref Message m) //
        { // 
            switch (m.Msg) // 
            { // 
                case WM_SIZE: // 
                    if (m.WParam.ToInt32() == SIZE_MAXIMIZED) // 
                    { // // 窗体最大化 // 
                        WindowState = FormWindowState.Normal; //
                    } // 
                    else if (m.WParam.ToInt32() == SIZE_MINIMIZED) // 
                    { // // 窗体最小花 // 
                        Console.WriteLine("Minimized"); // } // 
                        else // 
{ // // 其他 // 
                            base.DefWndProc(ref m); // 
                            Console.WriteLine(m.WParam.ToInt32().ToString()); // 
                        } //
                        break; // 
                        default: // 
                        base.WndProc(ref m); // //
                        Console.WriteLine(m.LParam.ToString()); // 
                        break; // 
                    } //
            }
            #endregion
            #region gridveiw边框样色重绘 
            private void dataGridView1_Paint(object sender, PaintEventArgs e)
            {
                e.Graphics.DrawRectangle(Pens.Peru, new Rectangle(0, 0, this.dataGridView1.Width - 1, this.dataGridView1.Height - 1));
            }
            #endregion
            #region 窗体透明 API方式,备用 签入桌面此API无法工作 
            [DllImport("user32.dll")]
        public extern static IntPtr GetDesktopWindow();
        [DllImport("user32.dll")]
        public extern static bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags);
        public static uint LWA_COLORKEY = 0x1;
        public static uint LWA_ALPHA = 0x2; // 0x00000002; 
        [DllImport("user32.dll")]
        public extern static uint SetWindowLong(IntPtr hwnd, int nIndex, uint dwNewLong);
        [DllImport("user32.dll")]
        public extern static uint GetWindowLong(IntPtr hwnd, int nIndex);
        public enum WindowStyle :int { GWL_EXSTYLE = -20 }
        public enum ExWindowStyle : uint { WS_EX_LAYERED = 0x00080000         }
        private void SetWindowTransparent(byte bAlpha)
        {
            try
            {
                SetWindowLong(this.Handle, (int)WindowStyle.GWL_EXSTYLE, GetWindowLong(this.Handle, (int)WindowStyle.GWL_EXSTYLE) | (uint)ExWindowStyle.WS_EX_LAYERED);
                SetLayeredWindowAttributes(this.Handle, 0x003F85CD, bAlpha, LWA_COLORKEY | LWA_ALPHA);
            } catch { }
        }
        protected override CreateParams CreateParams {
            get { CreateParams cp = base.CreateParams;
                cp.Parent = GetDesktopWindow();
                cp.ExStyle = 0x00000080 | 0x00000008;//WS_EX_TOOLWINDOW | WS_EX_TOPMOST 
                return cp;
            }
        }
        #endregion
        #region 窗体穿透 
        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 = 0x2;
        public void CanPenetrate()
        {
            uint intExTemp = GetWindowLong(this.Handle, GWL_EXSTYLE);
            uint oldGWLEx = SetWindowLong(this.Handle, GWL_EXSTYLE, WS_EX_TRANSPARENT | WS_EX_LAYERED);
            SetLayeredWindowAttributes(this.Handle, 0x003F85CD, 100, LWA_ALPHA | LWA_COLORKEY);
        }
        #endregion
        private void mainfrm_FormClosing(object sender, EventArgs e) { }
        [DllImport("user32.dll")]
        private static extern bool GetWindowText(int hWnd, StringBuilder title, int maxBufSize);
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private extern static int GetWindowTextLength(IntPtr hWnd);
        private void mainfrm_Load(object sender, EventArgs e)
        { //
            MessageBox.Show(GetDesktopWindow().ToString());
            int hDesktop = FindWindow("Progman", null); //
            int length = GetWindowTextLength(new IntPtr(hDesktop)); //
            StringBuilder stringBuilder = new StringBuilder(2 * length + 1); //
            GetWindowText(hDesktop, stringBuilder, stringBuilder.Capacity); //
            string strTitle = stringBuilder.ToString(); //
            MessageBox.Show(strTitle); hDesktop = GetWindow(hDesktop, GW_CHILD); SetParent((int)this.Handle, hDesktop); //
            this.SetWindowTransparent(50);
            dataGridView1.Width = this.Width - 10;
            DataTable dt = new DataTable();
            dt.Columns.Add("任务名称");
            dt.Columns.Add("当前状态");
            dt.Columns.Add("开始日期");
            dt.Columns.Add("添加人员");
            DataRow dr = dt.NewRow();
            dr["任务名称"] = "test";
            dr["当前状态"] = "进行";
            dr["开始日期"] = "test";
            dr["添加人员"] = "test";
            dt.Rows.Add(dr);
            dataGridView1.DataSource = dt;
        }
        #region 移动窗体 
        private Point mouseOffset; //记录鼠标指针的坐标 
        private bool isMouseDown = false; //记录鼠标按键是否按下 
        //创建该窗体 MouseDown、MouseMove、MouseUp事件的相应处理程序 
        private void GB_Title_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            int xOffset;
            int yOffset;
            if (e.Button == MouseButtons.Left) {
                xOffset = -e.X; yOffset = -e.Y;
                mouseOffset = new Point(xOffset, yOffset);
                isMouseDown = true;
            }
        }
        private void GB_Title_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) {
            if (isMouseDown) {
                Point mousePos = Control.MousePosition; mousePos.Offset(mouseOffset.X, mouseOffset.Y);
                Location = mousePos;
            }
        }
        private void GB_Title_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e) {
            // 修改鼠标状态isMouseDown的值 
            // 确保只有鼠标左键按下并移动时,才移动窗体 
            if (e.Button == MouseButtons.Left) { isMouseDown = false; } }
        #endregion
        private void btn_quit_Click(object sender, EventArgs e) { Application.Exit(); } } }

 

 

最终选择的实现方式。设置窗体和要设置透明控件的BackColor,然后设置窗体的TransparencyKey的颜色和刚才设置BackColor相同

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace Haedu_Job {
    public partial class mainfrm : Form
    {
        public mainfrm()
        {
            InitializeComponent();
        }
        #region 创建依附于桌面的窗体 
        [DllImport("user32.dll", EntryPoint = "FindWindow")]
        public static extern int FindWindow( string lpClassName, string lpWindowName );
        [DllImport("user32.dll", EntryPoint = "GetWindow")] //获取窗体句柄,hwnd为源窗口句柄 /*wCmd指定结果窗口与源窗口的关系,它们建立在下述常数基础上: GW_CHILD寻找源窗口的第一个子窗口 GW_HWNDFIRST为一个源子窗口寻找第一个兄弟(同级)窗口,或寻找第一个顶级窗口 GW_HWNDLAST为一个源子窗口寻找最后一个兄弟(同级)窗口,或寻找最后一个顶级窗口 GW_HWNDNEXT为源窗口寻找下一个兄弟窗口 GW_HWNDPREV为源窗口寻找前一个兄弟窗口 GW_OWNER寻找窗口的所有者 */ 
        public static extern int GetWindow( int hwnd, int wCmd ); [DllImport("user32.dll", EntryPoint = "SetParent")]
        public static extern int SetParent( int hWndChild, int hWndNewParent ); //
        const int GW_HWNDFIRST = 0; //{同级别 Z 序最上} //
        const int GW_HWNDLAST = 1; //{同级别 Z 序最下} //
        const int GW_HWNDNEXT = 2; //{同级别 Z 序之下} //
        const int GW_HWNDPREV = 3; //{同级别 Z 序之上} 
        const int GW_OWNER = 4; //{属主窗口} 
        const int GW_CHILD = 5;//{子窗口中的最上} //
        [DllImport("user32.dll", EntryPoint = "GetDesktopWindow")] //
        public static extern int GetDesktopWindow();
        #endregion
        private void mainfrm_FormClosing(object sender, EventArgs e) { }
        private void mainfrm_Load(object sender, EventArgs e) {
            DataTable dt = new DataTable();
            dt.Columns.Add("任务名称");
            dt.Columns.Add("当前状态");
            dt.Columns.Add("开始日期");
            dt.Columns.Add("添加人员");
            DataRow dr = dt.NewRow();
            dr["任务名称"] = "test";
            dr["当前状态"] = "进行";
            dr["开始日期"] = "test";
            dr["添加人员"] = "test";
            dt.Rows.Add(dr);
            dataGridView1.DataSource = dt;
            int hDesktop = FindWindow("Progman", null);
            hDesktop = GetWindow(hDesktop, GW_CHILD);
            SetParent((int)this.Handle, hDesktop);
            this.TopMost = true;
        }
        #region 移动窗体         
        private Point mouseOffset; //记录鼠标指针的坐标 
        private bool isMouseDown = false; //记录鼠标按键是否按下 //创建该窗体 MouseDown、MouseMove、MouseUp事件的相应处理程序 
        private void GB_Title_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) {
            int xOffset;
            int yOffset;
            if (e.Button == MouseButtons.Left) {
                xOffset = -e.X;
                yOffset = -e.Y;
                mouseOffset = new Point(xOffset, yOffset);
                isMouseDown = true;
            }
        }
        private void GB_Title_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) {
            if (isMouseDown) {
                Point mousePos = Control.MousePosition; mousePos.Offset(mouseOffset.X, mouseOffset.Y);
                Location = mousePos;
            }
        }
        private void GB_Title_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e) { // 修改鼠标状态isMouseDown的值 // 确保只有鼠标左键按下并移动时,才移动窗体 
            if (e.Button == MouseButtons.Left) { isMouseDown = false; }
        }
        #endregion
        private void btn_quit_Click(object sender, EventArgs e) {
            Application.Exit();
        }
        private void button1_Click(object sender, EventArgs e) {
            int hDesktop = FindWindow("Progman", null);
            hDesktop = GetWindow(hDesktop, GW_CHILD);
            SetParent((int)this.Handle, hDesktop);
            this.TopMost = true;
        }
    }
}

 

不过唯一不好的地方就是这个依附于桌面,但是要比桌面图标高上一层,所以会遮挡掉桌面图标,我没有找到如何设置窗体为桌面图标的下一层的资料。所以这个问题没法解决,如果您有办法,请留言,非常感谢。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值