想用C#做一个能够透明+鼠标透过的窗口,遇到一些问题

RooLB 2011-11-09 11:01:48

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;
using System.Reflection;
using System.Diagnostics;

namespace Easy
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public delegate int HookProc(int nCode, int wParam, IntPtr lParam);
static int hHook = 0;
public const int WH_KEYBOARD_LL = 13;
HookProc KeyBoardHookProcedure;


private void Form1_Load(object sender, EventArgs e)
{
this.Opacity = 0.8;
this.TopMost = true;
this.ShowInTaskbar = true;
this.WindowState = FormWindowState.Normal;
SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) | WS_EX_LAYERED);
SetLayeredWindowAttributes(Handle, 0, 128, LWA_ALPHA);
}




[StructLayout(LayoutKind.Sequential)]
public class KeyBoardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
#region DllImport
//设置钩子
[DllImport("user32.dll")]
public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
//抽掉钩子
public static extern bool UnhookWindowsHookEx(int idHook);
[DllImport("user32.dll")]
//调用下一个钩子
public static extern int CallNextHookEx(int idHook, int nCode, int wParam, IntPtr lParam);

[DllImport("kernel32.dll")]
public static extern int GetCurrentThreadId();

[DllImport("kernel32.dll")]
public static extern IntPtr GetModuleHandle(string name);
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
public static extern long GetWindowLong(IntPtr hwnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
public static extern long SetWindowLong(IntPtr hwnd, int nIndex, long dwNewLong);
[DllImport("user32", EntryPoint = "SetLayeredWindowAttributes")]
public static extern int SetLayeredWindowAttributes(IntPtr Handle, int crKey, byte bAlpha, int dwFlags);
const int GWL_EXSTYLE = -20;
const int WS_EX_TRANSPARENT = 0x20;
const int WS_EX_LAYERED = 0x80000;
const int LWA_ALPHA = 2;

#endregion
#region 自定义事件
public void Hook_Start()
{
// 安装键盘钩子
if (hHook == 0)
{
KeyBoardHookProcedure = new HookProc(KeyBoardHookProc);
hHook = SetWindowsHookEx(WH_KEYBOARD_LL,
KeyBoardHookProcedure,
GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0);
if (hHook == 0)
{
Hook_Clear();
//throw new Exception("设置Hook失败!");
}
}
}

//取消钩子事件
public void Hook_Clear()
{
bool retKeyboard = true;
if (hHook != 0)
{
retKeyboard = UnhookWindowsHookEx(hHook);
hHook = 0;
}
//如果去掉钩子失败.
if (!retKeyboard) throw new Exception("UnhookWindowsHookEx failed.");
}

public static int KeyBoardHookProc(int nCode, int wParam, IntPtr lParam)
{
if (nCode >= 0)
{
KeyBoardHookStruct kbh = (KeyBoardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyBoardHookStruct));
if (kbh.vkCode == (int)Keys.Y && (int)Control.ModifierKeys == (int)Keys.Control + (int)Keys.Alt)
{ MessageBox.Show("x");
SetWindowLong(lParam, GWL_EXSTYLE, GetWindowLong(lParam, GWL_EXSTYLE));
}
}

return CallNextHookEx(hHook, nCode, wParam, lParam);
}


private void button1_Click(object sender, EventArgs e)
{
Hook_Start();
SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) | WS_EX_TRANSPARENT | WS_EX_LAYERED);

}

private void button2_Click(object sender, EventArgs e)
{

Hook_Clear();
}

}
}
#endregion



这个程序有两个问题
1,全局钩子用快捷键呼出后,出弹出两次消息框,而且第一次消息框很快弹出,第二个就要等3s左右
2,通过快捷键取消透明+透过无效

麻烦各位大大帮我分析一下,谢谢
...全文
278 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
黄亮 2011-11-09
  • 打赏
  • 举报
回复
鼠标都能透过,那怎么玩呢。
小童 2011-11-09
  • 打赏
  • 举报
回复
关注一下
RooLB 2011-11-09
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 denqh 的回复:]

有这么麻烦么?把窗体this.TransparencyKey设为Transparent
里面随便于放一个控件,如RICHTECTBOX,WEBBRER什么的。而且透过窗口一点问题都没有。
[/Quote]

透明倒是没太大的问题,使之也穿透没问题。但是用快捷键获取窗口焦点的时候(即取消穿透)却失败了,求实现的具体...

我想达到的效果是
1,正常情况下置于顶层;鼠标穿透窗口无法获取窗口焦点;
2,需要操作窗口时通过全局快捷键获取其焦点,可以控制该窗口,此时无法鼠标穿透窗口
3,当不需要的时候通过快捷键使其恢复状态1
DENQH 2011-11-09
  • 打赏
  • 举报
回复
有这么麻烦么?把窗体this.TransparencyKey设为Transparent
里面随便于放一个控件,如RICHTECTBOX,WEBBRER什么的。而且透过窗口一点问题都没有。
wocaononame 2011-11-09
  • 打赏
  • 举报
回复
不懂,帮顶
wangyu20052005 2011-11-09
  • 打赏
  • 举报
回复
最好截个图 说明一下,就能理解你的意思了。
RooLB 2011-11-09
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 lihuoyin1226 的回复:]
1,全局钩子用快捷键呼出后,出弹出两次消息框,而且第一次消息框很快弹出,第二个就要等3s左右

-- 这个主是要因为keyboard有两个事件,key_down 和 key_up,所以你会看到两个消息框弹出
[/Quote]

原来是这样,忽略了这点,谢谢了

现在问题主要在于如何恢复窗口的焦点和无法穿透。

我重新写了代码,这样清晰多了,但仍是出现提示框,无法更改窗口状态,是不是API用得不对,起初怀疑是窗口指针没获取正确,把窗口指针设为全局变量放进去仍失败,求指点

    
public partial class Form1 : Form
{//钩子API
[DllImport("user32.dll")]
public static extern bool RegisterHotKey(IntPtr hWnd, int id, uint control, Keys vk);
[DllImport("user32.dll")]
public static extern bool UnregisterHotKey(IntPtr hWnd, int id);

//窗口API
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
public static extern long GetWindowLong(IntPtr hwnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
public static extern long SetWindowLong(IntPtr hwnd, int nIndex, long dwNewLong);
[DllImport("user32", EntryPoint = "SetLayeredWindowAttributes")]
public static extern int SetLayeredWindowAttributes(IntPtr Handle, int crKey, byte bAlpha, int dwFlags);
const int GWL_EXSTYLE = -20;
const int WS_EX_TRANSPARENT = 0x20;
const int WS_EX_LAYERED = 0x80000;
const int LWA_ALPHA = 2;
IntPtr ip;
public Form1()
{
InitializeComponent();
}


private void Form1_Load(object sender, EventArgs e)
{
ip = this.Handle;
this.Opacity = 0.8;
this.TopMost = true;
this.ShowInTaskbar = true;
this.WindowState = FormWindowState.Normal;
RegisterHotKey(this.Handle, 225, 0, Keys.X);
SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) |WS_EX_TRANSPARENT| WS_EX_LAYERED);
SetLayeredWindowAttributes(Handle, 0, 128, LWA_ALPHA);
}

protected override void WndProc(ref Message m)
{

if (m.WParam.ToString().Equals("225"))
{
SetWindowLong(ip, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE));
MessageBox.Show("X"); }
base.WndProc(ref m);
}
lihuoyin1226 2011-11-09
  • 打赏
  • 举报
回复
if (kbh.vkCode == (int)Keys.Y && (int)Control.ModifierKeys == (int)Keys.Control + (int...

--觉得这行代码应该有点问题,会碰到优先级的问题,最好写成if (kbh.vkCode == (int)Keys.Y && ((int)Control.ModifierKeys == (int)Keys.Control + (int...)),可以试着看一下
lihuoyin1226 2011-11-09
  • 打赏
  • 举报
回复
1,全局钩子用快捷键呼出后,出弹出两次消息框,而且第一次消息框很快弹出,第二个就要等3s左右

-- 这个主是要因为keyboard有两个事件,key_down 和 key_up,所以你会看到两个消息框弹出
wxm3630478 2011-11-09
  • 打赏
  • 举报
回复
全局的快捷键 可以用 注册系统热键 的方式嘛!
RooLB 2011-11-09
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 juliohuang 的回复:]

鼠标都能透过,那怎么玩呢。
[/Quote]

所以需要一个快捷键让窗口还原,否则确实没法操作
dylike 2011-11-09
  • 打赏
  • 举报
回复
我有现成代码,晚上给你。
mjp1234airen4385 2011-11-09
  • 打赏
  • 举报
回复
正常情况下置于顶层;鼠标穿透窗口无法获取窗口焦点;


这个功能实现,建议使用拷贝软件界面直接写到屏幕上,这样就不存在问题。
幸福的小木鱼 2011-11-09
  • 打赏
  • 举报
回复
取消穿透的时候你你把下面一个窗体隐藏试一下,

111,131

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Creator Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧