您的位置:首页 > 编程语言 > C#

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

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

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

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

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


 

不过唯一不好的地方就是这个依附于桌面,但是要比桌面图标高上一层,所以会遮挡掉桌面图标,我没有找到如何设置窗体为桌面图标的下一层的资料。所以这个问题没法解决,如果您有办法,请留言或者发送邮件到wdw984@126.com。非常感谢。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: