当前位置:编程学习 > C#/ASP.NET >>

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


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,通过快捷键取消透明+透过无效

麻烦各位大大帮我分析一下,谢谢
--------------------编程问答-------------------- 不懂,帮顶 --------------------编程问答-------------------- --------------------编程问答-------------------- 有这么麻烦么?把窗体this.TransparencyKey设为Transparent
里面随便于放一个控件,如RICHTECTBOX,WEBBRER什么的。而且透过窗口一点问题都没有。 --------------------编程问答--------------------
引用 3 楼 denqh 的回复:
有这么麻烦么?把窗体this.TransparencyKey设为Transparent
里面随便于放一个控件,如RICHTECTBOX,WEBBRER什么的。而且透过窗口一点问题都没有。


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

我想达到的效果是
1,正常情况下置于顶层;鼠标穿透窗口无法获取窗口焦点;
2,需要操作窗口时通过全局快捷键获取其焦点,可以控制该窗口,此时无法鼠标穿透窗口
3,当不需要的时候通过快捷键使其恢复状态1 --------------------编程问答-------------------- 关注一下 --------------------编程问答-------------------- 鼠标都能透过,那怎么玩呢。 --------------------编程问答-------------------- --------------------编程问答-------------------- 取消穿透的时候你你把下面一个窗体隐藏试一下, --------------------编程问答-------------------- 正常情况下置于顶层;鼠标穿透窗口无法获取窗口焦点;


这个功能实现,建议使用拷贝软件界面直接写到屏幕上,这样就不存在问题。 --------------------编程问答-------------------- 我有现成代码,晚上给你。 --------------------编程问答--------------------
引用 6 楼 juliohuang 的回复:
鼠标都能透过,那怎么玩呢。


所以需要一个快捷键让窗口还原,否则确实没法操作 --------------------编程问答-------------------- 全局的快捷键 可以用 注册系统热键 的方式嘛! --------------------编程问答-------------------- 1,全局钩子用快捷键呼出后,出弹出两次消息框,而且第一次消息框很快弹出,第二个就要等3s左右

  -- 这个主是要因为keyboard有两个事件,key_down 和 key_up,所以你会看到两个消息框弹出 --------------------编程问答-------------------- --------------------编程问答-------------------- 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...)),可以试着看一下 --------------------编程问答--------------------
引用 13 楼 lihuoyin1226 的回复:
1,全局钩子用快捷键呼出后,出弹出两次消息框,而且第一次消息框很快弹出,第二个就要等3s左右

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


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

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

我重新写了代码,这样清晰多了,但仍是出现提示框,无法更改窗口状态,是不是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);
        }
--------------------编程问答-------------------- 最好截个图 说明一下,就能理解你的意思了。
补充:.NET技术 ,  C#
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,